iOS--逆向

HOOK原理及介绍

2018-07-25  本文已影响0人  Superman168

注入小结

通过之前的学习,我们知道了利用动态库注入的两种方式:

- Framework
- Dylib

然后开始在注入的动态库中,开发你想实现的逻辑功能!

一、HOOK概述

HOOK(钩子) 其实就是改变程序执行流程的一种技术的统称!

15245516017168.jpg

iOS中HOOK技术的几种方式

1、Method Swizzle

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

2、fishhook

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

OC 是动态语言,C 则是静态语言,一经编译,所有的都可以获取到,那 Fishhook 是怎么做到的呢????

3、Cydia Substrate

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

Cydia Substrate主要由3部分组成:

fishhook 的简单使用

Github 有相关的介绍,使用方法等;

https://github.com/facebook/fishhook


- (void)viewDidLoad {
    [super viewDidLoad];
    
    // rebinding 结构体的定义
    //    struct rebinding {
    //        const char *name; // 需要 HOOK 的函数名称,字符串
    //        void *replacement; // 替换的新函数(函数指针,也就是函数名称)
    //        void **replaced; //  保存原始函数指针变量/地址的指针(它是一个二级指针!)
    //    };
    // C 语言传参是值/址传递的,把它的值/址穿过去,就可以在函数内部修改函数指针变量的值

    // 定义 rebinding 结构体
    struct rebinding nslogRebind;
    // 函数名称
    nslogRebind.name = "NSLog";
    // 新的函数指针
    nslogRebind.replacement = myLog;
    // 保存原始函数地址的变量的指针
    nslogRebind.replaced = (void *)&old_Nslog;// fishhook 将 old_Nslog 这个指针指向了 NSLog 这个函数,怎么做的呢???

    // 定义数组
    struct rebinding rebs[] = {nslogRebind};
    
    /*
     1. rebindings : 存放 rebinding 结构体的数组,可以交换 N 种方法
     2. size_t rebindings_nel : 数组的长度???
     */
    rebind_symbols(rebs, 1);
}

// 函数指针,用来保存原始的函数地址 (C 语言语法,函数指针类型变量)
static void (*old_Nslog)(NSString *format, ...);

// 自定义的 Log
void myLog (NSString *format, ...){
    format = [format stringByAppendingString:@"——> 勾上了!!!💖💖💖💖💖💖💖💖"];
    old_Nslog(format);
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    NSLog(@"点击了屏幕");
    
}

点击屏幕,可以看到控制台日志:

image.png
- (void)viewDidLoad {
    [super viewDidLoad];
    // 交换简写!
    // (struct rebinding [1]) 数组类型
    // {{"func",newFunc,(void *)&funcP}} 值为结构体,三个参数
    rebind_symbols((struct rebinding [1]){{"func",newFunc,(void *)&funcP}}, 1);
}

// 原始函数指针
static void (*funcP)(const char *);
// 新函数
void newFunc(const char *str){
    NSLog(@"———> 勾住了!!!💖💖💖💖💖💖");
    funcP(str);
}

// 原始函数
void func(const char * str){
    NSLog(@"%s",str);
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    
    func("Hello world!!!");
}
image.png

首先代码是没有问题的,为什么呢?自定义方法交换不了呢???

fishhook 原理探究

  1. Mach-O 文件是怎么加载的?
    DYLD 工具动态加载,加载完 Mach-O 文件后,加载依赖的动态库,通过 image list 可以看到加载的相关类库。

  2. ASLR 地址空间随机布局,Mach-O 文件加载的时候是随机地址的。
    系统类库,每次启动,所有地址也是随机布局。

  3. PIC 位置代码独立

???

控制器(Programmable Interrupt Controller)”的简称。

???

可编程中断控制器(Programmable Interrupt Controller),也简称为PIC,是微处器与外设之间的中断处理的桥梁,由外设发出的中断请求需要中断控制器来进行处理。

如果 Mach-o 文件内部需要调用系统的函数时:

这也就是为什么内部/自定义的函数修改不了,只能修改 Mach-O 文件外部的函数,如果是另一个动态库的或者是需要动态符号绑定的就可以,在符号表中能找到的才可以。

接下来,验证一下:

还是用 fishhook Demo 测试 1 来测试,运行,查看 Mach-o 符号表:

image.png NSLog 函数

offset :8018, NSLog文件偏移地址,也就是说懒加载这个表也就在 Mach-O 文件偏移的地址 + 函数偏移地址

动态调试:

断点位置 Mach-O 在内存中的偏移地址

Mach-O 在内存中的偏移地址也就是 Mach-O 的真实地址。

Mach-o 文件Data 段中的函数指针

计算符号表的地址

通过符号表找方法的地址,通过 dis -s 反汇编命令查看函数详情。

接下来,过段点继续查看:

前后比较

通过上面可以看出,fishhook 之所以能够 Hook C 函数,是因为根据 Mach-O 文件 特点,PIC 位置代码独立 也就造就了所谓的静态语言 C 也有动态的部分,通过 DYLD 进行动态绑定的时候,我们做了手脚,替换为我们自定义的方法。

备注: 值得注意的是,调用之前先调用一下 NSLog 函数,(符号表中应该没有 NSLog 函数的地址,但其实是有,但是可能是不正确的/固定的地址??)否则则调用 rebind_symbols 方法前不能正确的获取 函数的符号表地址(fishHook 内部会调用吧??)

现在是存放在 Mach-o 文件偏移 8018 的位置 ,而它存放的一个 8 个字节的指针,保存的就是 动态缓存区 中保存 NSLog 函数的真实的地址,那这个地址是什么时候保存进去的呢???
并不是 Mach-O 文件加载的时候保存的,而是第一次调用 该函数时保存进去的,绑定一下,由 DYLD 绑定 NSLog 这个符号指向真实的 NSLog 的地址。

未调用方法的符号表 image.png

那 fishhook 根据方法字符串名字 "NSLog" 也就是 struct rebinding const char *name 是怎么找到的呢 ???

通过符号表查看函数名称字符串

再次查看 Mach-o 文件,上面查看的懒加载表中的 NSLog 函数:

懒加载表和动态符号表

懒加载表和动态符号表是一一对应 的关系,如下:

动态符号表

动态符号表中的 Data 其实就是 方法的 Symbol Table 中的下标,转换为 10 进制 (0x88 = 136),到 Symbol Table 中查看:

Symbol Table

_ 和 .
_ 是函数的开始,. 是分隔符,\0 的转义字符。

这里还不是最终的 NSLog 字符串,可以看到 _NSLog 在 String Table 中的 Index 偏移为 0x000000AC。接下来继续查看 String Table

NSLog 字符串存放的位置

String Table 首地址0xD0A4 + 偏移地址 0xAc = 0xD150

以上过程也就是 GitHub fishhook 的说明图,如下:

查找过程

小结:

image.png
上一篇下一篇

猜你喜欢

热点阅读