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的源码地址为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实现自己的代码。下面我们对此总结一下,写了一个本篇博客的整个过程便于大家整理,希望对大家有所帮助加深理解。
相关文章:

Hook原理--逆向开发
今天我们将继续讲解逆向开发工程另一个重要内容--Hook原理讲解。Hook,可以中文译为“挂钩”或者“钩子”,逆向开发中改变程序运行的一种技术。按照如下过程进行讲解 Hook概述Hook技术方式fishhook原理及实例符号表查看函数名称总结 一、Hook概述 在逆…...

做数据可视化,谨记三大要点
数据可视化报表就是“一图胜千言”的最佳例子。数据可视化,也就是将数据图形化、图表化,以良好的视觉效果呈现数据,达到发现、分析、预测、监控、决策等目的。要想做出一份优秀的数据可视化报表,那就要在做报表时谨记三大要点&…...
软件设计原则-接口隔离原则讲解以及代码示例
接口隔离原则 一,介绍 1.前言 接口隔离原则(Interface Segregation Principle,ISP)是面向对象设计中的一个原则,提倡使用多个专门的接口,而不使用单一的大接口。它最早由Robert C. Martin在其《敏捷软件…...

yolov8x-p2 实现 tensorrt 推理
简述 在最开始的yolov8提供的不同size的版本,包括n、s、m、l、x(模型规模依次增大,通过depth, width, max_channels控制大小),这些都是通过P3、P4和P5提取图片特征; 正常的yolov8对象检测模型输出层是P3、…...
Type Script的变量类型
Typescript 的重要特性之一就是数据有类型了。 常见的类型如:字符串、数值、布尔等都有了明确的定义。 变量声明的格式 let 变量名:类型 初始值;字符型 let str:string "abc";数值型 数值型也支持不同的进制,用前缀区分 支持 整…...

系统架构师备考倒计时13天(每日知识点)
1. 数据仓库四大特点 面向主题的。操作型数据库的数据组织面向事务处理任务,各个业务系统之间各自分离,而数据仓库中的数据是按照一定的主题域进行组织的。集成的。数据仓库中的数据是在对原有分散的数据库数据抽取、清理的基础上经过系统加工、汇总和整…...
20 | Spring Data JPA 中文文档
Spring Data JPA 中文文档 1. 前言 Spring Data JPA 为 Jakarta Persistence API(JPA)提供 repository 支持。它简化了需要访问JPA数据源的应用程序的开发。 1.1. 项目元数据 版本控制: https://github.com/spring-projects/spring-data-jpaBug跟踪:…...

【AOA-VMD-LSTM分类故障诊断】基于阿基米德算法AOA优化变分模态分解VMD的长短期记忆网络LSTM分类算法(Matlab代码)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
K8s:Pod 中 command、args 与 Dockerfile 中 CMD、 ENTRYPOINT 的对应关系
写在前面 前几天被问到,这里整理笔记之前也没怎么注意这个问题理解不足小伙伴帮忙指正 曾以为老去是很遥远的事,突然发现年轻是很久以前的事了。时光好不经用,抬眼已是半生,所谓的中年危机,真正让人焦虑的不是孤单、不…...

Visual Studio Code (VS Code)安装教程
Visual Studio Code(简称“VS Code”)。 1.下载安装包 VS Code的官网: Visual Studio Code - Code Editing. Redefined 首先提及一下,vscode是不需要破解操作的; 第一步,看好版本,由于我的系…...
技巧 | 如何解决 zsh: permission denied 问题 | Mac
技巧 | 如何解决 zsh: permission denied 问题 | Mac 问题描述 在 macOS 系统终端执行 sh 程序脚本时,抛出异常 zsh: permission denied 原因分析 用户没有权限,所以才出现了这个错误,所以只需要用 chmod 修改一下权限就可以了 解决方法…...

【JavaEE】线程安全的集合类 -- 多线程篇(9)
线程安全的集合类 多线程环境使用 ArrayList多线程环境使用队列多线程环境使用哈希表 多线程环境使用 ArrayList 自己使用同步机制 (synchronized 或者 ReentrantLock)Collections.synchronizedList(new ArrayList); synchronizedList 是标准库提供的一个基于 synchronized 进…...

【MySQL架构篇】MySQL字符集、大小写规范及默认数据库
文章目录 1. 字符集与字符集比较规则2. 大小写规范3. 默认数据库4. 与文件系统相关 1. 字符集与字符集比较规则 MySQL有4个级别的字符集和比较规则,分别是 服务器级别数据库级别表级别列级别 当创建对应表或列未指定字符集时,默认会取其上一级别的字符…...

【Linux系统编程】命令模式2
目录 一,Linux下的初阶认识 1,管道 2,时间戳 二,Liunx系统命令操作 1,date时间指令 2,cal日历指令 3,which和find查找指令 3-1,which指令: 3-2,find…...

【Leetcode】【中等】1726.同积元组
力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台备战技术面试?力扣提供海量技术面试资源,帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/tuple-with-same-product/ 给你…...

Git教程
文章目录 Git 介绍GIt历史Git 安装环境配置工作区、缓存区和仓库区(版本库)工作区(工作目录)暂存区仓库区git工作目录下文件的装填 Git 生成公钥及添加到gitlab或Gerrit上Git常用命令git stautsgit statu -sgit addgit commitgit reset1. git reset --ha…...

使用序列化技术保存数据 改进 IO流完成项目实战水果库存系统
上一节内容是 使用IO流完成项目实战水果库存系统https://blog.csdn.net/m0_65152767/article/details/133999972?spm1001.2014.3001.5501 package com.csdn.fruit.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java…...
0基础学习PyFlink——使用PyFlink的Sink将结果输出到外部系统
在《0基础学习PyFlink——使用PyFlink的SQL进行字数统计》一文中,我们直接执行了Select查询操作,在终端中直接看到了查询结果。 select word, count(1) as count from source group by word; ------------------------------------------------------ |…...

会声会影2024旗舰版详细功能介绍
随着网络视频的蓬勃发展,越来越多的人开始涉足视频剪辑领域,毕竟技多不压身嘛。在众多剪辑软件中,剪映和会声会影是备受新手青睐的两种。那么,会声会影和剪映哪个好呢?在它们之间,哪一个更适合初学者呢接&a…...
QtCreator 查看类帮助文档,快捷键操作:按两次F1 全屏帮助,Esc取消全屏
如何查看类帮助文档 选择类,按F1查看类帮助文档。 示例: #include <QLabel> // 将光标放在QLabel上,按F1右侧弹出的类帮助手册可视宽度很小,如果按两次 F1 键,帮助文档将会以全屏模式显示,以便更清…...

stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...

css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...

React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...