iOS由MacOS系統修改而來,所以很多機制是相同的,與Android-Linux相比相似性更高。iOS符號分為自動non-lazy和lazy綁定符號,non-lazy符號位于Mach-O文件__DATA Segment 的__nl_symbol_ptr section,lazy符號位于__DATA Segment 的__la_symbol_ptr section。對于non-lazy的符號綁定時機為動態庫加載(load),lazy符號的綁定時機則與Linux相同即函數第一次被調用。
測試代碼
#include <stdio.h>
int main(int argc, const char * argv[]) {
// insert code here...
printf("Hello, World!\n");
printf("Hello World Again!\n");
return 0;
}
lldb 調試
反匯編main函數
+34為調用第一個printf函數,+51第二次調用printf函數。
二進制文件DATA段有兩個section
DATA Segment
不用展開也應該能猜到是哪兩個sction,section[0]為__nl_symbol_ptr section[1]為__la_symbol_ptr 。回到匯編代碼,printf函數的地址無論第一次還是第二次都是0x100000f66,這個地址來自哪呢?
add.PNG
由上圖可知,0x100000f66值為__TEXT Segment中的__stub section。
該section的作用解釋如下
- section (__TEXT,__stubs) - section contains stubs with prefix imp___stubs__. That stubs are used in the code of __text section to compile procedures with external dependencies, such as system NSLog. dyld (dynamic linker) will replace such stubs on runtime with actual place in dynamic library.
大意就是該section保存的是編譯過程中的外部依賴,在運行時動態鏈接器dyld將其替換為實際位置 PS:靈魂翻譯
call下斷,si進去
程序jmpq 0x0000000100000f7c,在__la_symbol_ptr section address中符號的地址為0x0000000100001010
ladd.PNG
值相等
繼續調試
Screen Shot 2017-05-09 at 1.22.04 PM.png
0x0000000100000f7c僅將0x0壓棧后就jmp回0x100000f6c,printf函數的地址查詢最終是通過dyld_stub_binder函數實現。dyld_stub_binder中符號查找原理可以參考fishhook
看了以上匯編是否覺得與Linux PLT頗有幾分相似?
0x0同樣為索引
調用dyld_stub_binder前堆棧信息
第二次調用printf
Screen Shot 2017-05-09 at 1.37.54 PM.png
綁定結束,從此可以直接調用相應函數
返匯編
參考: