iOS 逆向开发16:HOOK原理上(HOOK 系统C函数)

iOS 逆向开发 文章汇总

目录


一、 HOOK概述

HOOK,中文译为“挂钩”或“钩子”。在iOS逆向中是指改变程序运行流程的一种技术。通过hook可以让别人的程序执行自己所写的代码。在逆向中经常使用这种技术。所以在学习过程中,我们重点要了解其原理,这样能够对恶意代码进行有效的防护。

HOOK示意图

iOS中HOOK技术的几种方式

  1. Method Swizzle 
    利用OC的Runtime特性,动态改变SEL(方法编号)和IMP(方法实现)的对应关系,达到OC方法调用流程改变的目的。主要用于OC方法。

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

  3. Cydia Substrate
    Cydia Substrate 原名为 Mobile Substrate ,它的主要作用是针对OC方法、C函数以及函数地址进行HOOK操作。当然它并不是仅仅针对iOS而设计的,安卓一样可以用。官方地址:http://www.cydiasubstrate.com/

Method Swizzle
Cydia Substrate-MobileHooker
Cydia Substrate-MobileLoader


二、fishHook的简单使用

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

获取代码:git clone https:github.com/facebook/fishhook.git

关键函数:

// 用来重 新绑定符号表的函数。使用它来交换
FISHHOOK_VISIBILITY
int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel);
参数一  存放rebinding结构体的数组(可以同时交换多个函数)
参数二  rebindings数组的长度
struct rebinding {
  const char *name;  // 需要HOOK的函数名称,字符串
  void *replacement; // 替换到哪个新的函数上(函数指针,也就是函数名称)
  void **replaced;   // 保存原始函数指针变量的指针(它是一个二级指针)
};

2.1 HOOK NSLog

#import "ViewController.h"
#import "fishhook.h"

- (void)viewDidLoad {
    [super viewDidLoad];
//------------HOOK NSLog------------

    //创建rebinding 结构体
    struct rebinding nslog;
    nslog.name = "NSLog";
    nslog.replacement = my_NSLog;
    //保存NSLog系统函数地址的指针!
    nslog.replaced = (void *)&sys_nslog;
    
    //需求:HOOK NSLog
    struct rebinding bds[] = {nslog};
    
    rebind_symbols(bds, 1);
}

//函数指针!
static void (*sys_nslog)(NSString *format, ...);

//新函数!
void my_NSLog(NSString *format, ...) {
    format = [format stringByAppendingString:@"\n我HOOK到了!"];
    //走到系统的NSLog里面去!
    sys_nslog(format);
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    NSLog(@"hello");
}

点击屏幕输出:hello
          我HOOK到了!

2.2 HOOK Func

#import "ViewController.h"
#import "fishhook.h"

void func(const char * str) {
    NSLog(@"%s",str);
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //----------HOOK  Func -------
    //创建rebinding 结构体
    struct rebinding func;
    func.name = "func";
    func.replacement = my_func;
    //保存NSLog系统函数地址的指针!
    func.replaced = (void *)&func_p;
    
    //需求:HOOK NSLog
    struct rebinding bds[] = {func};
    
    rebind_symbols(bds, 1);
}

static void (*func_p)(const char * str);

void my_func(const char * str) {
    NSLog(@"HOOK了!!");
    func_p(str);
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    func("hello");
}

点击屏幕输出:hello

从2.1和2.2可以看到fishHook只能HOOK系统的函数不能HOOK自定义的函数

因为NSLog不是本Mach-O文件中的,func是本Mach-O文件中的。编译的时候,并不知道NSLog 的真实地址!因此可以HOOK NSLog函数。


三、fishHook原理探究

How it works

dyld binds lazy and non-lazy symbols by updating pointers in particular sections of the __DATAsegment of a Mach-O binary. fishhook re-binds these symbols by determining the locations to update for each of the symbol names passed to rebind_symbols and then writing out the corresponding replacements.
For a given image, the __DATA segment may contain two sections that are relevant for dynamic symbol bindings: __nl_symbol_ptr and __la_symbol_ptr. __nl_symbol_ptr is an array of pointers to non-lazily bound data (these are bound at the time a library is loaded) and __la_symbol_ptr is an array of pointers to imported functions that is generally filled by a routine called dyld_stub_binder during the first call to that symbol (it's also possible to tell dyld to bind these at launch). In order to find the name of the symbol that corresponds to a particular location in one of these sections, we have to jump through several layers of indirection. For the two relevant sections, the section headers (struct sections from <mach-o/loader.h>) provide an offset (in the reserved1 field) into what is known as the indirect symbol table. The indirect symbol table, which is located in the __LINKEDIT segment of the binary, is just an array of indexes into the symbol table (also in __LINKEDIT) whose order is identical to that of the pointers in the non-lazy and lazy symbol sections. So, given struct section nl_symbol_ptr, the corresponding index in the symbol table of the first address in that section is indirect_symbol_table[nl_symbol_ptr->reserved1]. The symbol table itself is an array of struct nlists (see <mach-o/nlist.h>), and each nlist contains an index into the string table in __LINKEDIT which where the actual symbol names are stored. So, for each pointer __nl_symbol_ptrand __la_symbol_ptr, we are able to find the corresponding symbol and then the corresponding string to compare against the requested symbol names, and if there is a match, we replace the pointer in the section with the replacement.

3.1设置并进入第一个断点:

编译查看Mach-O文件

拿到ASLR的值:

ASLR + MachO中的 NSLog Data中的值就是当前NSLog的实际地址:
0x0000000100de0000+0x22a4 = 0x100de22a4

通过ASLR + MachO中的 NSLog Offset中的值也能看到NSLog的实际地址:

由于还未进行NSLog的符号绑定,因此此时NSLog的实际地址并不是NSLog真实函数的地址:

3.2进入第二个断点

由于是懒加载符号,所有在调用NSLog时才进行了符号绑定。

3.3进入第三个断点

经过fishhook将NSLog符号重新绑定了

C语言是静态语言,但不是所有的C函数调用都是静态的。外部的C函数调用是动态的。


四、NSLog间接符号绑定的流程

什么是符号表❓
对于函数名、变量名、方法名等编译完都会生成一张符号表,符号分为内部符号外部符号。外部符号(本Mach-O以外的符号)也称为间接符号。

符号也分为本地符号全局符号
本地符号:自己内部使用的
全局符号:外部也可以使用

// 全局符号 -- 暴露给外界使用
void test() {
}

// 本地符号 -- 作用域为本地符号
static void test1() {
    NSLog(@"test1");
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    test1();
}

编译进入可执行文件目录:
objdump --macho -t 文件名

可以看到test1是本地符号,test和main是全局符号

间接符号表


4.1 NSLog调用前进行符号绑定

添加如下代码:

运行查看汇编代码:

0x1047562d0-ASLR(0x0000000104754000)=0x22D0(NSLog的桩

因此调用NSLog时是bl到NSLog的桩(一块代码)。
桩的值为:1F2003D570E9025800021FD6 -- 即如下代码:

因此NSLog的执行流程为:bl-->桩代码(去符号表里面的绑定地址执行)-->符号表



0x0000000104756384(x16)-0x0000000104754000(ALSR)=0x2384

这里可以看到桩执行符号表中初始的地址(此时NSLog的真实地址还未绑定)

汇编继续执行236c的代码(重新运行了一次,ASLR和上面的不一样了):

经过执行dyld_stub_binder,就将NSLog的符号绑定了。

在非懒加载符号表中可以看到dyld_stub_binder的符号位置,非懒加载符号刚开始运行就绑定了(上篇文章可以看到非懒加载符号绑定的时机)。


4.2 NSLog符号绑定后的调用流程

0x0000000102890000(ALSR)+0x8000(offset) = 0x0102898000

已绑定符号

现在桩执行的就是0x0102898000指向的NSLog的真实地址了。

间接符号表的绑定流程:


NSLog间接符号表的绑定流程


总结

  • 符号绑定的过程
    • 外部函数调用是执行桩里面的代码! TEXT, stubs
      • 通过懒加载符号表里面的地址去执行!
    • 懒加载符号表里面默认保存的是寻找binder的代码
      • binder函数在非 懒加载符号表里面(程序运行就绑定好了! )
  • HOOK: 改变程序原有执行流程
    • iOS中的HOOK技术
      • OC方法: MethodSwizzle
      • 系统函数: fishhook
  • fishhook:
    • 重新绑定符号达到HOOK的目的
      • 外部符号,会在懒加载和非懒加载表中保存函数地址
      • fishhook就是找到这两张表,并且修改里面的地址做到HOOK!


参考

符号表Symbol Table
iOS-开发进阶02:链接与Symbol(上)
iOS-开发进阶03:链接与Symbol(下)

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

推荐阅读更多精彩内容