Inline HOOK API 改进版(hot-patching)

安卓添加vendor hook 在include/trace/hooks/目录下,创建头文件xxx.h。定义hook函数。 阅读详情

Inline HOOK API 改进版(hot-patching)

分类: C/C++语言 C/C++ inline汇编语言 汇编语言   6182人阅读  评论(13)  收藏  举报

记得在之前写过一篇hook api的文章(C/C++ HOOK API(原理深入剖析之-LoadLibraryA)),那篇文章主要原理是构造一块代码字节,将LoadLibraryA函数的前面16个字节给修改,然后跳转到自定义的函数中。要调用正常的函数时,又将其unHook,这样一来再一次调用中,有一次unhook和一次hook,操作显得过于频繁。而且hook与unhook当时设计成了thiscall,因此维护传递this的寄存器(通常是ecx)就成了必然,再加上参数的传递,__Inline_Hook_Func函数的逻辑就显得有点复杂和臃肿。

 

就以上情况,本文打算较之前的逻辑做个改进,抛弃掉this和参数的维护,利用windows为多数API预留的前五个字节的nop空间和mov edi, edi占用的两个字节来实现inline hook。即所谓的hot-patching技术,运行时修改函数的行为,同时不破坏函数的主体逻辑,因此免去了hook与unhook不断切换,在线程安全上也有很好的效果。

 

本文还是以LoadLibraryA函数为例,先看LoadLibraryA的反汇编:

7602285F  nop              
76022860  nop              
76022861  nop              
76022862  nop              
76022863  nop              
76022864  mov         edi,edi 
76022866  push        ebp  
76022867  mov         ebp,esp 
76022869  cmp         dword ptr [ebp+8],0 
7602286D  push        ebx  
7602286E  push        esi  
7602286F  push        edi  
76022870  je          7602288A 
76022872  push        760228A0h 
76022877  push        dword ptr [ebp+8] 
7602287A  call        dword ptr ds:[75FD12E4h] 
76022880  pop         ecx  
76022881  pop         ecx  
76022882  test        eax,eax 
76022884  je          7603F39F 
7602288A  push        0    
7602288C  push        0    
7602288E  push        dword ptr [ebp+8] 
76022891  call        76022859 
76022896  pop         edi  
76022897  pop         esi  
76022898  pop         ebx  
76022899  pop         ebp  
7602289A  ret         4  

 

如上,前面红色的部分即是可以灵活操作的部分,mov edi,edi两个字节可以替换成一个short jmp,5个nop字节可以替换成一个长跳。

蓝色的0x76022864地址是LoadLibraryA的入口,如果将这里改成short jmp后,要调用正常的LoadLibraryA,则只需要在此基础上加2个字节的偏移进行call即可。清楚了原理,先动手吧,用C++实现,先写一个类。

  1. class InlineHookHolder  
  2. {  
  3. public:  
  4.     class _ReadWriteVPHolder  
  5.     {  
  6.     public:  
  7.         _ReadWriteVPHolder( void* addr, DWORD size ) : pAddr( addr ), dwSize( size )  
  8.         {   
  9.             VirtualProtect( pAddr, dwSize, PAGE_EXECUTE_READWRITE, &dwFlag );   
  10.         }  
  11.   
  12.         ~_ReadWriteVPHolder( void )  
  13.         {  
  14.             VirtualProtect( pAddr, dwSize, dwFlag, &dwFlag );  
  15.         }  
  16.   
  17.     private:  
  18.         void* pAddr;  
  19.         DWORD dwFlag;  
  20.         DWORD dwSize;  
  21.     };  
  22.   
  23.     InlineHookHolder( int dst_jmp_func, int src_hook_func ) :  
  24.         pSrcFunc( ( BYTE* )src_hook_func - 5 )  
  25.     {   
  26.         // raii vp Holder  
  27.         _ReadWriteVPHolder holder( pSrcFunc, 7 );  
  28.   
  29.         // jmp offset, contain 5 byte of itself  
  30.         ( int& )pSrcFunc[1] = ( int )dst_jmp_func - ( int )pSrcFunc - 5;  
  31.         pSrcFunc[ 0 ]       = 0xE9;     // far jmp  
  32.   
  33.         // mov edi, edi  
  34.         pSrcFunc[ 5 ]       = 0xEB;     // short jmp  
  35.         pSrcFunc[ 6 ]       = 0xF9;     // short jmp offset: -7  
  36.     }  
  37.   
  38.     ~InlineHookHolder( void )   
  39.     {  
  40.         // raii vp holder  
  41.         _ReadWriteVPHolder holder( pSrcFunc, 7 );  
  42.   
  43.         // 5 nop  
  44.         memset( pSrcFunc, 0x90, 5 );  
  45.   
  46.         // unhook mov edi, edi  
  47.         pSrcFunc[ 5 ] = 0x8B;  
  48.         pSrcFunc[ 6 ] = 0xFF;  
  49.     }  
  50.   
  51. private:  
  52.     BYTE* pSrcFunc;  
  53. };  

 

这个InlineHookHolder构造时,便将目标函数进行hook操作,这个操作将mov edi,edi替换成jmp XX,这里是相对偏移,偏移量为7字节(5个nop字节加上本身2个字节),所以有:
pSrcFunc[ 5 ]       = 0xEB;     // short jmp
pSrcFunc[ 6 ]       = 0xF9;     // short jmp offset: -7

0xEB即是short jmp的机器码,0xF9即偏移,这里是负数,向前偏移7个字节。

 

至于5个nop即替换成了jmp 0x???????。因此有:

( int& )pSrcFunc[1] = ( int )dst_jmp_func - ( int )pSrcFunc - 5; // 跳转的偏移,目标地址与当前地址的差值+jmp本身的5个字节
pSrcFunc[ 0 ]       = 0xE9;   // 长jmp 的机器码

 

在构造函数修改之后,析构函数负责unhook,在其间的过程中都不需要操作。

写好了类,然后再写跳转到的自定义函数,代码如下:

 

  1. typedef WINBASEAPI HMODULE ( WINAPI *PLOADLIBA )( LPCSTR lpFileName );  
  2. typedef WINBASEAPI HMODULE ( WINAPI *PLOADLIBW )( LPCWSTR lpFileName );  
  3.   
  4. #define LOADER_CAST( T, ptr ) reinterpret_cast< T >( ( ( int )ptr ) + 2 );  
  5. #define WINAPI_FUNC( _ret, _name ) _ret WINAPI _name  
  6. #define DECLARE_HOOK_HOLDER( _T, holder, jmp_, src_ ) /  
  7.         _T jmp_##holder( ( int )jmp_, ( int )src_ );  
  8.   
  9. WINAPI_FUNC( HMODULE, MyLoadLibraryA )( LPCSTR lpFileName )  
  10. {  
  11.     if ( lpFileName == NULL )  
  12.         return NULL;  
  13.   
  14.     PLOADLIBA pLoader = LOADER_CAST( PLOADLIBA, LoadLibraryA );  
  15.     HMODULE   hMod    = pLoader( lpFileName );  
  16.     // code....  
  17.     return hMod;  
  18. }  

 

如上面代码,LOADER_CAST宏用于将API的入口地址加上2,避免又跳转到自定义hook函数里面了。

 

由于LoadLibraryA是__stdcall(WINAPI宏),会在内部ret时保持堆栈平衡,因此我们自定义的函数也保持这个规则,不然会导致堆栈不平衡。WINAPI_FUNC宏就是为了遵循这个规则而定义的,免得粗心忘了加__stdcall了。

 

DECLARE_HOOK_HOLDER宏是声明定义一个InlineHookHolder对象,将原函数和目标函数传入构造函数进行hook操作。我们可以将这个对象声明成全局的,这样在程序退出时调用析构进行unhook,_ReadWriteVPHolder类也是为了RAII的机制。

 

最后调用代码可以简单如下:

  1. DECLARE_HOOK_HOLDER( InlineHookHolder, _inline_hook_a, MyLoadLibraryA, LoadLibraryA );  
  2. int main( void )  
  3. {  
  4.     LoadLibraryA( "d3d9.dll" ); // 假如load这个dll  
  5.     return 0;  
  6. }  

 

当然在MyLoadLibraryA里就可以做一些我们想做的事情了,比如检测你加载的DLL是否合法等,这对于比较简单的游戏反外挂上有一定的作用。本文就只抛砖引玉介绍下原理吧。

 

 

与之前的版本比较,这种方法只能应用于预留了5个nop和mov edi,edi这7个字节的API函数,不建议强制使用这种方式,视情况而定。再者,在本文中没有涉及手工编写内嵌汇编代码,逻辑简单且更清晰,在效率上也较高一些,安全性方面也要好一些。不过之前的方法对于追究堆栈调用模型很有好处。

 

本文原理比较简单,就先介绍到此,欢迎大牛拍砖。

iOS应用加固与混淆实战:从原理到工程实践 在移动应用开发领域,代码保护是保障应用安全与商业利益的核心环节。其基本原理在于通过技术手段增加逆向工程的难度,从而保护知识产权、防止核心逻辑泄露与接口滥用。从技术价值看,有效的代码保护不仅能防范抄袭和收入损失,更是应对安全合规要求的关键。具体到iOS平台,这通常通过一套组合技术实现,包括代码混淆、运行时保护及环境检测等。代码混淆作为静态保护的核心,通过符号重命名、控制流平坦化和字符串加密,使反编译后的代码难以理解;而加固则提供了动态防御,如反调试、反注入和完整性校验,共同构成纵深防御体系。在实际应用场景中, 阅读详情

相关推荐

微软揭秘 Windows Server Hotpatching 工作原理,带你了解编程中的奥秘

它允许在不重启服务器的情况下应用关键系统更新和补丁,从而最大程度地减少系统的停机时间。通过理解和应用 Windows Server Hotpatching 技术,开发人员可以在不中断系统运行的情况下应用关键的系统更新和补丁,提高服务器的可用性和稳定性。这项技术在生产环境中尤为重要,因为它可以减少系统的停机时间,提高服务的连续性。它使用一种称为“代码补丁”或“代码挂钩”的技术,将新的代码片段插入到系统中。最后,我们将新函数的地址写入原始函数的位置,从而完成函数的更新。将新函数的代码复制到分配的内存空间中。

HackWhisper的博客 249

GKI改造原则、机制和方法

Google在android11-5.4分支上开始要求所有下游厂商使用Generic Kernel Image(GKI),需要将SoC和device相关的代码从核心内核剥离到可加载模块中...

内核工匠 3万+

WRF后处理总结:wrf-python与NCL在WRF后处理中的基本应用——变量提取、计算与可视化

判断需要提取的变量与诊断量确定后,使用getvar函数进行提取。可使用ncdump-h命令查看wrfout中的变量,wrf中的诊断量分类也可从官方文档处查阅。判断绘图类型所需的可视化绘图类型,决定了你在WRF后处理中的计算步骤。1D点线图:ll_to_xy interpline2D填色图:interplevel3D剖面图:vinterp vertcross绘图、美化色标、XY轴、标签的设置等等。

weixin_43750300的博客 1万+

Hook :HOOK API 原理深入剖析2 - Inline(hot-patching)

记得在之前写过一篇hook api的文章(C/C++ HOOK API(原理深入剖析之-LoadLibraryA)),那篇文章主要原理是构造一块代码字节,将LoadLibraryA函数的前面16个字节给修改,然后跳转到自定义的函数中。要调用正常的函数时,又将其unHook,这样一来再一次调用中,有一次unhook和一次hook,操作显得过于频繁。而且hook与unhook当时设计成了thiscal

it技术学习 1051

头歌 操作系统 课堂练习2.1:外部中断 第2关:第一次时钟中断

将答案0x796c输入到workspace/mushixun/恢复点的地址.txt中的括号里即可,随后使用kill命令防止对第三关的环境造成影响。

Yinfrey的博客 6096

有关SPSS中Fisher精确检验无法进行的解决方法(由于无法打开临时文件,因此无法进行计算)

最近在帮一个四年生完成她的毕业论文,在用SPSS进行R×C表检验的时候,发现Fisher精确检验的结果无法显示,提示为“由于无法打开临时文件,因此无法进行计算”,大概像下图一样。 (这图是从网上找的) 然...

chuyang37的博客 3万+

apache模块开发之挂钩、可选函数和过滤器

一.挂钩使用   1.自定义挂钩的使用步骤: 1、声明 #define AP_DECLARE_HOOK(ret,name,args) /     APR_DECLARE_EXTERNAL_HOOK(ap,AP,ret,name,args) 即,使用宏AP_DECLARE_HOOK或APR_DECLARE_EXTERNAL_HOOK来声明一个挂钩,该声明宏展开后是五个函数:挂钩的执行函数

Guo_guo 4522

2026.2.23:AgentScope框架实战<一>:安装并使用agentscope

本文介绍了AgentScope框架的安装与使用实践。通过PyPI安装agentscope[full]后,演示了如何创建ReActAgent代理:1)配置DashScope聊天模型;2)注册自定义工具函数(查询位置和天气);3)初始化代理并处理用户请求。示例展示了代理如何响应复合查询(如同时获取北京位置和天气信息),输出结果显示代理成功执行了工具调用并返回结构化响应。该框架支持Python 3.13环境,提供内存管理、工具集成等功能,适用于构建智能代理系统。

拥抱具身智能,昇腾Ascend C 511

Apache中的挂钩剖析

5.5 挂钩(HOOK)5.5.1 为什么引入挂钩在Apache1.3版本中,对HTTP 请求的处理包括若干个固定阶段,比如地址转换阶段、身份确认阶段、身份认证阶段、权限确认阶段、MIME类型识别阶段等等,这也意味着Apache1.3 中的挂钩数目是有限的,固定的。这个反映在模块结构中就是针对每个HOOK都对应一个函数指针。比如如果需要检查用户的身份是否合法则只需要调用 ap_chec

BLOG@JayXie.COM 482

华为OD机试新系统真题【迷宫相遇】

华为OD机试 新系统真题【迷宫相遇】,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。华为OD机试真题【迷宫相遇】多语言题解。

qq_45776114的博客 770

ADB 安装教程:如何在 Windows、 Linux 上安装 Android Debug Bridge

本文介绍了在Windows和Linux系统上安装ADB(Android调试桥)的方法。对于Windows系统:1)从官网下载ADB工具并解压;2)通过命令提示符验证安装;3)配置环境变量以实现全局使用;4)再次验证全局ADB功能。Linux系统可通过包管理器直接安装(如Ubuntu使用apt,Fedora使用dnf),安装后同样需验证版本信息确认成功。两种系统安装完成后,都能通过"adb version"命令检查安装状态。

qq_53545309的博客 444

蓝桥杯单片机NE555频率测量:从测频法到测周法的实战指南

在嵌入式系统与单片机开发中,频率测量是一项基础且关键的技术,它直接关联到信号处理、传感器数据采集和系统时序控制等核心功能。其原理主要基于定时器/计数器对周期性信号的边沿进行捕获与计量,通过统计固定时间内的脉冲数(测频法)或测量单个脉冲的周期时间(测周法)来计算频率值。这项技术的工程价值在于实现了对模拟信号的数字化精确感知,是连接物理世界与数字系统的桥梁。典型的应用场景包括转速监测、音频信号分析、通信解码以及各类传感器(如编码器、NE555振荡器)的信号读取。本文聚焦于蓝桥杯竞赛中的经典NE555模块,深入探

weixin_34185512的博客 288

26届数字IC秋招笔试面试全攻略-ASIC设计流程全解析

本文系统介绍了ASIC芯片设计的全流程。前端设计包括规格制定、架构设计、RTL编码和功能验证;后端设计完成物理实现,涵盖布局规划、时钟树综合、布线和物理验证等步骤;Tapeout阶段完成制造数据准备和交付。文章详细说明了各阶段的关键任务、验证方法和设计指标,并列举了典型工具链,为ASIC设计提供了全面的流程指导。通过严格的检查清单和验证步骤,确保芯片设计符合制造要求和性能目标。

2301_79143213的博客 365

linux kernel hook

其时是用的linux一个热修补技术。调用内核api 把旧函数前修改成跳转,跳转到新的函数里去执行。这个api就是stop_machine 但是传的不是函数而是一个包好的结构体stop_machine https://www.ibm.com/developerworks/cn/aix/library/au-spunix_ksplice/源码地址:https://github.com/haidrago...

weixin_33929309的博客 501

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

Apache内容生成器 (1)

在HTTP请求处理的关键步骤中 Apache对不同类型的文件的处理是不一样的。比如对于所有.html文件,通常的处理方法就是直接将该文件返回给客户端,而对于各种脚本文件比如.pl、.asp或者CGI则需要经过预处理生成html之后才能返回给客户端。不同类型的脚本的处理又由不同的应用程序处理。 为了能够对各种类型的文件方便的进行处理,Apache中引入了处理器的概念。 13.1 内容处理器概述

ssdbbg的专栏 1726

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

内存泄漏专题(7)hook之宏定义

在此之前,我们封装一个链表,用来存储每次申请内存的地址以及申请内存的大小,在每次申请内存的时候,向链表添加一条数据,每次释放的时候,将对应的记录删除掉,那么,当程序结束,如果链表还有数据,那就是没有释放的泄露部分的内存。我们注意在第1行包含了头文件,并在第4行和14行分别调用了mcheck的接口,这样的话,就可以检测出这个过程中出现的内存泄露问题,以上代码运行会产生一个名为。它告诉我们第6,11,13行分别出现了内存泄露,大小是多少,调用的那么函数申请的内存,还是比较详细的。函数时,先调用我们自己定义的。

禹鼎侯的博客 830

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

CppCon 2025 学习:CTwik : General Purpose Hot Patcher For C++ A tool for hot patching changed C++ co

x86-64 长跳转需要 14~16 字节需要保证覆盖完整指令边界防止半条指令被破坏这是一个:基于依赖图 + 动态库 + 机器码跳转覆盖的C++ 运行时热更新系统Hot Patching 机制的执行流程在主程序(Main Executable,可能是静态链接)中,原始函数位于地址0x1433保存旧栈帧基址,RSP-=8,[RSP]=old RBP建立新栈帧 RBP=RSP保存被调用者需要保护的寄存器 rbx为局部变量分配 56 字节栈空间,RSP=RSP-56。

虾球 761

【Inline Hook基础篇】挂钩系统API

对于怎么挂钩系统API的实现,网上对此的解释有很多也很详细。这边暂不进行长篇大论,就简单的说明下原理:修改系统API的前几个字节,并写入 JMP 0x15a123 汇编指令,实现调用系统API自动跳转到我们的API的过程。 对于API HOOK的实现,现成的有MHOOK、DETOUR等类似的框架实现。既然我们要清晰的认识具体怎么实现,那么我们就自己编写实现方式,不采用第三方库。其实也很简单,没啥...

Fzuim的博客 1739

Vue3 学习笔记 —— Hooks、全局函数和变量、Vue3 插件

Vue3 学习笔记 —— Hooks、全局函数和变量、Vue3 插件

Lyrelion的博客 5796

Inline HOOK

本文主要介绍了如何使用Inline HOOK来替换不在IAT表当中的函数

Tandy12356_的博客 6280

Hook攻防之InlineHook

Inline Hook,又称为超级Hook,是一种强大而又灵活的Hook技术。Inline Hook的主要思想就是直接修改目标函数的代码,通常是在目标函数的开头插入一个跳转指令(jmp)。这个跳转指令会将程序的执行流跳转到我们自定义的函数中。在我们的自定义函数中,我们可以执行任意的代码,然后再跳回目标函数的剩余部分。这样,我们就可以在不改变目标函数原有逻辑的基础上,添加自己的功能。

xf555er的博客 3029

Ring3下Inline Hook API

用CreateFile为例子,讲解一下Ring3下的Inline Hook API,基本原理很简单 1、获取CreateFile函数的地址 2、读取CreateFile函数的前8个字节 3、将CreateFile函数的前8个字节,修改成mov eax,我的函数地址  jmp eax 4、进入我的函数地址之后,记得恢复CreateFile函数原来的8个字节,不然没法正常使用CreateFil

125096 524

inlinehook 看这一篇

inlinehook 代码实战

4421
上一篇: 函数开始处的MOV EDI, EDI的作用收藏
下一篇: mov edi,edi和Hot Patching详解
linuxheik
博客等级 码龄15年 865粉丝 135原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值