iOS開發-fishhook交換NSLog函數實現

fishhook

https://github.com/facebook/fishhook

fishhook是一個facebook的開源項目。

通過修改Mach-O文件指向外部函數的指針的值,來達到hook的目的

hook原理

蘋果爲了能在 Mach-O 文件中訪問外部函數,採用了一個技術,叫做PIC(位置代碼獨立)技術。
當你的應用程序想要調用 Mach-O 文件外部的函數的時候,或者說如果 Mach-O 內部需要調用系統的庫函數時,Mach-O 文件會:

先在 Mach-O 文件的 _DATA 段中建立一個指針(8字節的數據,放的全是0),這個指針變量指向外部函數。
DYLD 會動態的進行綁定!將 Mach-O 中的 _DATA 段中的指針,指向外部函數。
所以說,C的底層也有動態的表現。C在內部函數的時候是靜態的,在編譯後,函數的內存地址就確定了。但是,外部的函數是不能確定的,也就是說C的底層也有動態的。fishhook 之所以能hook C函數,是利用了 Mach-O 文件的 PIC(位置代碼獨立) 技術特點。也就造就了靜態語言C也有動態的部分,通過 DYLD進行動態綁定的時候做了手腳。

原文鏈接:https://www.jianshu.com/p/4d86de908721

大概就是說:

app是一個mach-o文件,其內容中_DATA字段有一個指針,指向外部框架(例如Fundation),例如Fundation框架的NSLog,我們通過修改_DATA字段的這個指針指向我們所寫的函數,然後在函數中指向原函數,就可以達到hook的目的。

hook

通過 MachOView 這個軟件打開 appMach-O 文件
在這裏插入圖片描述
加載Mach-ONSLog屬於lazy symbol Pointer

對於非懶加載符號表 Non-lazy symbol Pointer,DYLD會立刻馬上去鏈接動態庫   
對於懶加載符號表 lazy symbol Pointer,DYLD會在執行代碼的時候去動態的鏈接動態庫

通過fishhook修改代碼如下:

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    // 這裏由於NSLog是lazy pointer,所以需要調用一次,纔會被寫入_DATA 中的指針
    NSLog(@"dylib link address");
    
    struct rebinding nslogbind;
    
    nslogbind.name = "NSLog";
    nslogbind.replacement = newmethod;
    nslogbind.replaced = (void*)&old_nslog;
    
    struct rebinding rebinds[] = {nslogbind};
    //這裏進行斷點
    rebind_symbols(rebinds, 1);
    
}

static void (*old_nslog)(NSString *format,...);


void newmethod(NSString *format,...) {
    va_list va;
    va_start(va, format);
    //改變下字符串,證明hook過了
    format = [format stringByAppendingString:@" hook"];
    old_nslog(format,va);
    va_end(va);
    
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    NSLog(@"點擊屏幕");
}

@end

通過 rebind_symbols 斷點來檢測hook前後的_DATA中的符號表指針存儲是否改變。

找到NSLog的地址

找到NSLog對應包中的偏移量。

在這裏插入圖片描述
Offset表示符號偏移量,當Mach-O文件加載後,NSLog符號表綁定地址應該是Mach-O文件偏移量 + Offset

Mach-O文件偏移量可以通過llvm在xcode斷點時打印image list獲取

(lldb) image list
[  0] D6F7D258-D608-3ED0-A7D1-16215F661AEE 0x0000000100264000 /Users/sheng/Library/Developer/Xcode/DerivedData/hookTest-fdbgciwrddbskoafylnbaldfxzyr/Build/Products/Debug-iphoneos/hookTest.app/hookTest 
[  1] 3049BF50-A9B1-318C-8B2B-34774DE49438 0x0000000100434000 /Users/sheng/Library/Developer/Xcode/iOS DeviceSupport/12.4.5 (16G161)/Symbols/usr/lib/dyld 
[  2] 5D56F475-48DE-3DF0-955D-EBABE2A63DCF 0x000000019eea2000 /Users/sheng/Library/Developer/Xcode/iOS DeviceSupport/12.4.5 (16G161)/Symbols/System/Library/Frameworks/Foundation.framework/Foundation 
...

hookTest的偏移量是 0x0000000100264000
那麼NSLog的符號綁定地址就是 0x0000000100264000+0x8018

(lldb) x 0x0000000100264000+0x8018
0x10026c018: 4c c4 fb 9e 01 00 00 00 58 24 fb 9e 01 00 00 00  L.......X$......
0x10026c028: 64 2b b8 ca 01 00 00 00 90 a5 26 00 01 00 00 00  d+........&.....

//這地址裏面的值,是指向外部函數的指針的地址,也就是動態緩存區裏面 NSLog 的真實函數地址。
// 地址從右往左,字節爲單位
4c c4 fb 9e 01 00 00 00 
//得到地址爲
0x000000019efbc44c

通過dis -s反彙編查看

(lldb) dis -s 0x000000019efbc44c
Foundation`NSLog:
    0x19efbc44c <+0>:  sub    sp, sp, #0x20             ; =0x20 
    0x19efbc450 <+4>:  stp    x29, x30, [sp, #0x10]
    0x19efbc454 <+8>:  add    x29, sp, #0x10            ; =0x10 
    0x19efbc458 <+12>: add    x8, x29, #0x10            ; =0x10 
    0x19efbc45c <+16>: str    x8, [sp, #0x8]
    0x19efbc460 <+20>: add    x1, x29, #0x10            ; =0x10 
    0x19efbc464 <+24>: mov    x2, x30
    0x19efbc468 <+28>: bl     0x19efbc3bc               ; _NSLogv

hook後的地址

斷點過了之後,我們還是一樣查看(lldb) x 0x0000000100264000+0x8018

(lldb) x 0x0000000100264000+0x8018
0x10026c018: 00 94 26 00 01 00 00 00 58 24 fb 9e 01 00 00 00  ..&.....X$......
0x10026c028: 64 2b b8 ca 01 00 00 00 68 2a 06 9e 01 00 00 00  d+......h*......

//00 94 26 00 01 00 00 00
//0x0100269400

(lldb) dis -s 0x0100269400
hookTest`newmethod:
    0x100269400 <+0>:  sub    sp, sp, #0x40             ; =0x40 
    0x100269404 <+4>:  stp    x29, x30, [sp, #0x30]
    0x100269408 <+8>:  add    x29, sp, #0x30            ; =0x30 
    0x10026940c <+12>: mov    x8, #0x0
    0x100269410 <+16>: stur   x8, [x29, #-0x8]
    0x100269414 <+20>: sub    x9, x29, #0x8             ; =0x8 
    0x100269418 <+24>: str    x0, [sp, #0x18]
    0x10026941c <+28>: mov    x0, x9

已經替換成newmethod

點擊屏幕控制檯輸出

2020-03-28 20:43:31.938544+0800 hookTest[10749:1804880] 點擊屏幕 hook

這裏完成了NSLoghook,接下來就想實現對objc_msgSend方法的hook,但是這個函數是彙編編寫的.s文件 ,要實現hook需要了解彙編,並重寫一個新的方法。後續…

參考文章: https://www.jianshu.com/p/4d86de908721

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章