离久的小站

关于fishhook

2019/04/22 Share

fishhook 是 Facebook 出的一个非常简单的库,可以在模拟器和设备上的iOS上运行的Mach-O二进制文件中动态重新绑定符号。这提供了类似于DYLD_INTERPOSE在OS X上使用的功能。

facebook fishhook github 地址
我自己写中文注释的 fishhook

实现思路

Mach-O

首先需要学会 Mach-O 文件的知识,上一篇文章有描述

程序启动的时候 Mach-O 文件会被 DYLD (动态加载器)加载进内存。加载完 Mach-O 后,DYLD接着会去加载 Mach-O 所依赖的动态库

ASLR

地址空间布局随机化。它会让 Mach-O 文件加载的时候是随机地址。有了这个技术,Mach-O 文件每次加载进内存的时候地址都是不一样的。主要是为了防止逆向技术

Mach-O 文件里只有我们自己写的函数,系统的动态库的函数是不在 Mach-O 文件里的。也就是说每次启动从 Mach-O 文件到系统动态库函数的偏移地址都是变化的

PIC 位置代码独立

苹果为了能在 Mach-O 文件中访问外部函数,采用了一个技术,叫做PIC(位置代码独立)技术
当你的应用程序想要调用 Mach-O 文件外部的函数的时候,或者说如果 Mach-O 内部需要调用系统的库函数时,Mach-O 文件会:

  1. 先在 Mach-O 文件的 _DATA 段中建立一个指针(8字节的数据,放的全是0),这个指针变量指向外部函数
  2. DYLD 会动态的进行绑定!将 Mach-O 中的 _DATA 段中的指针,指向外部函数

fishhook的原理其实就是,将指向系统方法(外部函数)的符号重新进行绑定指向内部的函数

所以 fishhook 只能 hook 动态加载的系统库 C 函数

具体实现

Mach-O内部有两个指针用来加载动态库:

  1. Non-Lazy Symbol Pointers :不懒加载指针
  2. Lazy Symbol Pointers :懒加载指针

对于非懒加载符号表,DYLD 会立刻马上去链接动态库
对于懒加载符号表,DYLD 会在执行代码的时候去动态的链接动态库 (例如 NSLog)

下图是 facebook 提供的实现原理图

具体思路就是:

  1. 寻找 Mach-O LoadCommand 中的 __LINKEDIT 链接器使用段
  2. 寻找 Mach-O LoadCommand 中的 LC_SYMTAB 符号表信息
  3. 寻找 Mach-O LoadCommand 中的 LC_DYSYMTAB 动态符号表信息
  4. 通过以上三个得到 链接程序时候的基址 、 符号表的地址 、 动态符号表地址 、 字符串表地址
  5. 寻找 Mach-O 中的 S_LAZY_SYMBOL_POINTERS 和 S_NON_LAZY_SYMBOL_POINTERS 两个加载指针
  6. 遍历动态符号表,从而获取符号表中字符串表的偏移量
  7. 通过字符串表地址和偏移量,获取到符号的名字
  8. 将名字和 hook 的目标函数名字对比,如果相同,将指向地址交换
CATALOG
  1. 1. 实现思路
    1. 1.1. Mach-O
    2. 1.2. ASLR
    3. 1.3. PIC 位置代码独立
    4. 1.4. 具体实现