上篇文章解释了外部符号加载的原理,知道了外部函数地址最后都保存在__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