x86架构下如何Hook运行时未知数量的函数
问题
运行时获取同一进程内的一组函数地址,需要在这些函数被调用时记录对应的函数地址。
已尝试方案的局限
单个函数Hook可以用subhook这类库实现,伪代码如下:
create_hook(function_to_be_hooked, intermediate); intermediate(args...) { log("function with address %p got called", &function_to_be_hooked); remove_hook(function_to_be_hooked); ret = function_to_be_hooked(args...); create_hook(function_to_be_hooked, intermediate); return ret; }
但这个方案无法直接扩展到运行时数量未知的多函数场景:如果用同一个中间函数Hook多个目标函数,无法区分到底是哪个函数被触发调用。当前环境为Linux下的C/C++,可选Hook库为subhook和funchook,二者均不支持直接关联Hook上下文。
解决方案
1. 为每个目标函数生成独立中间包装函数
通过C/C++宏为每个目标函数创建专属的中间函数,每个中间函数硬编码对应的目标函数地址,调用时直接记录该地址。
示例代码(基于subhook):
#include <subhook.h> #include <stdio.h> // 宏定义:为指定函数地址生成专属Hook逻辑 #define CREATE_TARGET_HOOK(func_addr) \ static void* intermediate_##func_addr(void* args) { \ printf("Called function at address: %p\n", (void*)func_addr); \ subhook_remove((subhook_t)hook_handle_##func_addr); \ void* ret = ((void*(*)(void*))func_addr)(args); \ subhook_install((subhook_t)hook_handle_##func_addr); \ return ret; \ } \ subhook_t hook_handle_##func_addr = subhook_create((void*)func_addr, intermediate_##func_addr, 0); // 编译时已知的目标函数地址示例 void* known_target_funcs[] = {0x12345678, 0x87654321}; int main() { // 为每个编译时已知的函数创建Hook CREATE_TARGET_HOOK(0x12345678); CREATE_TARGET_HOOK(0x87654321); subhook_install(hook_handle_0x12345678); subhook_install(hook_handle_0x87654321); // 后续逻辑... return 0; }
局限:仅适用于编译时已知目标函数地址的场景,运行时动态获取的地址无法用此方法。
2. 汇编跳转桩+上下文存储(适配动态地址)
对于运行时动态获取的函数地址,需要手动构造跳转桩,把目标函数地址作为上下文传递给统一的中间处理函数:
- 为每个目标函数分配可执行内存作为跳转桩,在跳转桩中把目标函数地址存入线程局部存储(避免多线程冲突)。
- 跳转桩跳转到统一的中间处理函数,处理函数从线程局部存储中取出目标地址记录日志,再调用原始函数并恢复Hook。
示例代码(Linux x86_64平台):
#include <subhook.h> #include <stdio.h> #include <stdlib.h> #include <sys/mman.h> #include <stdint.h> // 线程局部存储:保存当前触发Hook的目标函数地址 __thread void* current_target = NULL; // 线程局部存储:保存当前Hook的句柄,用于临时移除Hook __thread subhook_t current_hook_handle = NULL; // 统一的Hook处理函数 void* hook_handler(void* args) { printf("Called function at address: %p\n", current_target); // 临时移除Hook,调用原始函数 subhook_remove(current_hook_handle); void* ret = ((void*(*)(void*))current_target)(args); subhook_install(current_hook_handle); return ret; } // 为目标函数创建跳转桩并关联Hook void* setup_dynamic_hook(void* target_func, subhook_t* out_hook_handle) { // 分配可执行内存页 void* trampoline = mmap(NULL, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (trampoline == MAP_FAILED) return NULL; // x86_64汇编逻辑:将target_func存入current_target,然后跳转到hook_handler unsigned char* asm_ptr = (unsigned char*)trampoline; // mov QWORD PTR [rip + offset], target_func *asm_ptr++ = 0x48; *asm_ptr++ = 0xC7; *asm_ptr++ = 0x05; *(uintptr_t*)asm_ptr = (uintptr_t)¤t_target - (uintptr_t)(asm_ptr + 4); asm_ptr += 4; *(uintptr_t*)asm_ptr = (uintptr_t)target_func; asm_ptr += 8; // mov QWORD PTR [rip + offset], hook_handle *asm_ptr++ = 0x48; *asm_ptr++ = 0xC7; *asm_ptr++ = 0x05; *(uintptr_t*)asm_ptr = (uintptr_t)¤t_hook_handle - (uintptr_t)(asm_ptr + 4); asm_ptr += 4; *(uintptr_t*)asm_ptr = (uintptr_t)*out_hook_handle; asm_ptr += 8; // jmp hook_handler *asm_ptr++ = 0xE9; *(uintptr_t*)asm_ptr = (uintptr_t)hook_handler - (uintptr_t)(asm_ptr + 4); asm_ptr += 4; // 创建Hook:将目标函数重定向到跳转桩 *out_hook_handle = subhook_create(target_func, trampoline, 0); return trampoline; } int main() { // 运行时动态获取的函数地址示例 void* dynamic_targets[] = {0x11223344, 0x55667788}; subhook_t hook_handles[2]; void* trampolines[2]; // 为每个动态地址设置Hook for (size_t i = 0; i < 2; i++) { trampolines[i] = setup_dynamic_hook(dynamic_targets[i], &hook_handles[i]); if (trampolines[i]) { subhook_install(hook_handles[i]); } } // 后续逻辑... // 清理资源 for (size_t i = 0; i < 2; i++) { if (hook_handles[i]) subhook_remove(hook_handles[i]); if (trampolines[i]) munmap(trampolines[i], 4096); } return 0; }
注意事项:
- 汇编代码需适配目标平台(x86_64与x86差异较大)。
- 必须确保跳转桩内存页拥有可执行权限(通过
mmap的PROT_EXEC参数设置)。 - 多线程场景下必须用线程局部存储(
__thread)保存上下文,避免不同线程的Hook上下文混乱。
3. funchook适配方案
funchook的回调签名固定,但可以用线程局部存储传递上下文,逻辑和方法2一致:为每个目标函数创建跳转桩,传递目标地址到线程局部变量,再进入统一处理函数。
总结
- 编译时已知函数地址:用宏生成独立中间函数,实现简单且高效。
- 运行时动态获取地址:通过汇编跳转桩+线程局部存储传递上下文,实现多Hook的区分。
内容的提问来源于stack exchange,提问作者Phastasm
相关产品推荐
相关产品推荐

