返回

Hook 总结之 fishhook 源码逐行分析

IOS

鱼钩剖析:深入探究 iOS 系统中的 Hook 技术

Hook 技术初探

在 iOS 系统的开发领域,Hook 技术可谓是一门广受推崇的秘术,其能让你随心所欲地改写函数的行为,如同在编程世界中施展魔法。它的用途可谓包罗万象,从代码调试到安全分析,再到性能优化,都能大显身手。

鱼钩鱼钩,鱼跃龙门

在 iOS 平台上,fishhook 堪称 Hook 技术的翘楚,由 Facebook 的大牛们倾情打造。它提供了一套简单易用的 Hook 接口,让你无需修改原始代码,便可尽情施展改造之术。fishhook 采用动态链接库注入的方式,巧妙地修改函数指针,从而实现 Hook 功能。

鱼钩源码,逐层解剖

fishhook 的源码由两部分组成:头文件 fishhook.h 和源文件 fishhook.c 。头文件定义了 Hook 函数接口,而源文件则负责实现 Hook 功能。

1. 鱼钩初始化

fishhook 的初始化过程在 fishhook_init 函数中展开。它首先通过 dlopen 函数加载待 Hook 的动态库,然后获取待 Hook 函数的地址。

void fishhook_init(void) {
    fishhook_init_dyld();
    fishhook_init_objc();
}

2. Hook 方法

fishhook 提供了两种 Hook 方法:rebind_symbolsreplace_symbols

  • rebind_symbols :将待 Hook 函数的指针重新绑定到新的函数,灵活性高,可随时取消 Hook。
  • replace_symbols :直接替换待 Hook 函数的代码,无法取消 Hook。

3. 逐行源码分析

接下来,让我们逐行分析 fishhook.c 源码,领略 Hook 技术的精妙之处:

rebind_symbols 函数:

int rebind_symbols(struct rebinding *bindings, int count) {
    void *old_addr;
    void *new_addr;
    for (int i = 0; i < count; i++) {
        old_addr = bindings[i].orig_addr;
        new_addr = bindings[i].new_addr;
        struct hook_entry *entry = get_hook_entry(old_addr);
        if (entry == NULL) {
            return -1;
        }
        entry->new_addr = new_addr;
        return 0;
    }
}

函数解析:

rebind_symbols 函数对给定的函数列表进行 Hook,将旧函数地址替换为新函数地址。它首先获取旧函数地址和新函数地址,然后查找对应的 Hook 条目。如果 Hook 条目不存在,则返回错误。最后,修改 Hook 条目的新函数地址。

replace_symbols 函数:

int replace_symbols(struct rebinding *bindings, int count) {
    void *old_addr;
    void *new_addr;
    for (int i = 0; i < count; i++) {
        old_addr = bindings[i].orig_addr;
        new_addr = bindings[i].new_addr;
        void *old_ptr;
        old_ptr = *(void * volatile *)old_addr;
        *(void * volatile *)old_addr = new_addr;
        free(old_ptr);
        return 0;
    }
}

函数解析:

replace_symbols 函数直接替换给定函数的代码。它首先获取旧函数地址和新函数地址,然后直接修改旧函数地址指向的新函数地址。最后,释放旧函数的内存。

4. 取消 Hook

fishhook 提供了 unwind 函数取消 Hook。该函数根据 Hook 条目中的信息恢复原始函数地址。

int unwind(struct rebinding *bindings, int count) {
    void *old_addr;
    void *new_addr;
    for (int i = 0; i < count; i++) {
        old_addr = bindings[i].orig_addr;
        new_addr = bindings[i].new_addr;
        struct hook_entry *entry = get_hook_entry(old_addr);
        if (entry == NULL) {
            return -1;
        }
        *(void * volatile *)old_addr = entry->orig_addr;
        free(entry);
        return 0;
    }
}

函数解析:

unwind 函数对给定的函数列表取消 Hook。它首先获取旧函数地址和新函数地址,然后查找对应的 Hook 条目。如果 Hook 条目不存在,则返回错误。最后,修改旧函数地址指向的原始函数地址。

总结

本文对 fishhook 源码进行了深入分析,展现了 Hook 技术在 iOS 系统中的原理和实现。掌握 fishhook 的工作原理,开发者可以更深刻地理解 Hook 技术在 iOS 开发中的应用,为代码调试、安全分析和性能优化等任务提供新的思路。

常见问题解答

  1. Hook 技术有哪些优点?
    Hook 技术能够修改函数行为,而无需修改原始代码,提高了调试、分析和优化的灵活性。

  2. fishhook 和其他 Hook 框架有什么区别?
    fishhook 由 Facebook 开发,以其易用性和对 Objective-C 方法的良好支持而著称。

  3. Hook 技术有哪些安全隐患?
    Hook 技术可能被恶意软件利用,因此在使用时需要谨慎,防止被恶意程序劫持。

  4. 如何使用 fishhook?
    在 iOS 项目中添加 fishhook 库,然后使用其提供的 Hook 函数进行 Hook 操作。

  5. Hook 技术有哪些应用场景?
    Hook 技术广泛应用于代码调试、安全分析、性能优化、测试和修改系统行为等领域。