iOS-Debug-Hacks involves the dynamic debugging, static analysis and decompile of third-party libraries.git
《Advanced Apple Debugging & Reverse Engineering》值得一看github
談談對函數的理解bootstrap
一個函數調用包括將數據(以參數和返回值的形式)和控制從代碼的一部分轉移到另外一部分。在函數調用過程當中,數據傳遞、局部變量的分配和釋放是經過棧來實現的,而爲單個函數調用分配的那部分棧稱爲棧幀(Stack Frame)。函數
(lldb) bt * thread #1, stop reason = trace * frame #0: 0x000000010e533fcf dyld`_dyld_debugger_notification + 1 frame #1: 0x000000010e533795 dyld`gdb_image_notifier(dyld_image_mode, unsigned int, dyld_image_info const*) + 111 frame #2: 0x000000010a36b269 dyld_sim`notifyGDB(dyld_image_states, unsigned int, dyld_image_info const*) + 40 frame #3: 0x000000010a364142 dyld_sim`dyld::notifyBatchPartial(dyld_image_states, bool, char const* (*)(dyld_image_states, unsigned int, dyld_image_info const*), bool, bool) + 814 frame #4: 0x000000010a36d107 dyld_sim`ImageLoader::link(ImageLoader::LinkContext const&, bool, bool, bool, ImageLoader::RPathChain const&, char const*) + 101 frame #5: 0x000000010a364548 dyld_sim`dyld::link(ImageLoader*, bool, bool, ImageLoader::RPathChain const&, unsigned int) + 161 frame #6: 0x000000010a365a5c dyld_sim`dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**, unsigned long*) + 3840 frame #7: 0x000000010a3613d4 dyld_sim`start_sim + 136 frame #8: 0x000000010e52bded dyld`dyld::useSimulatorDyld(int, macho_header const*, char const*, int, char const**, char const**, char const**, unsigned long*, unsigned long*) + 2200 frame #9: 0x000000010e5297a3 dyld`dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**, unsigned long*) + 436 frame #10: 0x000000010e5253d4 dyld`dyldbootstrap::start(macho_header const*, int, char const**, long, macho_header const*, unsigned long*) + 453 frame #11: 0x000000010e5251d2 dyld`_dyld_start + 54
bt 命令是得益於棧幀才能實現的,棧幀能夠當作是函數執行的上下文,其中保存了函數的返回地址和局部變量,咱們知道堆是從低地址向高地址延伸的,而棧是從高地址向低地址延伸的。
每一個函數的每次調用,都會分配給它一個獨立的棧幀,rbp 寄存器指向當前棧幀的底部(高地址),被稱做幀指針,rsp 寄存器指向棧幀的頂部(低地址),被稱做棧指針spa
上述 2 和 3 步驟其實就是 call 指令的任務,而 4 和 5 經過彙編指令表示以下:線程
0x1054e09c0 <+0>: pushq %rbp //第四步 0x1054e09c1 <+1>: movq %rsp, %rbp //第五步
call function
參數中的 function 是 TEXT 段的程序,
call 指令其實能夠拆解成兩步,debug
call 指令其實等價於下面的命令:3d
push next_instruction jmp function
在 OSX 中,最多能夠有 6 個整型(整數和指針)經過寄存器傳遞,這 6 個寄存器分別是 rdi, rsi, rdx, rcx, r8 和 r9(順序和參數的順序保持一致),指針
此時就須要藉助棧了,能夠將剩下的參數逆序壓入棧中。OSX 容許將 8 個浮點數經過浮點數寄存器 xmm0-xmm7 進行傳遞。code
使用 rax 寄存器做爲整數返回值,浮點數返回值則使用 xmm0-xmm1 寄存器
當寄存器的值是字符串的時候,LLDB 能夠經過
po (char *) $rsi
命令輸出寄存器對應的字符串值,
不然直接使用 po $rsi
,只會按照整數格式輸出 rsi 寄存器的值。
消息轉發流程越日後,處理消息所付出的代價也就越大。因此若非必要,應當儘早結束消息轉發流程。若是消息轉發的流程中都沒有處理未知消息,最終會調用 doesNotRecognizeSelector: 拋出異常,表示對象沒法正確識別此 SEL。
@dynamic
使用 @dynamic 告訴編譯器不作處理,而後 Getter 和 Setter 方法是在運行時動態建立
br s 是 breakpoint set 的意思,-n 表示根據函數名稱來下斷點,做用和符號斷點同樣,
br s -F
b -[TCWebViewKit open]
只不過 b 命令是 _regexp-break 的縮寫,是用正則匹配的方式下斷點。
-給在指定的內存地址設置斷點,
下斷點的命令爲 br s -a 0x000000010940b24e
,這種方式能夠用在知道 block 內存地址的時候,給 block 設置斷點。