Fishhook原理解析

初识fishhook

Fishhook 是 facebook 的开源库。官方描述,它的作用是:

... enables dynamically rebinding symbols in Mach-O binaries running on iOS in the simulator and on device

支持对 iOS 模拟器和设备上运行的 Mach-O 二进制文件,动态地重绑定其中的符号

更浅显的解读是,如果你的程序调用了动态库中的函数 A,可以通过 fishhook,在运行时将“调用函数 A”改为“调用函数 B”。

Fishhook 的源码只有 250 行,因此可以方便地接入到业务中。

C函数调用也能篡改?

我们能理解 OC 中 method swizzling 的原理。因为 OC 有一套运行时机制,因此给 OC 对象 ​obj​ 发送消息 ​call​ 时,要经过 runtime 的匹配,才能在运行时得出 ​call​  方法的地址,让指令跳转到 ​call​ 方法内部。因此,只要在 runtime 匹配的过程中做手脚,就可以将 ​call​ 方法篡改为其他方法。

但是 C 语言中,调用某个函数,指令跳转到某个地址,这是在编译链接时就决定的。看起来我们并不能在运行时改变这个地址。但实际上,如果调用的函数是动态库中的,那么,这个二进制程序,在启动前也并不知道动态库中这个函数的地址。这个地址也是运行时计算得到的。因此这就给 fishhook 提供了机会。

先看上一篇博客:

Fishhook做了什么?

  这时,我们想,如果把 __la_symbol_ptr 中存的地址改了,那是不是就能把 printf 函数指向其它一段指令了呢?Fishhook 也是这样想的。所以 Fishhook 的原理,也是篡改内存中 __la_symbol_ptr 中的内容。把原本应该存 printf() 地址的那块内存,内容改为 my_printf() 地址。

  那么问题来了,我们能用函数指针的方式,知道 my_printf() 的地址,但是我们怎么知道,__la_symbol_ptr 中的第几个元素,表示的是 printf() 的地址呢?

  如果我们能知道 __la_symbol_ptr 中的第 n 个元素,表示的函数的名字,那我们可以遍历 __la_symbol_ptr 数组,找到表示 printf() 的那个。

于是现在问题变成了,我们怎么知道 __la_symbol_ptr 中的每个元素表示的函数的名字呢?

这里就有一个规律:遍历__la_symbol_ptr中的每个元素获取到函数名,去判断是否要篡改的函数

Fishhook原理解析_第1张图片

走一遍流程:

__la_symbol_ptr -->  Indirect Symbols

MachO 文件有个规律,__la_symbol_ptr 节中的第 i 个数据,在 Indirect Symbols 中有对应的体现,且 index 变成了 reserved0 + i。

printf() 对应的数据,在 __la_symbol_ptr 节中是第 10 个元素,__la_symbol_ptr 中的 reserved1 为 12,那么我们找到 Indirect Symbols 中的第 22 个元素:Fishhook原理解析_第2张图片

Fishhook原理解析_第3张图片

这里的值是 0x50

Indirect Symbols --> Symbol Table

我们拿着 0x50,去 Symbol Table 中找到 Symbol Table 中 index = 0x50 的数据。??

Fishhook原理解析_第4张图片

得到0x233

struct nlist_64 {
    union {
        uint32_t  n_strx; /* index into the string table */
    } n_un;
    uint8_t n_type;        /* type flag, see below */
    uint8_t n_sect;        /* section number or NO_SECT */
    uint16_t n_desc;       /* see  */
    uint64_t n_value;      /* value of this symbol (or stab offset) */
};

Symbol Table --> String Table

Symbol Table 中偏移量为 0x233 的字符串,就是 _printf

Fishhook原理解析_第5张图片

这样,主 binary 就知道,__la_symbol_ptr 节中的第 10 个元素,代表 printf,

篡改 __la_symbol_ptr 中的数据

这样,fishhook 只要遍历一次 __la_symbol_ptr,当发现第 i 个元素对应的名字,就是我们要 hook 的名字时,就可以将 __la_symbol_ptr 中的第 i 个元素的值篡改掉,完成 hook 的过程。

参考资料

Fishhook 源码:https://github.com/facebook/fishhook

iOS逆向(6)-从fishhook看runtime,hook系统C函数 https://www.jianshu.com/p/b6a72aa6c146

Dyld之二: 动态链接过程:https://blog.cnbluebox.com/blog/2017/10/12/dyld2/

你可能感兴趣的:(IOS)