Linux下如何正确hook malloc函数?现有方案仍存递归问题
如何安全Hook malloc避免无限递归
你提到的两种Hook malloc的方案都会触发无限递归,核心原因是:第一次调用dlsym(RTLD_NEXT, "malloc")时,dlsym内部会调用malloc,而此时自定义的malloc已经被动态链接器优先加载,会再次进入自定义的malloc函数,由于real_malloc还未初始化,会反复调用dlsym导致无限递归。
以下是几种可行的解决方法:
方案1:利用构造函数提前获取真实malloc地址
通过GCC的__attribute__((constructor))属性,在程序进入main前自动执行初始化逻辑,提前获取libc的真实malloc地址。此时构造函数的执行时机早于任何用户代码的malloc调用,且dlsym在此阶段调用不会触发自定义的malloc hook,能安全完成初始化。
#include <stdio.h> #include <dlfcn.h> #include <stdlib.h> static void* (*real_malloc)(size_t) = NULL; // 构造函数,程序启动时自动执行 __attribute__((constructor)) void init_real_malloc() { real_malloc = dlsym(RTLD_NEXT, "malloc"); if (!real_malloc) { fprintf(stderr, "Failed to resolve real malloc: %s\n", dlerror()); _exit(EXIT_FAILURE); } } void* malloc(size_t size) { printf("malloc(%zu) bytes requested\n", size); return real_malloc(size); }
方案2:直接加载libc库获取malloc地址(底层方案)
跳过RTLD_NEXT,直接打开系统的libc动态库,从中获取malloc的符号地址。这种方式完全绕开了动态链接器的符号优先级,避免dlsym触发自定义malloc。
注意:不同系统的libc库路径不同,Linux下通常是libc.so.6,macOS下是libSystem.B.dylib,需要根据目标系统调整。
#include <stdio.h> #include <dlfcn.h> #include <stdlib.h> static void* (*real_malloc)(size_t) = NULL; __attribute__((constructor)) void init_real_malloc() { // Linux下的libc路径,macOS替换为"libSystem.B.dylib" void* libc_handle = dlopen("libc.so.6", RTLD_NOW); if (!libc_handle) { fprintf(stderr, "Failed to open libc: %s\n", dlerror()); _exit(EXIT_FAILURE); } real_malloc = dlsym(libc_handle, "malloc"); if (!real_malloc) { fprintf(stderr, "Failed to resolve real malloc: %s\n", dlerror()); dlclose(libc_handle); _exit(EXIT_FAILURE); } dlclose(libc_handle); } void* malloc(size_t size) { printf("malloc(%zu) bytes requested\n", size); return real_malloc(size); }
方案3:使用GNU malloc钩子(已废弃,仅作参考)
GNU libc曾提供__malloc_hook接口用于注册malloc回调,无需替换malloc符号即可实现Hook。但该接口已被标记为废弃,未来可能被移除,仅作兼容性参考:
#include <stdio.h> #include <malloc.h> #include <stdlib.h> static void* (*old_malloc_hook)(size_t, const void*); static void* my_malloc(size_t size, const void* caller) { // 临时禁用钩子,避免调用真实malloc时递归触发 __malloc_hook = old_malloc_hook; printf("malloc(%zu) called from %p\n", size, caller); void* ptr = malloc(size); // 恢复钩子 __malloc_hook = my_malloc; return ptr; } __attribute__((constructor)) void init_hook() { old_malloc_hook = __malloc_hook; __malloc_hook = my_malloc; }
内容的提问来源于stack exchange,提问作者bobeff
相关产品推荐
相关产品推荐

