依旧是复习过去学过的知识。本文的Hook技术对应内容请看侧边目录。一、内联Hook(InlineHook)(1)inline hook 是什么当我们想要拦截现有运行中的进程内某个现有的汇编函数体,最常用的办法就是 inline hook。它可以在权限允许内,通过修改程序运行中的内存代码段汇编,以达到拦截任何函数的目的,包括系统api(只限非内核态的函数体,要hook内核函数需要进内核态),以及程序内部现有的任何函数体。比如想拦截系统APICreateFileW的调用,修改原调用参数并继续执行CreateFileW原函数逻辑,获得返回值,或者直接拦截返回NULL失败,或者拦截程序本身代码汇编的函数体,用 inline hook都可以做到。具体步骤如下:备份原始指令:在目标函数入口处,保存前几个字节(通常是 5 到 12 字节)。写入跳转指令:将目标函数的开头替换为一条跳转指令(通常是 JMP)。执行自己的逻辑:程序运行到目标函数时,会直接跳到你写的“钩子函数”里。跳回原函数:如果你还想让原程序继续运行,就在执行完你的逻辑后,先执行备份的原始指令,再跳回目标函数的后续位置。(2)示例代码解析
x86示例代码如下,需要注意的是编译器如果发现 OriginalHelloWorldFunction 内容很短,且在同一个文件里,它在编译 main 函数时,将不会去执行 CALL 指令,而是直接把那句 printf 的内容复制到了 main 里面。所以需要在函数定义前加上 __declspec(noinline),通知编译器不要内联这个函数。#include <windows.h>
#include <stdio.h>
// --- 被 HOOK 的目标函数 ---
__declspec(noinline) void OriginalHelloWorldFunction() {
printf("[执行] 原始的 Hello World 函数\n");
// --- 我们自定义的钩子函数 (Hook 函数) ---
void MyCustomHelloWorldFunction()
printf("[拦截] 成功进入了我们的钩子函数!\n");
// --- 核心:执行 Inline Hook 的逻辑 ---
void SetupInlineHookJmp32()
// 1. 定义跳转机器码结构 (E9 + 4字节偏移量)
// 机器码格式:E9 XX XX XX XX
// 2. 计算跳转偏移量 (公式:目标地址 - 原地址 - 指令长度)
// 注意:跳转是相对于当前指令下一条地址开始计算的
DWORD RelativeOffset = (DWORD)MyCustomHelloWorldFunction - (DWORD)OriginalHelloWorldFunction - 5;
// 将计算好的 4 字节偏移填充到机器码中
*(DWORD*)(JumpInstruction + 1) = RelativeOffset;
// 3. 修改目标内存属性为“可读写执行”,否则修改代码会引发崩溃 (Access Violation)
DWORD OldMemoryProtection;
VirtualProtect(OriginalHelloWorldFunction, 5, PAGE_EXECUTE_READWRITE, &OldMemoryProtection);
// 4. 正式写入机器码 (覆盖原函数开头的 5 个字节)
memcpy(OriginalHelloWorldFunction, JumpInstruction, 5);
// 5. 恢复内存原始保护属性 (养成良好的安全习惯)
VirtualProtect(OriginalHelloWorldFunction, 5, OldMemoryProtection, &OldMemoryProtection);
printf("[系统] Inline Hook 已部署完毕。\n");
int main()
printf("====== 32位 Inline Hook 测试开始 ======\n\n");
// 第一步:测试 Hook 之前的函数行为
printf("1. 尝试直接调用函数(此时未 Hook):\n");
// 注意:这里如果先调用,可能会被编译器内联,测试建议直接开始 Hook
OriginalHelloWorldFunction();
// 第二步:部署 Hook
SetupInlineHookJmp32();
// 第三步:再次调用原函数名,观察输出
printf("\n2. 再次尝试调用原函数:\n");
OriginalHelloWorldFunction();
printf("\n====== 测试结束 ======\n");
getchar(); // 暂停程序查看结果
return 0;
}x64示例代码:#include <windows.h>
#include <stdio.h>
// 告诉编译器不要内联这些函数
__declspec(noinline) void OriginalHelloWorldFunction()
printf("[执行] 原始的 x64 Hello World 函数\n");
void MyCustomHelloWorldFunction()
printf("[拦截] 成功进入了 x64 钩子函数!\n");
void SetupInlineHookX64()
// 1. 定义 12 字节的绝对跳转指令
// 48 B8 [8字节地址] FF E0 (jmp rax)
BYTE JumpInstruction[12] = {
0x48, 0xB8, 0, 0, 0, 0, 0, 0, 0, 0, // mov rax, <address>
0xFF, 0xE0 // jmp rax
// 2. 将 64 位绝对地址写入机器码
void* TargetAddress = &MyCustomHelloWorldFunction;
memcpy(&JumpInstruction[2], &TargetAddress, 8);
// 3. 修改内存属性(注意:这次需要 12 字节空间)
DWORD OldMemoryProtect
...(已截断)
---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-290783.htm
[原创]游戏逆向中常用的Hook技术
436 浏览
2 回复
tql
jiayou