iOS逆向:在任意app上開啟malloc stack追蹤內存來源

lldb有一個內存調試工具malloc stack,開啟以后就可以查看某個內存地址的malloc和free記錄,追蹤對象是在哪里創建的。

這個工具可以打印出對象創建的堆棧,而在逆向時,也經常需要追蹤某些方法的調用棧,如果可以隨時打印出某個對象的創建記錄,也就能直接找到其所在的類和方法,不用再花費大量的時間去打log和動態調試追蹤了。

malloc stack

在自己的項目中,要開啟malloc stack,需要在Product->Scheme->Edit Scheme->Diagnistic里勾選Malloc Stack選項。

效果如下。

測試代碼:

- (IBAction)create:(id)sender {NSString *testString = [NSString stringWithFormat:@"string created by %@",self];}
復制代碼

斷點后在lldb中使用lldb.macosx.heap里的malloc_info命令,雖然官網上說是Mac app才能用的命令,但是經測試現在在iOS上也能用了:

(lldb) p/x testString
(__NSCFString *) $3 = 0x16eac000 @"string created by <ViewController: 0x16e9d7c0>"
(lldb) command script import lldb.macosx.heap //加載lldb.macosx.heap
"malloc_info", "ptr_refs", "cstr_refs", "find_variable", and "objc_refs" commands have been installed, use the "--help" options on these commands for detailed help.
(lldb) malloc_info -s 0x16eac000
0x0000000016eac000: malloc(    64) -> 0x16eac000 __NSCFString.NSMutableString.NSString.NSObject.isa
stack[0]: addr = 0x16eac000, type=malloc, frames:[0] 0x00000000242948ab libsystem_malloc.dylib`malloc_zone_malloc + 123[1] 0x00000000244e3bc1 CoreFoundation`_CFRuntimeCreateInstance + 237[2] 0x00000000245a6ffd CoreFoundation`__CFStringCreateImmutableFunnel3 + 1657[3] 0x00000000244ee0f7 CoreFoundation`CFStringCreateCopy + 359[4] 0x00000000245a725d CoreFoundation`_CFStringCreateWithFormatAndArgumentsAux2 + 89[5] 0x0000000024d17dd3 Foundation`-[NSPlaceholderString initWithFormat:locale:arguments:] + 139[6] 0x0000000024d17cd1 Foundation`+[NSString stringWithFormat:] + 61[7] 0x00000000000d7343 testMallocStack`-[ViewController create:] + 97 at ViewController.m:23:28[8] 0x00000000287a5771 UIKit`-[UIApplication sendAction:to:from:forEvent:] + 81[9] 0x00000000287a5701 UIKit`-[UIControl sendAction:to:forEvent:] + 65[10] 0x000000002878d61f UIKit`-[UIControl _sendActionsForEvents:withEvent:] + 447[11] 0x00000000287a5051 UIKit`-[UIControl touchesEnded:withEvent:] + 617[12] 0x00000000287a4cbf UIKit`-[UIWindow _sendTouchesForEvent:] + 647[13] 0x000000002879d5d7 UIKit`-[UIWindow sendEvent:] + 643[14] 0x000000002876e119 UIKit`-[UIApplication sendEvent:] + 205[15] 0x000000002876c757 UIKit`_UIApplicationHandleEventQueue + 5135[16] 0x0000000024599257 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15[17] 0x0000000024598e47 CoreFoundation`__CFRunLoopDoSources0 + 455[18] 0x00000000245971af CoreFoundation`__CFRunLoopRun + 807[19] 0x00000000244e9bb9 CoreFoundation`CFRunLoopRunSpecific + 517[20] 0x00000000244e99ad CoreFoundation`CFRunLoopRunInMode + 109[21] 0x0000000025763af9 GraphicsServices`GSEventRunModal + 161[22] 0x00000000287d5fb5 UIKit`UIApplicationMain + 145[23] 0x00000000000d7587 testMallocStack`main + 107 at main.m:14:9[24] 0x000000002419c873 libdyld.dylib`start + 3[25] 0x000000003a9c0001 libsystem_pthread.dylib`_thread + 1
復制代碼

這個工具是繼承自gdb的malloc_history,不過malloc_history只能用在模擬器上,而malloc_info在模擬器和真機上都可以使用。另外,新版Xcode又增加了一個新的lldb工具memory history,在Product->Scheme->Edit Scheme->Diagnistic里勾選Address Sanitizer即可,效果類似。

使用非官方版的heap.py

注意,在Xcode8.3以后使用malloc_info會導致lldb調試器crash,似乎是出bug了,一直沒修復。在Xcode8.2上可以正常使用。

所以我們需要替換一下lldb自帶的lldb.macosx.heap模塊。使用這個非官方的版本:heap.py。

lldb可以加載自定義的pthon腳本。只需要在lldb中輸入:

command script import python腳本的地址
復制代碼

因此把上面的heap.py下載到本地后,輸入:

command script import /你的路徑/lldb/examples/darwin/heap_find/heap.py
復制代碼

即可。

在任意app上開啟malloc stack

Address Sanitizermemory history需要重新編譯app,但是malloc stack只需要在app啟動前設置環境變量MallocStackLoggingMallocStackLoggingNoCompact即可。開啟后會在系統的/tmp目錄下生成一個.index文件,這個文件里的內容是依賴于app的運行時環境的,進程退出以后這個文件也就沒用處了。

那么,現在的問題就變成了如何給app設置啟動環境變量。

方法一:execve

這是我一開始使用的方法。使用execve函數來運行app的二進制文件。

由于沙盒的限制,需要讓app擁有root權限才能使用execve。步驟如下。

1.重簽名ipa

重簽名需要逆向的app。因為需要對app內容作出修改。重簽名后安裝到越獄設備上。

2.移動app到系統app目錄下,修改權限

只有系統目錄下的app才有root權限。

假設需要逆向的app是YOUR_APP.app。把app移動到系統app目錄下:mv -f /var/containers/Bundle/Application/xxxxxxxxxxxxx/YOUR_APP.app /Applications/YOUR_APP.app

然后修改文件權限:

cd /Applications

chown -R root:wheel YOUR_APP.app

chmod 4755 YOUR_APP.app/YOUR_APP

移動后,用uicache刷新app圖標,用killall SpringBoard重啟SpringBoard

3.使用引導程序啟動app

最終的目的就是使用引導程序用execve啟動app,在啟動前設置環境變量。

首先重命名原來的二進制文件:mv YOUR_APP.app/YOUR_APP YOUR_APP.app/YOUR_APP_Orig

然后制作引導程序,隨便創建一個iOS工程,替換main.m里的內容為:

int main(int argc, char * argv[]) {@autoreleasepool {NSString* string = [[NSBundle mainBundle] pathForResource:@"YOUR_APP_Orig" ofType:nil];//YOUR_APP_Orig是所要啟動的二進制文件名argv[0] = (char*)[string UTF8String];char *envp[] ={"HOME=/var/root","LOGNAME=root","PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/bin/X11:/usr/games","USER=root","MallocStackLogging=1","MallocStackLoggingNoCompact=1"0};execve([string UTF8String], argv, envp);return 0;}
}
復制代碼

編譯后,取出二進制文件,重命名為YOUR_APP,復制到越獄設備的/Application/YOUR_APP.app/目錄下。

給引導程序設置執行權限:chmod +x /Application/YOUR_APP.app/YOUR_APP

最后重啟SpringBoard:killall SpringBoard

這樣,每次啟動app就都會使用引導程序間接啟動app。

缺點

  • 步驟繁瑣。
  • 有些app重簽名很麻煩。
  • 越獄后的系統分區容量很小,很容易就被占滿了,想要測試大一點的app就麻煩了。
  • 無法使用debugserver喚醒app,調試啟動過程。因為YOUR_APPYOUR_APP_Orig是兩個進程,第一個在execve執行完就退出了。
  • 把app放到系統目錄下有時候會引起crash。

方法2:debugserver參數

方法1實在是太麻煩了,有時候遇上重簽名失敗的app就更麻煩了。但其實還有另一個更直接的方法。就是使用debugserver的命令。

debugserver是動態調試工具,參考:IOS平臺lldb動態調試介紹。

安裝好后,在越獄設備上輸入debugserver *:1234 /var/containers/Bundle/Application/589822B6-BFDA-4A3D-A71C-AD0D30BA6077/WeChat.app/WeChat就能喚醒app進行調試。

但是網上的教程都沒有提到,其實debugserver還有一個隱藏的參數--env(-env,-e都可以),就是用來設置進程的環境變量的:

debugserver *:1234 /var/containers/Bundle/Application/589822B6-BFDA-4A3D-A71C-AD0D30BA6077/WeChat.app/WeChat -env MallocStackLogging=1 -env MallocStackLoggingNoCompact=1

當時我想debugserver會不會有設置環境變量的功能,沒想到隨便試了個-env就成功了。后來在debugserver的源碼里也發現了它的存在:debugserver.cpp(搜索g_long_options可以找到env)。

這樣,即使app沒有重簽名,也可以直接調試了。

缺點

debugserver無法啟動調試extension app,因為extension app是依賴于宿主app而存在的,不能單獨運行。這種情況就只能使用方法1了。

測試

這里使用一個重簽名,并且恢復了符號表的微信進行測試。

比如找到微信查看表情的界面,打印出內存地址為0x108795c20

<MMEmoticonView: 0x108795c20; frame = (276.25 404.25; 215.5 215.5); autoresize = LM+RM+TM+BM; layer = <CALayer: 0x170828700>>
復制代碼

第一次使用malloc_info需要在lldb里導入lldb.macosx.heap,這里需要導入非官方版本的heap.py

(lldb) command script import heap.py的路徑
"malloc_info", "ptr_refs", "cstr_refs", "find_variable", and "objc_refs" commands have been installed, use the "--help" options on these commands for detailed help.
復制代碼

使用malloc_info打印創建堆棧:

(lldb) malloc_info -s 0x108795c20
0x0000000108795c20: malloc(   480) -> 0x108795c20 MMEmoticonView.UIView.UIResponder.NSObject.isa
stack[0]: addr = 0x108795c20, type=malloc, frames:[0] 0x000000018374e0ac libsystem_malloc.dylib`calloc + 40[1] 0x000000018318b624 libobjc.A.dylib`class_createInstance + 76[2] 0x0000000183199ae4 libobjc.A.dylib`_objc_rootAlloc + 52[3] 0x00000001026d8fd4 WeChat`-[MMImageBrowseView InitEmoticonView:] + 432[4] 0x000000010245e950 WeChat`-[MMEmotionMsgBrowseViewController initImageViewWithFrame:] + 404[5] 0x000000010245ea74 WeChat`-[MMEmotionMsgBrowseViewController setupImageView] + 156[6] 0x000000010245e024 WeChat`-[MMEmotionMsgBrowseViewController initView] + 224[7] 0x000000010245d76c WeChat`-[MMEmotionMsgBrowseViewController viewDidLoad] + 112[8] 0x000000018a5f7924 UIKit`-[UIViewController loadViewIfRequired] + 1056[9] 0x000000018a60f4b4 UIKit`-[UIViewController __viewWillAppear:] + 132[10] 0x00000001026e05f8 WeChat`-[MMUIViewController beginAppearanceTransition:animated:] + 92[11] 0x000000018a7975b4 UIKit`-[UINavigationController _startCustomTransition:] + 1136[12] 0x000000018a6afe74 UIKit`-[UINavigationController _startDeferredTransitionIfNeeded:] + 676[13] 0x000000018a6afadc UIKit`-[UINavigationController __viewWillLayoutSubviews] + 64[14] 0x000000018a6afa40 UIKit`-[UILayoutContainerView layoutSubviews] + 188[15] 0x000000018a5f4a80 UIKit`-[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1196[16] 0x0000000187aa29d8 QuartzCore`-[CALayer layoutSublayers] + 148[17] 0x0000000187a974cc QuartzCore`CA::Layer::layout_if_needed(CA::Transaction*) + 292[18] 0x0000000187a9738c QuartzCore`CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 32[19] 0x0000000187a143e0 QuartzCore`CA::Context::commit_transaction(CA::Transaction*) + 252[20] 0x0000000187a3ba68 QuartzCore`CA::Transaction::commit() + 512[21] 0x0000000187a3c488 QuartzCore`CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) + 120[22] 0x00000001846f60c0 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 32[23] 0x00000001846f3cf0 CoreFoundation`__CFRunLoopDoObservers + 372[24] 0x00000001846f4180 CoreFoundation`__CFRunLoopRun + 1024[25] 0x00000001846222b8 CoreFoundation`CFRunLoopRunSpecific + 444[26] 0x00000001860d6198 GraphicsServices`GSEventRunModal + 180[27] 0x000000018a6627fc UIKit`-[UIApplication _run] + 684[28] 0x000000018a65d534 UIKit`UIApplicationMain + 208[29] 0x00000001000ebea4 WeChat`-[WATemplateMsgMngSwitchCell .cxx_destruct] + 372[30] 0x00000001836055b8 libdyld.dylib`start + 4
復制代碼

這樣就直接找到表情界面所在的類,以及在哪里初始化了。

這樣的話,只要能找到一個對象,就能快速定位到其所在模塊。比原來打log,打斷點一步步回溯高效多了。

恢復符號表

建議在對app重簽名時恢復符號表。恢復符號表后,就能直接在堆棧中看到方法名,免去了計算偏移量然后在hopper里查找的麻煩。

參考:iOS符號表恢復&逆向支付寶, restore-symbol。

其他幾個調試命令

ptr_refs

可以在內存中找出哪些地址引用了某個指針,也就相當于查看某個變量在哪里被引用。

cstr_refs

在內存中尋找某個C String在哪里被引用。

find_variable

在當前棧幀上尋找某個局部變量在哪里被引用。

objc_refs

在內存中尋找某個類的實例。

轉到Xcode中調試

如果想要在Xcode中調試并開啟malloc stack,則需要先用debugserver啟動app,在終端的lldb里連接上以后,再用process detach斷開連接。接下來用Xcode的Attach to Process就可以了,參考:iOS逆向:用Xcode直接調試第三方app。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/278239.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/278239.shtml
英文地址,請注明出處:http://en.pswp.cn/news/278239.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【CH4302】Interval GCD

思路&#xff1a;線段樹維護a的差分數組的gcd&#xff0c; 因為$gcd(a_1,a_2,a_3,...,a_n)gcd(a_1,a_2-a_1,a_3-a_2,...,a_n-a_{n-1})$。 原區間修改可以轉化為差分數組上的兩次單點修改。 因為實際計算時還需要原數&#xff0c;所以用樹狀數組維護b的增減量。 詢問時&#xff…

Vue 的路由實現 Hash模式 和 History模式

Hash 模式: Hash 模式的工作原理是onhashchange事件&#xff0c;Window對象可以監聽這個事件... 可以通過改變路徑的哈希值&#xff0c;來實現歷史記錄的保存&#xff0c;發生變化的hash 都會被瀏覽器給保存下來&#xff0c;所以下次盡管瀏覽器沒有請求服務器&#xff0c;但是還…

我的第一次——網站備案

暫無內容 轉載于:https://my.oschina.net/vright/blog/1784979

使用LiveClick升級您的實時書簽

If you like to subscribe to feeds using Firefox’s Live Bookmarks feature, the LiveClick extension gives you so many upgrades that I can only cover the highlights of how great it is. 如果您想使用Firefox的“實時書簽”功能訂閱供稿&#xff0c;則LiveClick擴展程…

操作系統的概論梳理

轉載于:https://www.cnblogs.com/hclhechunlu/p/10477470.html

win7下如何顯示緬文和使用緬文輸入法?

windows 7 操作系統默認不支持緬文&#xff0c;所以緬文在win7上不能顯示&#xff0c;當然也沒有提供緬文輸入法。 一、顯示緬文 windows系統下顯示緬文字母只需要安裝緬文字體就可以了。目前常見的緬文字體就是Zawgyi-One&#xff0c;Zawgyi-One是一種廣泛使用的緬文字體。Zaw…

airpods2使用_如何使用AirPods和AirPods Pro:完整指南

airpods2使用Burdun Iliya/ShutterstockBurdun Iliya /快門Just bought yourself or received a new pair of AirPods or AirPods Pro? Welcome to the truly wireless earphones life. Setting up AirPods is quite straightforward, but here’s how to customize and get t…

LANG

修改 /etc/sysconfig/i18n 文件 locale 查看字符集 轉載于:https://www.cnblogs.com/todayORtomorrow/p/10479594.html

如何在iPhone上共享視頻之前從視頻中刪除音頻

Sometimes, you’d like to share a video with others, but the accompanying audio track is distracting or perhaps introduces privacy concerns. Luckily, there’s a quick way to silence a video using Photos on iPhone and iPad. Here’s how. 有時&#xff0c;您想…

入門第十一課 Python語句的嵌套

1、說個小故事&#xff1a;話說一個人買到一個治療瘙癢的偏方&#xff0c;在拆開無數層的包裝后&#xff0c;得到的只是一張寫著“撓撓”的小紙條兒。 嵌套&#xff0c;類似于在一個語句中&#xff0c;嵌套另一個語句。舉個栗子-_-!! 我們要計算從1到100之間&#xff0c;所有的…

【TensorFlow篇】--Tensorflow框架實現SoftMax模型識別手寫數字集

一、前述 本文講述用Tensorflow框架實現SoftMax模型識別手寫數字集&#xff0c;來實現多分類。 同時對模型的保存和恢復做下示例。 二、具體原理 代碼一&#xff1a;實現代碼 #!/usr/bin/python # -*- coding: UTF-8 -*- # 文件名: 12_Softmax_regression.pyfrom tensorflow.ex…

web頁面鎖屏初級嘗試

因為工作需要&#xff0c;所以在網上找了一些素材來弄這個功能。在我找到的素材中&#xff0c;大多都是不完善的。雖然我的也不是很完善&#xff0c;但是怎么說呢。要求不是很高的話。可以直接拿來用的【需要引用jQuery】。廢話不多說直接上代碼 這部分是js代碼 1 <script&g…

Java 并發工具箱之concurrent包

概述 java.util.concurrent 包是專為 Java并發編程而設計的包。包下的所有類可以分為如下幾大類&#xff1a; locks部分&#xff1a;顯式鎖(互斥鎖和速寫鎖)相關&#xff1b;atomic部分&#xff1a;原子變量類相關&#xff0c;是構建非阻塞算法的基礎&#xff1b;executor部分&…

如何提高gps精度_如何在鍛煉應用程序中提高GPS跟蹤精度

如何提高gps精度l i g h t p o e t/Shutterstocklightpoet /快門Tracking your runs, bike rides, and other workouts is fun because you can see how much you’re improving (or, in my case, dismally failing to improve). For it to be effective, though, you have to …

centos proftp_在CentOS上禁用ProFTP

centos proftpI realize this is probably only relevant to about 3 of the readers, but I’m posting this so I don’t forget how to do it myself! In my efforts to ban the completely insecure FTP protocol from my life entirely, I’ve decided to disable the FTP…

Java通過Executors提供四種線程池

http://cuisuqiang.iteye.com/blog/2019372 Java通過Executors提供四種線程池&#xff0c;分別為&#xff1a;newCachedThreadPool創建一個可緩存線程池&#xff0c;如果線程池長度超過處理需要&#xff0c;可靈活回收空閑線程&#xff0c;若無可回收&#xff0c;則新建線程。n…

一個在線編寫前端代碼的好玩的工具

https://codesandbox.io/ 可以編寫 Angular&#xff0c;React&#xff0c;Vue 等前端代碼。 可以實時編輯和 preview。 live 功能&#xff0c;可以多人協作編輯&#xff0c;不過是收費的功能。 可以增加依賴的包&#xff0c;比如編寫 React 時&#xff0c;可以安裝任意的第三…

MySQL數據庫基礎(五)——SQL查詢

MySQL數據庫基礎&#xff08;五&#xff09;——SQL查詢 一、單表查詢 1、查詢所有字段 在SELECT語句中使用星號“”通配符查詢所有字段在SELECT語句中指定所有字段select from TStudent; 2、查詢指定字段 查詢多個字段select Sname,sex,email from TStudent; 3、查詢指定記錄…

使用生成器創建新的迭代模式

一個函數中需要有一個 yield 語句即可將其轉換為一個生成器。 def frange(start, stop, increment):x startwhile x < stop:yield xx incrementfor i in frange(0, 4, 2):print(i) # 0 2 一個生成器函數主要特征是它只會回應在迭代中使用到的 next 操作 def cutdata(n):p…

前端異常捕獲與上報

在一般情況下我們代碼報錯啥的都會覺得 下圖 然后現在來說下經常用的異常 1.try catch 這個是比較常見的異常捕獲方式通常都是 使用try catch能夠很好的捕獲異常并對應進行相應處理&#xff0c;不至于讓頁面掛掉&#xff0c;但是其存在一些弊端&#xff0c;比如需要在捕獲異常的…