如何重写__libc_start_main,使其不调用main而执行自定义函数?
完全可以实现!
当然没问题——重写__libc_start_main来替换最终调用的目标函数,正是解决你当前"main运行两次"问题的完美方案。
先给你理清楚核心逻辑:__libc_start_main是glibc中负责启动流程的关键函数,它会完成所有初始化工作(比如全局对象构造、环境变量初始化、线程设置等),最后才调用程序的main函数。我们的目标就是劫持这个函数,让它在完成初始化后调用我们的自定义函数,而非原main。
具体实现步骤(最稳妥的动态劫持方案)
推荐用LD_PRELOAD加载自定义共享库的方式,这种方法不需要修改原程序代码,兼容性也强:
编写自定义共享库代码
我们需要实现自己的__libc_start_main,在里面替换掉原main函数指针,再调用真正的glibc版本完成初始化和启动:#include <stdio.h> #include <dlfcn.h> // 自定义的替代函数,签名要和main完全一致 int my_custom_main(int argc, char** argv, char** envp) { printf("Running my custom main instead of original!\n"); // 如果需要调用原main,可以在这里保存原指针后调用 // return original_main(argc, argv, envp); return 0; } // 定义真正的__libc_start_main函数指针类型 typedef int (*libc_start_main_t)(int (*)(int, char**, char**), int, char**, void (*)(void), void (*)(void), void (*)(void), void*); libc_start_main_t real_libc_start_main; // 我们的__libc_start_main实现 int __libc_start_main(int (*original_main)(int, char**, char**), int argc, char** ubp_av, void (*init)(void), void (*fini)(void), void (*rtld_fini)(void), void* stack_end) { // 获取glibc真正的__libc_start_main函数 real_libc_start_main = (libc_start_main_t)dlsym(RTLD_NEXT, "__libc_start_main"); if (!real_libc_start_main) { fprintf(stderr, "Failed to get real __libc_start_main: %s\n", dlerror()); return 1; } // 调用真正的启动函数,但把目标替换成我们的自定义函数 return real_libc_start_main(my_custom_main, argc, ubp_av, init, fini, rtld_fini, stack_end); }编译共享库
用gcc编译成动态链接库:gcc -shared -fPIC -o libcustommain.so custom_main.c -ldl运行目标程序
通过LD_PRELOAD让程序优先加载我们的库:LD_PRELOAD=./libcustommain.so ./your_target_program
关键细节提醒
- 签名一致性:自定义函数的签名必须和标准
main完全匹配(包括第三个环境变量参数,有些系统会隐式传递,但显式声明更稳妥)。 - 避免递归调用:用
RTLD_NEXT获取原函数,确保我们的实现不会无限递归调用自己。 - 原main的调用:如果需要保留原
main的功能,可以在自定义函数中调用保存下来的original_main指针。 - 架构兼容性:不同CPU架构的
__libc_start_main签名可能有细微差异,比如参数顺序或类型,需要根据目标平台调整。
这种方案完全跳过了原main的自动调用,只会执行一次我们的自定义函数,完美解决你遇到的"main运行两次"问题。
内容的提问来源于stack exchange,提问作者Rahul Dugar
相关产品推荐
相关产品推荐

