上篇文章解释了外部符号加载的原理,知道了外部函数地址最后都保存在__DATA_CONST,__got或__DATA,__lay_symbol_ptr。
因此我们如果想要hook外部函数,只需要在启动后修改这两个段内的值就行。
接下来就是怎么找到某个外部符号在__DATA_CONST,__got或__DATA,__lay_symbol_ptr的位置了。
假设这个外部符号名字是MMFWHeaderTest,因为无法确定是懒加载还是非懒加载符号,所以__DATA_CONST,__got和__DATA,__lay_symbol_ptr都要遍历。
但是我们看__DATA_CONST,__got和__DATA,__lay_symbol_ptr在mach-o文件的内容,都是函数指针,没有符号名称。我们要修改这里的值,但是要先找到,第几个符号是MMFWHeaderTest。
SectionHeader
先去Load Commands看看,在这里可以找到__la_symbol_ptr的section header,也可以找__got。

其中Indirect Sym Index(也就是Reserved1)代表在第一个懒加载的符号在间接符号表的位置是第14个。
Size是88,懒加载符号每个大小是8,所以懒加载符号一共有11个。
间接符号表
这样的话,我们需要遍历间接符号表 第14—24 的符号。这里也还是从0开始计数的。

找到间接符号表对应的位置,第一个数据是0x81,这代表这个符号在符号表的第0x81个。
符号表
所以这个符号的地址 = 符号表开头地址 + 0x81 * 符号表每个符号大小(0x10)
我这里是0xC300 + 0x81 * 0x10 = 0xCB10

字符串表
再看字符串表位置,0x74,不过这里是字符串表开头地址+0x74。
我这里是0xCCA8 + 0x74 = 0xCD1C
匹配成功,修改内存值
这就算匹配上了,所以懒加载符号表的第一个就是MMFWHeaderTest,然后我们直接修改__DATA,__la_symbol_ptr里第一个指针的值就行。
匹配失败,继续匹配
如果没匹配上,就回到间接符号表那一步,继续往下匹配。
如果__la_symbol_ptr找完了,就回到SectionHeader那一步,开始找__got。
如果都找完了还没有,那就说明这个符号不存在。
总结
以上就是fishhook的原理,具体操作可以看源码。
mach-o文件结构
- Header
- Load Commands
- Segment Header
- Section Header
- 其他
- Segment Header
- Segment
- Section















![[数据结构]——二叉树——堆的实现](https://img-blog.csdnimg.cn/direct/73b0de2425e242c4a3b8ce2da31a44e9.png)


