iOS逆向 HOOK原理之fishhook

一、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交流群:642 363 427,不管你是小白还是大牛欢迎入驻 ,分享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打印所有镜像资源——第一个就是进程的内存首地址
  1. 获取到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
  1. Dynamic System Table->Indirect Symbols中的value与Lazy Symbol Pointers一一对应,此表中的Data(0xA9=169)即为另一个表的下标
  1. 拿着这个下标在Symbol Table->Symbols中找到NSLog,此时的Data对应String Table Index中的偏移值(0x0000009B)
  1. 最后在String Table中计算表头(0x000061EC)+偏移量(0x0000009B),找到NSLog的函数地址

7.fishhook应用场景

既然fishhook可以交换C函数,那么就可以交换method_exchangeImplementations等函数来防止HOOK,项目本身如果需要使用method_exchangeImplementations则可以使用新的函数地址来进行操作

  • 攻:可以插入新的动态库提前进行HOOK方法,此时fishhook的防护就不起作用了
  • 防:也可以提前插入动态库进行fishhook交换(逆向注入的动态库一般排在原项目的动态库之后),此时fishhook代码先于hook代码,所以还是fishhook还是生效的
  • 攻:釜底抽薪——直接找到fishhook的函数地址进行修改,再次运行
  • ...

写在后面

在安全攻防领域中,hook原理起到至关重要的作用,而使用fishhook做防护虽然意义不大,但是了解fishhook原理对后续的学习还是挺有帮助的,想了解更多逆向相关知识不妨动动小手,点赞我来为你的技术多添一份光彩。

原文:GitHub

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容