阅读 1039

iOS逆向之旅(进阶篇) — HOOK(FishHook)

官方简介

fishhook is a very simple library that enables dynamically rebinding symbols in Mach-O binaries running on iOS in the simulator and on device. This provides functionality that is similar to using DYLD_INTERPOSE on OS X. At Facebook, we've found it useful as a way to hook calls in libSystem for debugging/tracing purposes (for example, auditing for double-close issues with file descriptors).
【简而言之就是一个很轻量级的库(就两个文件),可以动态的去修改macho可执行文件的属性】 项目地址:FishHook 。

案例一【HOOK 系统函数】

  • 直接把FishHook的两个文件直接拖进项目,并引入头文件

image.png

  • 申明一个函数指针用于保存原NSLog的真实函数地址 static void(*origNSLog)(NSString *format, ...);
  • 自定义一个新的函数用于取代NSLog
void newNSLog(NSString *format, ...){
    //再调用系统的nslog
    origNSLog(@"就不打印");
}
复制代码
  • 调用fishhook的rebind_symbols实现hook
struct rebinding bind;
bind.name = "NSLog";//要HOOK系统函数的函数名称
bind.replacement = newNSLog;//新的函数去替换系统的NSLog
bind.replaced = (void *)&origNSLog;//把真正的NSLog地址保存到origNSLog
struct rebinding rebs[] = {bind};
rebind_symbols(rebs, 1);
复制代码

上面这种事传统的写法,我们也可以简写成
rebind_symbols((struct rebinding [1]){{"NSLog",newNSLog,(void*)&origNSLog}}, 1);

  • 这样就hook成功了,直接看效果

image.png
HOOK成功~~~~~~~~~

案例二【HOOK 自定义函数】

  • 在案例一的基础上继续加,首先声明一个自定义函数func
void func(){
    NSLog(@"123");
}
复制代码
  • 申明一个函数指针用于保存原func的真实函数地址 static void(*origFunc)();
  • 自定义一个新的函数用于取代func
void newFunc(){
    NSLog(@"456");
}
复制代码
  • 调用fishhook的rebind_symbols实现hook rebind_symbols((struct rebinding [1]){{"func",newFunc,(void*)&origFunc}}, 1);
  • 查看hook结果

image.png
不难看出hook失败了,hook成功的话,应该打印456才对

FishHook的原理

通过以上两个案例为何FishHook能hook系统函数,却hook不了我们自己的函数,接下来我们对其原理进行分析

科普一下

ASLR技术:是一种针对缓冲区溢出的安全保护技术,通过对堆、栈、共享库映射等线性区布局的随机化,通过增加攻击者预测目的地址的难度。对于我们APP而言,它保证每次MachO文件加载的时候是随机地址【这个我们可以通过LLDB指令的image list去查看】

image.png

根据苹果pic技术【位置代码独立】,当我们Macho需要调用系统库函数的时候,会在_DATA段中建立一个指针。DYLD【动态库加载】会进行动态的绑定,会将这个指针指向外部函数

回过头我们在分析我们之前的两个案例

根据PIC技术,我们在调用NSLog的时候,系统会现在_Data段建立一个指针,这个指针在DYLD动态加载Foundation框架时,把这个指针指向NSLog的的真实地址。
fishhook他实际就是在改这个指针,让这个指针向我们本地函数的地址。
所以fishhook的函数名字就叫rebind_symbols(重新绑定这个符号【指针】),很贴切。而我们本身自己的函数,不存在这个DYLD动态加载的过程,自然无法HOOK的了。