2019年iOS逆向最新學(xué)習(xí)資料(三):強(qiáng)大的斷點(diǎn)調(diào)試工具

1、強(qiáng)大的lldb

上文我們說到了調(diào)試。在iOS逆向中,很多人推薦debugserver + lldb 其實(shí)調(diào)試只需要lldb就夠了。
debugserver配置的文章有很多,從14年到18年不等,但大部分都過時了。所以我也沒用。那 只用lldb該怎么斷點(diǎn)調(diào)試三方app呢?我們先來簡單看下lldb的斷點(diǎn)命令。

1.1 LLDB斷點(diǎn)命令:

1.1.1 設(shè)置斷點(diǎn) 下斷點(diǎn)命令我們只需要先會兩個就夠了:

a: 給指定內(nèi)存地址下斷點(diǎn): br set -a 0x00000000全拼我記不住
b: 給某方法下斷點(diǎn):b -n "[ClassName methodName]" 全拼同樣記不住
關(guān)于a,怎么定位方法內(nèi)存,一會再講。
關(guān)于b,很多app打App Store包的時候,是去掉了符號表的編譯配置項(xiàng)的。所以,我們暫時打不了三方app的方法斷點(diǎn)。不過不用急,后面我們會教大家如何還原三方app的符號表。

1.1.2 查看斷點(diǎn)

br list這個全拼我能記住:breakpoint list

1.1.3 刪除斷點(diǎn)
br del n 這里的n是上一步br list列出的斷點(diǎn)的序號。根據(jù)對應(yīng)的序號刪除想刪的斷點(diǎn)。當(dāng)然你也可以直接br del,然后lldb會問你是否要刪除全部斷點(diǎn)。[Y/n] ? 輸入Y即可。

1.2 如何定位函數(shù)地址

好 我們先來看看如何找到想斷點(diǎn)的函數(shù)的地址。為了降低被黑客攻擊的風(fēng)險(xiǎn),操作系統(tǒng)大都采用ASLR(地址空間布局隨機(jī)化) 技術(shù): 詳細(xì)解釋請看這 這個人的內(nèi)存管理講的不錯,一共7篇,建議大家有時間看看。

ASLR是一種避免類似攻擊的有效保護(hù)。進(jìn)程每一次啟動時,地址空間都會被簡單地隨機(jī)化:進(jìn)行整體的地址偏移,而不是攪亂。通過內(nèi)核將整個進(jìn)程的內(nèi)存空間“平移”某個隨機(jī)數(shù),進(jìn)程的基本內(nèi)存布局如程序文本、數(shù)據(jù)、庫等相對位置仍然是一樣的,但其具體的地址都不同了。
簡單來說,ASLR會在進(jìn)程啟動時候隨機(jī)一個基地址
lldb中的查看命令是image listimage list -o -f。


如過命令后面不加參數(shù),它打印的就是每個image(鏡像)的虛擬內(nèi)存地址。
如果加了-o參數(shù),打印的就是image的偏移量(相對于誰,暫時還沒研究)。

具體區(qū)別如下:
image list 打印的基地址: 0x102a94000
image list -o -f的地址: 0x002a94000

看出區(qū)別了么?第9位差了一個1。
這個1正好跟IDA工具中的0x 1 0000 0000對上了。
原因終于找到了,在:楊瀟玉大哥的這篇文章。main()調(diào)用之前會調(diào)用exec(),exec() 是一個系統(tǒng)調(diào)用。系統(tǒng)內(nèi)核把應(yīng)用映射到新的地址空間,且每次起始位置都是隨機(jī)的(因?yàn)槭褂?ASLR)。并將起始位置到 0x000000 這段范圍的進(jìn)程權(quán)限都標(biāo)記為不可讀寫不可執(zhí)行。如果是 32 位進(jìn)程,這個范圍至少是 4KB;對于 64 位進(jìn)程則至少是4GB。NULL 指針引用和指針截?cái)嗾`差都是會被它捕獲。4GB = 232,用二進(jìn)制表示就是:第32+1位為1,剩下的32位為0。而4位二進(jìn)制位可以表示一個十六進(jìn)制位,所以十六進(jìn)制表示就是:0x 1 0000 0000。這樣就滿足了64位進(jìn)程至少4GB的最小偏移范圍了。

這里我們提到的地址是虛擬地址,為什么不是物理地址?
原因是:操作系統(tǒng)將我們(程序猿)跟物理內(nèi)存劃分了一個安全界限,我們程序猿只需要用虛擬內(nèi)存跟操作系統(tǒng)打交道即可,操作系統(tǒng)調(diào)用底層硬件api,跟物理內(nèi)存打交道。如果程序猿直接跟物理內(nèi)存交流,恐怕不是那么安全的。程序一旦出了bug,可能會導(dǎo)致系統(tǒng)癱瘓。

基地址有了,在前面ASLR技術(shù)中我們提到內(nèi)核將整個進(jìn)程的內(nèi)存“平移”,所以數(shù)據(jù)段、代碼段等等內(nèi)存的偏移量其實(shí)是固定的,他們相對于mach-o header部分的偏移量是個常亮,那既然如此,我們的IDA工具又派上用場了:


這里列出的偏移地址,就是函數(shù)相對于mach-o的起始地址的偏移量,所以:
虛擬地址 = 基地址 + 偏移地址
那么,我們就可以在lldbbr set -a 0x102a94000下斷點(diǎn)了。
在這里在交給大家兩個好用的命令:
讀內(nèi)存命令:x 0x102a94000 全拼是:memory read 0x102a94000
反匯編命令:dis -s 0x102a94000 dis是dissamble的簡寫。

我們調(diào)試別人的app,是看不到源碼的,只能看匯編。所以這里建議大家學(xué)一下匯編。我知道很多人聽到匯編就頭大,不過不要緊,找對了教材,匯編真的可以通俗易懂。比如這本:《匯編語言第3版》王爽著。學(xué)習(xí)時長兩三天就夠。不信你試試。
我是從網(wǎng)上下的影印版PDF,閱讀效果不太好,大家可以買正版書或者正版PDF來學(xué)習(xí)。

學(xué)完了匯編,CPU工作原理你就基本了解了,再跟內(nèi)存交流起來就方便多了。不過你可能還是看不懂xcode中出現(xiàn)的上古語言。因?yàn)閮烧叩膮R編指令集不一樣,書里的CPU是古老的8086,是地址總線20位,數(shù)據(jù)總線16位的16位機(jī)器。而iPhone 5s之后都是arm64 CPU,命令不太一樣,總線位數(shù)也不一樣,不過如果你理解了CPU的工作原理,arm64其實(shí)只是換了一種語法而已。而且CPU尋址操作也變得更簡單。畢竟arm64數(shù)據(jù)總線跟地址總線位數(shù)相同(皆為64位),CPU不再需要地址加法器計(jì)算地址了。

這些都掌握了之后,我們可以看一下runtime源碼,重點(diǎn)看一下objc/message部分。
目前蘋果官方最新的是objc4-762版本,為了方便調(diào)試,我從github上下載了objc4-750版本,就差一個版本,不影響我們理解原理。
runtime 非官方Git地址
可以結(jié)合這篇文章進(jìn)行理解。作者梳理的很好,從objc_msgSend的匯編代碼入口開始,梳理到最終的runtime消息轉(zhuǎn)發(fā)機(jī)制。

有了這些基礎(chǔ),下面我們再進(jìn)行斷點(diǎn)調(diào)試的時候,就會方便很多。

比如說,我們給沒有隱藏符號表的app下斷點(diǎn):


斷點(diǎn)viewDidAppear:

未隱藏符號表的程序,斷點(diǎn)的時候,函數(shù)名也會顯示出來。

接下來我們將用到一個進(jìn)階命令:register read 查看寄存器信息:


前面如果你研究了runtime的objc_msgSend函數(shù),你就會知道,該函數(shù)有兩個默認(rèn)參數(shù)(receiver, cmd),第一個參數(shù)是消息接收者,第二個是函數(shù)地址。在iOS arm64 CPU中,通用寄存器中的x0~x7寄存器 用于參數(shù)傳遞。所已x0寄存器的值就是我們該函數(shù)的第一個參數(shù):消息接收者,也就是DJHomeViewController類型的一個對象。結(jié)合po命令,我們就可以查看很多東西了。
第二個參數(shù)是函數(shù)地址,對應(yīng)x1寄存器。
objc_msgSend中第三個參數(shù)(x2寄存器),就是viewDidAppear:后面的傳參了,我們看到這個值是0. 回頭看看class-dump,可以看到這個參數(shù)要求傳一個布爾值,那么 我們就可以猜出該函數(shù)入?yún)⑹莊alse。

有了對象和參數(shù)地址,你就擁有了一切。

比如,我們通過class-dump 看到該類有這么一個屬性,那我們就可以直接訪問!

我們可以用p命令 輸出一下對象,該功能有點(diǎn)類似于expression命令。
此時會生成一個$符號開頭的變量,這個變量可以在后續(xù)lldb中使用。
那么接下來我們就可以利用kvc進(jìn)行訪問任何內(nèi)容了。也可以直接像寫OC代碼一樣,在lldb中寫方法調(diào)用。例如:po [$10 class];
lldb常用命令可以看這里、或這里。網(wǎng)上有很多這類文章,大家可以自行查找。

到這里,我們可以看到,假如調(diào)試的時候能看到函數(shù)名,那我們逆向就沒有任何阻礙。所以,符號表是我們的必爭之地!
如何還原符號表,請看下集:iOS逆向資料(四):還原符號表,再無障礙

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容