iOS 上修改私有方法的几种方式解析
通过创建 Category 复写,这种方式简单而粗暴,在面试中往往会被遗忘,但它有什么明显的副作用,而且为什么在 Category 中复写就能覆盖原方法实现,也很值得深究;
通过 void method_exchangeImplementations(Method m1, Method m2) 等类似方式实现 Method Swizzling,可能由于 mattt 的强大社区影响力这种方式现在已经“烂大街”了,绝大多数开发者都会多少有所了解,但这种“烂大街”的写法是为什么这么写的,仍然值得探讨;
通过第三方框架 Aspects 来修改私有方法,对于项目内有强 AOP 编程需求的很可能会选择这个方式,那么 Aspects 相对于普通的 Method Swizzling 有什么区别,它又是怎么实现交换后的还原呢,这点也想和大家分享;
Fishhook 这种方式本不该拿到这里来讨论,相对于前面三种方式都是针对 OC 这个语言的动态性来做文章的,Fishhook 则是对 C 语言方法进行了 Hook,它在逆向技术中占据了很大的作用。OC 的消息转发机制是依赖于 C 函数 objc_msgSend ,那么在一些特殊需求需要直接 Hook C 函数的话,Fishhook 就会派上用场了,这里也会对 Fishhook 如何实现 Hook C 语言方法作一些简介;
Fishhook
在__DATA Segment上创建一个指针,等到启动的时候,dyld动态的去做绑定(bind)
核心原理,finshhook就是通过rebind_symbols修改__DATASegment上的符号指针指向,来动态的hook C函数。
__DATA段中,有两个Sections和动态符号绑定有关:
__nl_symbol_ptr 存储了non-lazily绑定的符号,这些符号在mach-o加载的时候绑定。
__la_symbol_ptr 存储了lazy绑定的符号(方法),这些方法在第一调用的时候,由dyld_stub_binder来绑定,所以你会看到,每个mach-o的non-lazily绑定符号都有dyld_stub_binder。
具体的Hook过程
1 遍历Load Command,找到__LINKEDIT段,stab symbol table和symbol
2 找到symbol和string table的base地址
3 获取indriect table的数据(uint32_t类型的数组)
4 再一次遍历laod command,这一次遍历__DATA段中的Sections,对S_LAZY_SYMBOL_POINTERS和S_NON_LAZY_SYMBOL_POINTERS段中的指针进行rebin,调用函数perform_rebinding_with_section
5perform_rebinding_with_section,进行section中的symbol rebind。
MachOView 这个工具可以快速查看 Math-O 格式的文件,简单易用
1 |
Mach-O 文件的动态链接、库、Dyld(含dlopen)
(二) Mach-O 文件结构
系列文章