一、HOOK概述

1.HOOK定义

HOOK翻译成中文为“挂钩”、“钩子”,在iOS逆向畛域中指的是扭转程序运行流程的一种技术,通过HOOK能够让他人的程序执行本人所写的代码

下列示意图就是对HOOK性能的形象诠释:

  • 注入恶意代码让用户误以为打卡胜利,理论并没有实现打卡(只批改两头流程)
  • 注入恶意代码让用户误以为网络出问题(开拓新的流程分支)

2.HOOK形式

在iOS中HOOK技术有以下几种:

  • Method Swizzling:利用OC的Runtime个性,动静扭转SEL(办法编号)IMP(办法实现)的对应关系,达到OC办法调用流程扭转的目标
  • fishhook:这是FaceBook提供的一个动静批改链接machO文件的工具,利用machO文件加载原理,通过批改懒加载和非懒加载两个表的指针达到C函数HOOK的目标
  • Cydia Substrate:原名为Mobile Substrate,它的次要作用是针对OC办法、C函数以及函数地址进行HOOK操作,且安卓也能应用
之前曾经介绍过Method Swizzling了,OC的Runtime个性让它有了“黑魔法”之称,同时也是局限性所在

三者的区别如下:

  • Method Swizzling只实用于动静的OC办法(运行时确定函数实现地址)
  • fishhook实用于动态的C办法(编译时确定函数实现地址)
  • Cydia Substrate是一种弱小的框架,只须要通过Logos语言(相似于正向开发)就能够进行Hook,实用于OC办法、C函数以及函数地址

二、fishhook

1.fishhook的应用

整个fishhook就凋谢了一个构造体rebinding和两个函数

  • rebind_symbolshook我的项目中的所有函数名称
  • rebind_symbols_image只hook某一个资源库的函数名称

应用fishhook的步骤:

  1. 导入头文件
#import "fishhook.h" 
  1. 指定替换函数——rebinding构造体对象
struct rebinding nslog;nslog.name = "NSLog";nslog.replacement = fxNSlog;nslog.replaced = (void *)&sys_nslog; 
  1. 调用rebind_symbols从新绑定符号
struct rebinding rebs[] = {nslog};rebind_symbols(rebs, 1); 

残缺代码如下:

#import "fishhook.h"@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    struct rebinding nslog;    nslog.name = "NSLog";    nslog.replacement = fxNSlog;    nslog.replaced = (void *)&sys_nslog;    struct rebinding rebs[] = {nslog};    rebind_symbols(rebs, 1);}static void(*sys_nslog)(NSString *format, ...);void fxNSlog(NSString *format, ...) {    format = [format stringByAppendingFormat:@"已hook"];    sys_nslog(format);}- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {    NSLog(@"点击屏幕");}@end 
  • 定义rebinding来指定替换的函数

    • name中指定Hook的函数名称(C字符串)
    • replacement中指定新的函数地址

      • c函数的名称就是函数指针——动态语言编译时就已确定
    • replaced中寄存原始函数地址的指针

      • 因为NSLog在Foundation库中,在每个手机的内存地址都不一样,不能通过CMD+B就能确定其内存地址
      • 这里fishhook在运行的时刻会动静获取到NSLog的地址,所以这里定义新的函数指针保留函数实现
      • 应用&批改变量外部的值
      • 应用(void *)进行类型转换
  • rebind_symbols中须要两个参数

    • 参数一是rebinding数组
    • 参数二是rebinding数组的长度

作为一个开发者,有一个学习的气氛跟一个交换圈子特地重要,这有个iOS交换群:642363427,不论你是小白还是大牛欢送入驻 ,分享BAT,阿里面试题、面试教训,探讨技术,iOS开发者一起交流学习成长!

2.fishhook的局限性

后面介绍了fishhook是用来hook C函数的,但在此前提下还是有它的局限性——无奈替换自定义函数

  • C函数是动态的,在编译时就曾经确定了函数地址(函数实现地址在MachO本地文件中)
  • 零碎C函数则是存在着动静的局部
那么为什么零碎级别的C函数就能够呢?这就要说到PIC技术了

3.PIC技术

PIC技术(Position-independent code),又叫做地位独立代码,是为了零碎C函数在编译期间可能确认一个地址的一种技术手段

  • 编译时在MachO文件中预留出一段空间——符号表(DATA段中)
  • dyld把利用加载到内存中时(此时在Load Commands中会依赖Foundation),在符号表中找到了NSLog函数,就会进行链接绑定——将FoundationNSLog的实在地址赋值到DATA段NSLog符号上
而自定义的C函数不会生成符号表,间接就是一个函数地址,所以fishhook的局限性就在于只有符号表内的符号能够hook(从新绑定符号)

4.LLDB调试

因为NSLog是个懒加载的符号,所以加了行代言代码

  1. 通过image list打印所有镜像资源——第一个就是过程的内存首地址

  2. 获取到MachO中NSLog的内存偏移量

应用计算器,内存首地址+内存偏移量=符号地址 
  1. 通过memory read 内存地址读出符号地址

因为iOS是小端模式,内存地址8位倒着读 
  1. 通过dis -s 内存地址查看汇编

此时的符号并没有绑定,因为还没有应用 
  1. 过掉断点(应用NSLog)再进行查看

此时的NSLog符号曾经被绑定 
  1. 再跳到下一步(重绑定符号)进行查看

此时的NSLog符号曾经被重绑定了 

5.fishhook原理摸索

接下来剖析下rebind_symbols

  • prepend_rebindingsrebindings数组一直增加到_rebindings_head链表的头部成为新的头节点
  • 判断链表_rebindings_head->next是否为空来判断是否是第一次调用

    • 若首次调用则应用_dyld_register_func_for_add_image进行回调监听
    • 若不是则遍历调用_rebind_symbols_for_image
  • 这个函数有个Int返回值

    • 如果重定向胜利则返回 0
    • 如果失败则返回 -1

接下来是_rebind_symbols_for_image对MachO文件的操作:依照规定计算各种表的地址和指针在表中的偏移量

最初一步,perform_rebinding_with_section依据算好的符号表地址和偏移量,找到在符号表中用于指向共享库指标函数的指针,将该指针的值(即指标函数的地址)赋值给rebinding*replaced,最初批改该指针的值为replacement(新的函数地址)

6.fishhook原理的实际——在MachO中查找函数实现

接下来就依据字符串对应在符号表中的指针,找到其在共享库的函数实现的

  1. NSLog在Lazy Symbol Pointers中位列第一个,下标为0

  2. Dynamic System Table->Indirect Symbols中的value与Lazy Symbol Pointers一一对应,此表中的Data(0xA9=169)即为另一个表的下标

  3. 拿着这个下标在Symbol Table->Symbols中找到NSLog,此时的Data对应String Table Index中的偏移值(0x0000009B)

  4. 最初在String Table中计算表头(0x000061EC)+偏移量(0x0000009B),找到NSLog的函数地址

7.fishhook利用场景

既然fishhook能够替换C函数,那么就能够替换method_exchangeImplementations等函数来避免HOOK,我的项目自身如果须要应用method_exchangeImplementations则能够应用新的函数地址来进行操作

  • 攻:能够插入新的动静库提前进行HOOK办法,此时fishhook的防护就不起作用了
  • 防:也能够提前插入动静库进行fishhook替换(逆向注入的动静库个别排在原我的项目的动静库之后),此时fishhook代码先于hook代码,所以还是fishhook还是失效的
  • 攻:釜底抽薪——间接找到fishhook的函数地址进行批改,再次运行
  • ...

写在前面

在平安攻防畛域中,hook原理起到至关重要的作用,而应用fishhook做防护尽管意义不大,然而理解fishhook原理对后续的学习还是挺有帮忙的,想理解更多逆向相干常识无妨动动小手,增加一下咱们的交换群642363427来为你的技术多添一份荣耀。