08.Hook

一、常见的Hook技术

  • Method Swizzle

    • 利用OC的Runtime特性,动态改变SEL和IMP的对应关系,达到OC方法调用流程的改变。主要用于OC方法。

  • fishhook

    • Facebook提供的一个动态修改链接mach-O文件的工具。利用MachO文件加载原理,通过懒加载和非懒加载两个表的指针达到C函数Hook的目的。

  • Cydia Substrate

    • 主要针对OC方法、C函数以及对函数地址进行Hook操作。不经针对iOS,安卓也可以用。

二、fishhook

fishhook-Githubarrow-up-right

  • 首先回顾一下OC的动态特性

    • 并不是直接调用方法的实现地址,而是通过一张selector和imp的映射表去找

    • 静态语言如C,是直接通过地址访问

      • 但外部C函数调用是通过符号绑定来的

2.1 rebind_symbols

/*
 * For each rebinding in rebindings, rebinds references to external, indirect
 * symbols with the specified name to instead point at replacement for each
 * image in the calling process as well as for all future images that are loaded
 * by the process. If rebind_functions is called more than once, the symbols to
 * rebind are added to the existing list of rebindings, and if a given symbol
 * is rebound more than once, the later rebinding will take precedence.
 */
FISHHOOK_VISIBILITY
int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel);

参数列表:

  • 需要Hook的rebinding数组

  • 长度

2.2 rebinding

name 需要Hook的函数名称,C字符串 replacement 新函数的地址 replaced 原始函数的指针

2.3 使用 rebind_symbols hook NSLog

通过查看接口我们需要创建一些数据。

输出结果:

Hook成功!

2.4 试一试hook C函数?

定义一个这样的函数

修改rebinding信息

发现并没有成功!应为这个是通过地址直接访问的。

三、重绑定符号

一个问题:编译的时候,NSLog的真实地址知道么?不知道。

在MachO加载进内存时,dyld会先加载依赖的系统库进共享缓存。

NSLog在Foundation框架中,加载后dyld会将NSLog的真实地址告诉MachO。

验证一下fishhook的实现:

hook

在hook前后分别下断点,打开汇编断点。

第一个断点:

-> 0x10233d234 <+188>: bl 0x10233e320 ; symbol stub for: NSLog

下一步:

第二个断点:

-> 0x10233d254 <+220>: bl 0x10233e320 ; symbol stub for: NSLog

下一步:

分析:

bl 0x10233e320 ; symbol stub for: NSLog

这一段是到0x10233e320中去寻找符号绑定的地址

第一次的第二步找到了系统原本函数的地址

第二次走到第二步后发现已经是hookNSLog了

四、符号绑定的过程

  • 间接符号表

    • MachO文件以外的,所有调用系统的都是外部的。

  • 本地符号

    • 上架去符号,去的是本地符号

  • 全局符号

    • 可以暴露给外界

4.1 桩

一块代码!

上面一段中看到的一段汇编指令

bl 0x10233e320 ; symbol stub for: NSLog

0x10233e320就是NSLog的桩

bl -> 桩 -> 通过符号表去执行代码

懒加载符号表全部都是通过桩去进行绑定的

五、总结

  • 符号绑定过程

    • 外部函数调用是执行桩里的代码

      • 通过懒加载符号表里的地址去执行

    • 懒加载符号表里面默认保存的是binder的代码

      • bingder函数在非懒加载符号的表里面(程序运行就绑定好了)

Last updated