Hook原理--逆向开发

news2024/12/22 17:59:22

今天我们将继续讲解逆向开发工程另一个重要内容--Hook原理讲解。Hook,可以中文译为“挂钩”或者“钩子”,逆向开发中改变程序运行的一种技术。按照如下过程进行讲解

  1. Hook概述
  2. Hook技术方式
  3. fishhook原理及实例
  4. 符号表查看函数名称
  5. 总结

一、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的源码地址为GitHub - facebook/fishhook: A library that enables dynamically rebinding symbols in Mach-O binaries running on iOS.

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[1] = {nslog};
    /**
     * 存放rebinding结构体的数组
     * 数组的长度
     */
    rebind_symbols(rebs, 1);
}
//---------------------------------更改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[1] = {nslog};
    /**
     * 存放rebinding结构体的数组
     * 数组的长度
     */
    rebind_symbols(rebs, 1);
}
//---------------------------------更改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实现自己的代码。下面我们对此总结一下,写了一个本篇博客的整个过程便于大家整理,希望对大家有所帮助加深理解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1121208.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LeetCode刷题---有效的括号

这里用到了栈的思想 栈(stack)是限定仅在表尾进行插入或者删除的线性表。对于栈来说&#xff0c;表尾端称为栈顶&#xff08;top&#xff09;&#xff0c;表头端称为栈低&#xff08;bottom&#xff09;。不含元素的空表称为空栈。因为栈限定在表尾进行插入或者删除&#xff0c…

生成包含10个随机字母或数字的字符串,然后统计每个字符的出现次数

from random import choices from string import ascii_letters, digitsx .join(choices(ascii_lettersdigits, k10)) d dict() # 创建空字典 for ch in x:d[ch] d.get(ch, 0) 1 # x中有ch字符,个数1,并作为字典的值 print(x) print(d)也可以使用collections模块的defaul…

从车窗升降一探 Android 车机的重要 API:车辆属性 CarProperty

前言 前面我们介绍过 Android 车机 Automotive OS 的几块重要内容&#xff1a; 一文了解 Android 车机如何处理中控的旋钮输入从实体按键看 Android 车机的自定义事件机制深度入门 Android 车机核心 CarService 的构成和链路 本篇文章我们聚焦 Android 车机上最重要、最常用…

LeetCode--180 连续出现的数字

文章目录 1 题目描述2 结果示例3 解题思路3.1 MySQL 代码 4 知识拓展 1 题目描述 Logs表: ---------------------- | Column Name | Type | ---------------------- | id | int | | num | varchar | ----------------------在 SQL 中&#xff0c;id …

Mybatis的SqlRunner执行流程

Mybatis的SqlRunner执行流程 SqlRunner exec new SqlRunner(connection); Map<String, Object> row exec.selectOne("SELECT * FROM PRODUCT WHERE PRODUCTID ?", "FI-SW-01");connection.close();assertEquals("FI-SW-01", row.ge…

YOLOv5算法改进(19)— 手把手教你去更换NMS(DIoU-NMS/CIoU-NMS/EIoU-NMS/GIoU-NMS/SIoU-NMS)

前言:Hello大家好,我是小哥谈。YOLOv5中的NMS指非极大值抑制(Non-Maximum Suppression),它是一种用于目标检测算法中的后处理技术。在检测到多个重叠的边界框时,NMS可以帮助选择最佳的边界框。NMS的工作原理是首先根据预测边界框的置信度对它们进行排序,然后从置信度最高…

iOS逆向工程之Theos

如果你对iOS逆向工程有所了解&#xff0c;那么你对Tweak并不陌生。那么由Tweak我们又会引出Theos, 那么什么是Theos呢&#xff0c;简单一句话&#xff0c;Theos是一个越狱开发工具包&#xff0c;Theos是越狱开发工具的首先&#xff0c;因为其最大的特点就是简单。大道至简&…

python中多行注释与取消注释

在小白学习python编程的过程中&#xff0c;我们经常会发现很多同学们喜欢问的一个问题&#xff1a; 怎么多行注释呢&#xff1f; 怎么取消多行注释呢&#xff1f; 以上种种问题我相信来到这里都会得到相应答案 那我们接下来开始吧&#xff01; 文章目录 单行注释多行注释取消多…

c初阶检测题

选择题 1.局部变量的作用域是&#xff1a;&#xff08;D&#xff09; A.main函数内部 B.整个程序 C.main函数之前 D.局部变量所在的局部范围 2.字符串的结束标志是&#xff1a;&#xff08;A&#xff09; 作业内容 A.是’0’ B.是EOF C. 是’\0’ D.是空格 3.下面那个不是…

精选六个大学生可以做的兼职副业,学习赚钱两不误

在当今的社会中&#xff0c;大学生们面临着学业压力和生活开销。为了减轻家庭的负担&#xff0c;同时也为了更好地拓宽自己的视野和实践能力&#xff0c;许多大学生开始寻找一种既可以学习又能赚钱的副业。这样的选择&#xff0c;不仅可以弥补金钱上的不足&#xff0c;还可以提…

【java计算机毕设】博客管理系统 javaweb springboot vue mysql

目录 1.项目功能截图​ 2.项目简介 3.源码下载地址 1.项目功能截图 2.项目简介 博客管理系统 idea mysql5.7/8 vue html jdk1.8 系统功能&#xff1a; 前台功能&#xff1a;文章信息&#xff0c;相册信息&#xff0c;留言板&#xff0c;个人中心&#xff0c;后台管理 后…

闭包(函数)

把内部函数通过return扔出去 必要条件

靶机 DC-2

DC_2 信息搜集 存活检测 详细扫描 添加 host 后台网页扫描 网页信息搜集 主页面 找到 flag1&#xff0c;提示使用 cewl 密码生成工具 wp 登陆界面 使用 wpscan 扫描用户 wpscan --url http://dc-2/ --enumerate u 扫描出用户 tom、jerry、admin 将三个用户名写入文件中…

一文解密网络背后的秘密

一文解密网络背后的秘密 网络的发展史从键入网址到网页进行显示期间法上了什么&#xff1f;首先我们需要了解一下URLDNS解析建立连接什么是三次握手&#xff0c;可不可以两次呢&#xff1f; 本地发送请求&#xff0c;服务器处理请求断开连接 实践一下 相信大家对网络都不陌生了…

《认知觉醒:开启自我改变的原动力》

目录 第一章 大脑 — 一切问题的起源 第二章 潜意识 — 生命留给我们的彩蛋 第三章 元认知 — 人类的终极能能力 第四章 专注力——情绪和智慧的交叉地带 第五章 学习力——学习不是一味地努力 第六章 行动力 — 没有行动世界只是个概念 第七章 情绪力 — 情绪是多角度看…

【JavaScript】深入讲解浏览器渲染原理

一. 浏览器是如何渲染页面的&#xff1f; 当浏览器的网络线程收到 HTML 文档后&#xff0c;会产生一个渲染任务&#xff0c;并将其传递给渲染主线程的消息队列。 在事件循环机制的作用下&#xff0c;渲染主线程取出消息队列中的渲染任务&#xff0c;开启渲染流程。 渲染&…

Python数据分析实战-使用numpy.where方法基于条件替换某列的值(附源码和实现效果)

实现功能 在Pandas中&#xff0c;replace方法默认是基于精确匹配进行替换&#xff0c;而不是基于条件匹配。要实现基于条件的替换&#xff0c;可以使用numpy.where函数。将DataFrame中某一列的指定的两个值分别替换为0和1&#xff0c;其他值替换为2 实现代码 import pandas …

【tg】3:线程模型:4个主要线程

media :调用主线程worker therad 、network thread 是webrtc要求的module thread 也是webrtc的moudle需要的代码分布 G:\CDN\P2P-DEV\tdesktop-offical\Telegram\ThirdParty\tgcalls\tgcalls\StaticThreads.hgetThreads 触发创建线程 分别获取,看起来是分别只有1个的 Threads…

不愧是疑问解决神器(二)!你强任你强

不愧是疑问解决神器(二)&#xff01;你强任你强&#x1f44d;&#x1f44d;&#x1f44d; 第3章 代码的坏味道 1.神秘命令(Mysterious Name)? 整洁代码中最重要的一环就是有一个好名字&#xff0c;使他们能够清晰地表明自己的功能和用法。但正因为如此&#xff0c;命名就成了…

17.Tensor Product Spaces

同样&#xff0c;本文仍采用非标准 的符号。 在之前的文章里&#xff0c;已经展示了&#xff1a; 使用张量积将向量和协向量组合在一起可以为我们提供线性映射&#xff0c;这个线性映射的系数实际上只是一个数组的条目。 还展示了&#xff1a;使用张量积组合两个协向量&#x…