iOS开发-fishhook交换NSLog函数实现

文章目录

  • fishhook
    • hook原理
  • hook
    • 找到NSLog的地址
    • hook后的地址

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 文件
iOS开发-fishhook交换NSLog函数实现_第1张图片
加载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对应包中的偏移量。

iOS开发-fishhook交换NSLog函数实现_第2张图片
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

你可能感兴趣的:(iOS开发-fishhook交换NSLog函数实现)