fishhook
· 阅读需 4 分钟
fishhook 是 Facebook 开源的一个轻量级库,它允许你在 iOS 和 macOS 平台上动态地重绑定 Mach-O 二进制文件中的符号。这意味着你可以在运行时“钩取”(Hook)系统级的 C 函数调用,将其替换为你自己的实现,而无需修改原始的二进制文件或重新启动应用。
🔧 核心原理
fishhook 的实现非常巧妙,它利用了 Mach-O 文件格式的动态链接机制。其核心原理可以概括为以下几点:
- 目标区域:
fishhook修改的并非只读的代码段(__TEXT),而是可写的数据段(__DATA)中的符号指针表(具体是__la_symbol_ptr和__nl_symbol_ptr节)。这些指针在程序启动时由动态链接器(dyld)填充为外部函数(如printf)的真实地址。 - 操作机制:通过
vm_protect这个底层系统调用,fishhook临时改变了存储符号指针的内存页面的保护属性,使其从只读变为可写。 - 写时复制(Copy-on-Write):这是关键的一步。当使用
VM_PROT_COPY参数时,系统会为当前进程创建一个该内存页的私有副本。这样,修改只会影响当前进程,而不会破坏共享的系统库。 - 地址替换:最后,
fishhook将符号指针表中目标函数的地址替换为你提供的自定义函数的地址。此后,所有通过该符号指针表发起的调用都会转向你的函数。
简单来说,fishhook 就像是修改了一个函数地址的“通讯录”,让程序在不知情的情况下调用你指定的新函数。
📝 使用方法
使用 fishhook 的步骤非常直接,通常包含以下三个环节:
- 引入库文件:将
fishhook.h和fishhook.c两个文件添加到你的项目中。 - 准备替换函数:定义一个与你想要钩取的函数签名完全一致的函数。在这个函数里,你可以添加自己的逻辑,并选择是否调用原始函数。
- 执行重绑定:调用
rebind_symbols函数,告诉fishhook要替换哪个符号。
下面是一个钩取 printf 函数的经典示例:
#include <stdio.h>
#include "fishhook.h"
// 用于保存原始printf函数指针的变量
static int (*orig_printf)(const char * restrict format, ...);
// 自定义的printf函数
int my_printf(const char * restrict format, ...) {
// 添加钩取逻辑,例如在输出前加上一个标记
orig_printf("[Hook] ");
// 继续执行原始printf的功能
va_list args;
va_start(args, format);
int result = orig_printf(format, args);
va_end(args);
return result;
}
int main() {
// 构造一个rebinding结构体数组
struct rebinding rebs[1] = {
{"printf", (void *)my_printf, (void **)&orig_printf}
};
// 执行重绑定
rebind_symbols(rebs, 1);
// 此时调用printf,实际执行的是my_printf
printf("Hello, Fishhook!\n"); // 输出: [Hook] Hello, Fishhook!
return 0;
}
代码示例整合自和
⚠️ 特点与局限性
了解 fishhook 的能力边界非常重要:
- 主要优势:
- 针对系统 C 函数:非常适合钩取来自
libSystem(如malloc,open,printf)等动态库的函数。 - 无需越狱:可在非越狱环境的 App Store 应用中使用。
- 针对系统 C 函数:非常适合钩取来自
- 主要局限性:
- 无法钩取静态函数:如果函数的实现在编译时已经静态链接到最终的可执行文件中(地址在编译期就已确定),
fishhook无法修改它。 - 无法钩取内联函数:编译器内联展开的函数没有独立的符号地址,因此无法被钩取。
- 对 Swift 函数效果有限:由于 Swift 复杂的名称修饰(Name Mangling)机制,直接钩取 Swift 函数比较困难。
- 无法钩取静态函数:如果函数的实现在编译时已经静态链接到最终的可执行文件中(地址在编译期就已确定),
🛡️ 应用场景与防护
fishhook 的强大功能使其在多种场景下发挥作用:
- 调试与日志记录:跟踪特定的系统调用,如记录所有文件操作(
open)或内存分配(malloc)。 - 性能监控:测量关键函数的执行时间。
- 安全研究:分析应用的行为或进行逆向工程。
- 功能扩展:在不拥有源码的情况下为现有函数添加新功能。
正因为 fishhook 可能被用于恶意目的,也催生了相应的防护技术。例如,AntiFishhook 就是一个专门设计来实时检测和防御 fishhook 攻击的库。
💎 总结
总而言之,fishhook 是一个通过动态修改 Mach-O 文件数据段中的符号绑定来实现 C 函数钩取的强大工具。它深刻体现了 macOS/iOS 系统底层动态链接的灵活性。
希望这些信息能帮助你全面理解 fishhook。如果你对某个特定细节或应用场景有进一步的疑问,我很乐意提供更多解答。
微信公众号

