抛出问题
OC
语言时动态语言,比如runtime
,很多东西时在运行时才确定的,比如方法调用,底层是在运行时调用objc_send
,通过SEL
去找对应的方法实现IMP
.正式因为运行时特性我们可以通过交换两个方法的IMP
来实现方法交换也就是iOS
老生常谈的MethodSwzzing
.
那么'c'语言属于静态语言,编译时刻就已经确定了函数地址.也就是说c函数调用时直接调用地址的
那么NSLog
等外部代码在编译时,我们时根本不知道他的真实地址的,因为他存在Foundation
框架中,是在系统中的共享缓存中的,所有APP
都是可以使用的,所以编译时根本不知道其真实地址. 那么这不是前后矛盾么
PIC(位置无关代码/位置独立代码)
在iOS
和macOS
中MachO
中有Text
段也就是代码段 和Data
段, 因为Text
段时rx
权限,所以apple
就在Data
段中放了一个占位符,让外部c函数先指向占位符,然后在运行的时候DYLD
将占位符修改成真实地址. 这个过程叫做符号绑定.
这个过程跟OC中的方法sel -> imp是很像的,正是有这个过程的存在所以可以修改占位符达到一个方法的Hook
,这也是fishhook
的原理
编译时模型: bl -> 占位符(Symbol)
运行时模型: bl -> 桩地址(Symbol Stubs段代码进行符号绑定) -> 真实地址
符号绑定过程
FishHook 是如何通过字符串找到符号表位置的
Lazy Symbol Pointers
懒加载表 所有需要进行bind
的函数都会在这个表中
Indirect Table
间接符号表,外部函数,也就本MachO以外的函数
Lazy Symbol Pointers
跟Indirect Table
的位置是有一一对应的关系
如图
Indirect Table
第一条也为NSlog
对应的data
,对应的data值000000EC
转换为10进制 为 236
代表的是NSLlog在总表也就是
Symbols中位置的角标
index`
可以看到 String Table Index
,data
就代表NSLlog
在String Table
中的位置000000E7
0000D7B0 + 000000E7 = 0000D897
就是NSlog
在String Table
中的地址
贴上一张fishhook github上的一张图
系统流程:
Lazy Symbol Table
中对应的index
Indirect Symbol Table
对应的index
找到data
字段(代表Symbol
中NSlog
对应的index
)Symbol Table
对应的位置找到data
字段(代表String Table
中的位置offset
偏移)string table (start address + offset)
就是NSlog
字符串的地址