Hook原理--逆向开发
今天我们将继续讲解逆向开发工程另一个重要内容--Hook原理讲解。Hook,可以中文译为“挂钩”或者“钩子”,逆向开发中改变程序运行的一种技术。按照如下过程进行讲解
- Hook概述
- Hook技术方式
- fishhook原理及实例
- 符号表查看函数名称
- 总结
一、Hook概述
在逆向开发中是指改变程序运行流程的技术,通过Hook可以让自己的代码运行在别人的程序中。需要了解其Hook原理,这样就能够对恶意代码攻击进行有效的防护。
二、Hook技术方式
2.1 Method Swizzle方式
Method Swizzle 上次已经讲到,是利用OC的Runtime的特性,去动态改变SEL(方法编号)与IMP(方法实现)的对应关系,达到OC方法调用流程更改的目的。也是主要用于OC方法。
2.2 Cydia Substrate方式
Cydia Substrate 原名叫做Mobile SubStrate,主要作用为针对C函数,OC函数以及函数的地址进行Hook操作。并且有个很大的优势,Cydia Substrate 并不是仅仅是针对iOS设计,Andriod一样也可以使用。
2.2.1
Cydia Substrate定义了一系列的函数和宏,底层调用了objc的runtime和fishHook来替代目标函数或者系统方法。
其中有两个函数
- MSHookMessageEx主要用于OC方法
void MSHookMessageEx(Class class, SEL selector, IMP replacement, IMP result)
- MSHookFunction主要用于C++和C函数
void MSHookFunction(voidfunction,void* replacement,void** p_original)
2.2.2 MobileLoader
MobileLoader主要用于加载第三方dylib运行的应用程序中。启动时MobileLoader会根据指定的第三方动态库加载进去,第三方动态库也是我们写的破解程序。
2.2.3 safe mode
破解程序的本质在于dylib,寄生于别人程序进程中。但是系统进程一旦出现错误,可能会导致整个进程崩溃,也可能会导致iOS程序崩溃。在Cydia Substrate 中引入了安全模式,如果一旦错误,三方的dylib会被禁用,便于查错和修复。
2.3 fishHook
fishHook是Facebook提供一种动态修改链接Mach-O文件的工具。此利用Mach-O文件加载原理,通过修改非懒加载和懒加载两个表的指针达到C函数的Hook的目的。
今天我们主要讲解第三种方式fishHook达到更改程序的目的。
三、fishhook原理及实例
3.1 概述
fishhook的源码地址为https://github.com/facebook/fishhook
fishhook的主要方法有两个还有一个结构体
查看代码结构为,将红色圈起来部分移入到代码中,即可使用fishhook来hook代码。
3.2 实例
3.2.1 Demo1实例1
// rebinding 结构体的定义
// struct rebinding {
// const char *name; // 需要 HOOK 的函数名称,字符串
// void *replacement; // 替换的新函数(函数指针,也就是函数名称)
// void **replaced; // 保存原始函数指针变量/地址的指针(它是一个二级指针!)
// };
// C 语言传参是值/址传递的,把它的值/址穿过去,就可以在函数内部修改函数指针变量的值 - (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"123");
//rebinding结构体
struct rebinding nslog;
nslog.name = "NSLog";// 函数名称
nslog.replacement = myNslog; // 新的函数指针
nslog.replaced = (void *)&sys_nslog;// 保存原始函数地址的变量的指针
//rebinding结构体数组
struct rebinding rebs[] = {nslog};
/**
* 存放rebinding结构体的数组
* 数组的长度
*/
rebind_symbols(rebs, );
}
//---------------------------------更改NSLog-----------
//函数指针,用来保存原始的函数地址 (C 语言语法,函数指针类型变量)
static void(*sys_nslog)(NSString * format,...);
//定义一个新的函数
void myNslog(NSString * format,...){
format = [format stringByAppendingString:@"勾上了!\n"];
//调用原始的
sys_nslog(format);
} -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
NSLog(@"点击了屏幕!!");
}
上面的代码运行结果如下:
3.2.2 Demo2实例2
void func(const char * str){
NSLog(@"%s",str);
} - (void)viewDidLoad {
[super viewDidLoad];
//rebinding结构体
struct rebinding nslog;
nslog.name = "func";
nslog.replacement = new_func;
nslog.replaced = (void *)&old_func;
//rebinding结构体数组
struct rebinding rebs[] = {nslog};
/**
* 存放rebinding结构体的数组
* 数组的长度
*/
rebind_symbols(rebs, );
}
//---------------------------------更改NSLog-----------
//函数指针
static void(*old_func)(const char * str);
//定义一个新的函数
void new_func(const char * str){
NSLog(@"%s + 1",str);
} -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
func("哈哈");
}
运行结果如下:
从上面可以看出自定义的交换方法为什么交换不了呢?首先可以肯定的是代码是OK的,下面我们讲解原理,为什么自定义的方法不行呢?
3.3 原理探究
Mach-O文件是如何加载的?
Dyld工具动态加载,加载MachO文件完成后,开始加载依赖的动态库,也就是通过上篇博客的image List 可看到相关的类库。
PIC(Promrammable Interrupt Controller)位置代码独立,由外设发出中断请求需要中断控制器来处理。
Mach-O文件内部调用系统函数时:
- Mach-O _data段建立了一个指针(也就是符号,实现指向内部的函数调用,指向了外部的函数地址),指向了外部函数(dyld),可读可写,当Mach-O被加载进去,就会指向所指的函数。
- Dyld会动态的绑定,将Mach-O中的data 段中指针指向了外部的函数,也是Dyld为什么叫做动态绑定的原因。
这也回答了上面的问题,为什么内部/自定义的函数不能修改,只能修改Mach-O文件的外部函数,如果是另外一个动态库或者需要动态符号绑定的就可以(符号表中能找到才可以实现)
下面我们是真实查看内容,通过实例
利用第一个Demo来测试,运行起来,然后查看可执行文件,通过MachoView工具
从图2看出offset偏移地址为3028,也就是NSLog函数文件的偏移地址,懒加载此表时在Mach-O文件偏移地址+函数偏移的地址。
下面以Demo1查看,在Demo1打断点,查看Mach-O函数偏移地址,通过指令image list 第一个就是Mach-O内容和地址(本人上篇博客地址即可)
Mach-O在内存的偏移地址也就是Mach-O的真实地址,发现为 0x000000010a9c5000
通过上面红色加重算法,计算Mach-O文件Data段的函数指针
发现执行完只有就会被绑定。NSLog函数文件就会被绑定。
下面再看一下,对于屏幕点击的,hook如下
前提是我们去除ViewDidLoad方法里面的NSLog(@“123”)这句代码,运行代码,最后将断点断在touchesBegan里面,此时开始看地址和内容
截图的前两次打印是程序运行时,但是未曾点击touchesBegan,后两次是点击屏幕时断点进入到了里面,再看内容,打印的对象是NSLog还是myNslog,通过上面发现是myNslog,说明Hook成功。
通过上面可看出,fishhook能够Hook c函数,是因为Mach-O文件特点,PIC位置代码独立造就了静态语言C也有动态的部分,之后通过Dyld进行动态绑定的时机,在这其中我们就可以做手脚,替换自定义的方法。
fishhook是根据方法字符串的名字“NSLog”,它是怎么找到的呢?下面将讲解利用符号表查看函数名称字符串。
四、符号表查看函数名称
再次查看Mach-O文件,查看懒加载表中的NSLog函数
懒加载表是和动态符号表是一一对应关系,通过上面发现NSLog函数时第一个,而对应的Dynamic Symbol table也是第一个,打开Dynamic Symbol table
查看Dynamic Symbol Table 第一个也是NSLog,查看Data值为7A,对应的十进制为122,然后到Symbols Table里面查看122,如下:
查看Symbols Table的data值为0000009B,然后在String Table Index去看函数偏移值为0000009B的内容,如下:
为什么选择00004F94查看NSLog呢,我们从上面得知Symbols Table的data值为0000009B,然后加上String Table的函数第一个地址为00004F04,然后将0000009B + 00004F04 = 0X4F9F,最后看00004F94里面包含了0X4F9F,蓝色内容看出是NSLog内容,也就是找到啦。完美!!!
以上过程可以在fishhook中github上有说明图:
上面的说明图也就是通过符号表查看函数名称以及反过来也可以逆查的过程。配上说明图,方便大家熟悉流程。
五、总结
上面讲述了Hook的几种技术方式以及fishhook的原理探究,以及如何让别人的app实现自己的代码。下面我们对此总结一下,写了一个本篇博客的整个过程便于大家整理,希望对大家有所帮助加深理解。
Hook原理--逆向开发的更多相关文章
- MachO文件详解--逆向开发
今天是逆向开发的第5天内容--MachO文件(Mac 和 iOS 平台可执行的文件),在逆向开发中是比较重要的,下面我们着重讲解一下MachO文件的基本内容和使用. 一.MachO概述 1. 概述 M ...
- iOS逆向开发(1):基础工具 | ssh | scp | socat
小白:小程,我一直想问,什么是逆向来着?是逆向行驶吗? 小程:理解为逆向行驶也没错.一般的项目是从无到有,而逆向是从已有的状态入手,分析出已有的流程与结构的手段. iOS上的逆向开发,是一件有趣的事情 ...
- x86平台inline hook原理和实现
概念 inline hook是一种通过修改机器码的方式来实现hook的技术. 原理 对于正常执行的程序,它的函数调用流程大概是这样的: 0x1000地址的call指令执行后跳转到0x3000地址处执行 ...
- 2021年正确的Android逆向开发学习之路
2021年正确的Android逆向开发学习之路 说明 文章首发于HURUWO的博客小站,本平台做同步备份发布.如有浏览或访问异常或者相关疑问可前往原博客下评论浏览. 原文链接 2021年正确的Andr ...
- Android C/C++层hook和java层hook原理以及比较
作者:Denny Qiao(乔喜铭),云智慧/架构师. 云智慧集团成立于2009年,是全栈智能业务运维解决方案服务商.经过多年自主研发,公司形成了从IT运维.电力运维到IoT运维的产业布局,覆盖ITO ...
- iOS逆向开发(8):微信自动添加好友
这一次,小程演示怎么让一个APP自动地运行,从而代替手工的操作.同样以"微信"以例,实现在一个微信群里面,对所有的成员,自动地一个一个地发出添加好友的请求. 知识点还是之前介绍的东 ...
- 一文看懂汽车电子ECU bootloader工作原理及开发要点
随着半导体技术的不断进步(按照摩尔定律),MCU内部集成的逻辑功能外设越来越多,存储器也越来越大.消费者对于汽车节能(经济和法规对排放的要求)型.舒适性.互联性.安全性(功能安全和信息安全)的要求越来 ...
- atitit.基于 Commons CLI 的命令行原理与 开发
atitit.基于 Commons CLI 的命令行原理与 开发 1. 命令行支持的格式有以下几种: 1 2. json化,map化的命令行参数内部表示 1 3. Ati cli 2 4. CLI库 ...
- FPGA组成、工作原理和开发流程
FPGA组成.工作原理和开发流程 原创 2012年01月07日 09:11:52 9402 0 4 ********************************LoongEmbedded***** ...
随机推荐
- jmeter-使用代理服务器录制脚本
使用代理服务器录制脚本 1.测试计划-添加线程组 2.工作台添加HTTP代理服务器(路径:工作台-右键添加-非测试元件-HTTP代理服务器) 3.端口号一般由8888改为其他的 4.打开chrome的 ...
- Gitlab CI 集成 Kubernetes 集群部署 Spring Boot 项目
在上一篇博客中,我们成功将 Gitlab CI 部署到了 Docker 中去,成功创建了 Gitlab CI Pipline 来执行 CI/CD 任务.那么这篇文章我们更进一步,将它集成到 K8s 集 ...
- angular 子路由跳转出现Navigation triggered outside Angular zone, did you forget to call ‘ngZone.run() 的问题修复
angular 路由功能非常强大,同时angular的路由也非常脆弱,非常容易出现错误. 那么在我们遇到异常时,首先要做的是什么? 第一步:检查代码,对比官方文档,发现代码中不一致的地方进行改正. 第 ...
- 基于 HTML5 + Canvas 实现的 PID 可视化系统
前言 随着工业物联网和互联网技术的普及和发展,人工填料的方式已经逐渐被机械设备取代.工业厂商减小误操作.提升设备安全以及追求高效率等制造特点对设备的要求愈加高标准.严要求.同时机械生产以后还需遵从整个 ...
- StackView在Android的应用
StackView是AdapterViewAnimator的子类,它用于显示Adapter提供的一系列View.StackView将会以“堆叠”的方式来显示多个列表项.为了控制StackView现实的 ...
- Codeforces Round #595 (Div. 3)D1D2 贪心 STL
一道用STL的贪心,正好可以用来学习使用STL库 题目大意:给出n条可以内含,相交,分离的线段,如果重叠条数超过k次则为坏点,n,k<2e5 所以我们贪心的想我们从左往右遍历,如果重合部分条数超 ...
- eclipse断点的使用---for循环举例
在很多时候,我们在学习过程中,不知道代码具体的实现过程,很好奇这个变量的值怎么就发生的变化,用好断点的使用,帮助我们更好的理解. 例子:10以内的奇数之和 package day03; public ...
- 小白学 Python(21):生成器基础
人生苦短,我选Python 前文传送门 小白学 Python(1):开篇 小白学 Python(2):基础数据类型(上) 小白学 Python(3):基础数据类型(下) 小白学 Python(4):变 ...
- Android音频开发(1):基础知识
Android音频开发(1):基础知识 导读 人的说话频率基本上为300Hz~3400Hz,但是人耳朵听觉频率基本上为20Hz~20000Hz. 对于人类的语音信号而言,实际处理一般经过以下步骤: 人 ...
- python模块——psutil
import psutil 内存 mem = psutil.virtual_memory() print(mem) >>> svmem(total=17048064000, avai ...