fishhook的使用
下载fishhook源码,新建工程,拖到工程中。使用fishhook来hookNSLog
创建一个
rebinding
结构体,设置3个参数。分别是:函数名,函数指针,新函数。按照原函数的格式定义一个新函数用来替换。定义函数指针用来接收被hook的函数,方便之后调用原函数。调用rebind_symbols
传入结构体,这样就hook完成了。
struct rebinding rebing;
rebing.name = "NSLog";
rebing.replaced = (void *)&orig_NSLog;
rebing.replacement = sww_NSLog;
struct rebinding bds[] = {rebing};
rebind_symbols(bds, 1);
//函数指针
static void (*orig_NSLog)(NSString *format, ...);
void sww_NSLog(NSString *format, ...){
NSString *str = [@"hook到了NSLog:" stringByAppendingString:format];
orig_NSLog(str);
}
在touchesBegin中调用NSLog方法,可以看到已经hook成功了。
符号绑定
当我们调用系统的C函数时,比如NSLog,这个函数在Foundation中,Foundation存在手机里,我们并不知道函数的真实地址。NSLog是外部符号,编译生成MachO文件时,把它保存在间接符号表中,他也在懒加载符号表中。第一次调用时,dyld会对NSLog进行符号重绑定,指向真正的函数地址,第二次包括以后再调用,就会跳转到真正的函数地址了。
汇编验证
通过查看两个NSLog的汇编,验证绑定过程
进入汇编,看到两个
bl 0x1043824f0
的指令,调用NSLog
进去第一个NSLog
进去
br x16
这里看到要调用dyld_stub_binder函数,这个就是dyld的绑定函数。
过掉dyld_stub_binder函数,进入第二个NSLog的汇编
进入下一步
这里看到直接进入NSLog的函数实现。
汇编+MachO
在汇编代码中,看到NSLog函数都会跳转到0x1005565a8地址去执行,读出0x1005565a8中的值为图中所示。通过image list拿出ASLR为0x0000000100550000,0x1005565a8在MachO中的偏移量为65a8,此时我们去MachO文件中查看。
进入到第一个NSLog里面,查看汇编,打印x16中的值0x0000000100556638,减去ASLR0x0000000100550000,结果为6638
去MachO中找偏移量为6638的位置,是一段汇编代码,最后会执行到6620
图:重绑定
这段代码,最后就是走到了dyld_stub_binder函数,进行重绑定。
看一下懒加载符号表,所有的外部函数都在这里,他们的data就是偏移量,NSLog6638,NSStringFromClass6644,UIApplicationMain66a4,去看
图:重绑定
,这个函数都会调用到6620,走到dyld_stub_binder函数,进行重绑定。
总结 符号绑定的过程:
- 外部函数执行首先调用
桩
代码 Text Stubs(执行懒加载符号表
中对应的函数) - 懒加载符号表里默认保存的是寻找binder函数(绑定之后,修改
懒加载符号表
中的值,改为函数的真实地址)
fishhook原理
fishhook只能hook系统的C函数。原因是:系统的C函数在MachO中的符号对应一个函数地址,fishhook所做的事情就是,修改了MachO文件中这个符号与地址的对应关系,把系统C函数绑定一个自定义的函数地址。修改了懒加载和非懒加载符号表。
下面为fishhook官方原理图:
- 懒加载符号表中拿到一个符号的index.
- 通过index,找到间接符号表中对应的符号,拿到其在Symbol Table中的index
- 在Symbol Table中找到对应符号,拿到其在String Table中的偏移量
- 在String Table中找到字符,与给定的名字对比,相同则修改其懒加载符号表中的函数地址为自定函数
去符号与恢复符号
我们的app在打包上架的时候。默认都会选择脱掉所有符号,包括本地符号,全局符号。这样既能减少包的体积,也能增加app的安全性。
脱掉符号的可执行文件,只有间接符号。
当我们遇到脱掉符号的app时,调试起来就比较困难了。但是我们可以恢复符号,原理就是根据OC的runtime,类名和方法名这些是不会被脱掉的,我们可以使用工具恢复OC的方法。
使用retore-symbol工具可以直接回复符号。恢复之后,会在Symbols里。之后还需要重新打包生成ipa,重签名等。