Links
Comment on page

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

  • 首先回顾一下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

/*
* A structure representing a particular intended rebinding from a symbol
* name to its replacement
*/
struct rebinding {
const char *name;
void *replacement;
void **replaced;
};
name 需要Hook的函数名称,C字符串 replacement 新函数的地址 replaced 原始函数的指针

2.3 使用 rebind_symbols hook NSLog

通过查看接口我们需要创建一些数据。
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor blackColor];
// 目标去Hook系统的NSLog函数
struct rebinding nslog;
nslog.name = "NSLog";
nslog.replacement = hook_NSLog;
// 保存NSLog函数的指针
nslog.replaced = (void *)&sys_NSLog;
struct rebinding bds[] = {nslog};
rebind_symbols(bds, 1);
}
/// 旧函数的指针
static void (*sys_NSLog)(NSString *format, ...);
// 新函数
void hook_NSLog(NSString *format, ...) {
format = [format stringByAppendingString:@"\n🌈"];
// 再调用系统的
sys_NSLog(format);
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSLog(@"RyukieLog");
}
输出结果:
2021-05-05 15:51:44.230666+0800 Hook[1650:239418] RyukieLog
🌈
2021-05-05 15:51:44.430579+0800 Hook[1650:239418] RyukieLog
🌈
2021-05-05 15:51:44.679392+0800 Hook[1650:239418] RyukieLog
🌈
Hook成功!

2.4 试一试hook C函数?

定义一个这样的函数
void logFun(const char * str) {
NSLog(@"%s", str);
}
修改rebinding信息
struct rebinding nslog;
nslog.name = "logFun";
nslog.replacement = new_logfun;
nslog.replaced = (void *)&old_logfun;
static void(*old_logfun)(const char * str);
void new_logfun(const char * str) {
str = "🌈";
// 再调用旧的
old_logfun(str);
}
发现并没有成功!应为这个是通过地址直接访问的。

三、重绑定符号

一个问题:编译的时候,NSLog的真实地址知道么?不知道。
在MachO加载进内存时,dyld会先加载依赖的系统库进共享缓存。
NSLog在Foundation框架中,加载后dyld会将NSLog的真实地址告诉MachO。
验证一下fishhook的实现:
hook
在hook前后分别下断点,打开汇编断点。
第一个断点:
-> 0x10233d234 <+188>: bl 0x10233e320 ; symbol stub for: NSLog
下一步:
-> 0x104cae320 <+0>: nop
0x104cae324 <+4>: ldr x16, #0x5cdc ; (void *)0x0000000104cae464
0x104cae328 <+8>: br x16
第二个断点:
-> 0x10233d254 <+220>: bl 0x10233e320 ; symbol stub for: NSLog
下一步:
-> 0x104cae320 <+0>: nop
0x104cae324 <+4>: ldr x16, #0x5cdc ; (void *)0x0000000104cad44c: hook_NSLog at /Users/RyukieW/RyukieSamaProject/Study/逆向/Code/Hook/Hook/Hook/ViewController.m:75
0x104cae328 <+8>: br x16
分析:
bl 0x10233e320 ; symbol stub for: NSLog
这一段是到0x10233e320中去寻找符号绑定的地址
第一次的第二步找到了系统原本函数的地址
第二次走到第二步后发现已经是hookNSLog了

四、符号绑定的过程

  • 间接符号表
    • MachO文件以外的,所有调用系统的都是外部的。
  • 本地符号
    • 上架去符号,去的是本地符号
  • 全局符号
    • 可以暴露给外界

4.1 桩

一块代码!
上面一段中看到的一段汇编指令
bl 0x10233e320 ; symbol stub for: NSLog
0x10233e320就是NSLog的桩
bl -> 桩 -> 通过符号表去执行代码
懒加载符号表全部都是通过桩去进行绑定的

五、总结

  • 符号绑定过程
    • 外部函数调用是执行桩里的代码
      • 通过懒加载符号表里的地址去执行
    • 懒加载符号表里面默认保存的是binder的代码
      • bingder函数在非懒加载符号的表里面(程序运行就绑定好了)