[英]Is it possible to override main method using LD_PRELOAD?
这主要是出于好奇。 我知道如果我用我自己的库函数定义 LD_PRELOAD 我自己的库,则可以替换库函数的定义(?)。 我可以对可执行文件的主要方法执行相同的操作吗?
也就是说,在不重建可执行文件的情况下,我可以对运行时做些什么,以便调用不同的 main() 吗?
不,您不能使用LD_PRELOAD
覆盖二进制文件的main
功能。
LD_PRELOAD A whitespace-separated list of additional, user-specified, ELF shared libraries to be loaded before all others. This can be used to selectively override functions in other shared libraries. For setuid/setgid ELF binaries, only libraries in the standard search directories that are also setgid will be loaded.
LD_PRELOAD 为您提供的是注入动态链接符号的能力,这样当运行时链接器去解析它们时,它会找到您的替换而不是它通常会找到的替换。 让我们看这个例子:
主.c:
#include <stdio.h>
int main (void)
{
puts("Hello, world!");
return 0;
}
put.c
#include <stdio.h>
int puts (const char *s)
{
return printf("Hijacked puts: %s\n", s);
}
如果编译 main.c,检查它的符号:
$ gcc -o main main.c
$ objdump -t main | grep 'main\|puts'
main: file format elf64-x86-64
0000000000000000 l df *ABS* 0000000000000000 main.c
0000000000000000 F *UND* 0000000000000000 puts@@GLIBC_2.2.5
0000000000000000 F *UND* 0000000000000000 __libc_start_main@@GLIBC_2.2.5
00000000004004f4 g F .text 0000000000000015 main
请注意,此处列出的main()
函数具有已知地址,而将从 glibc 中提取的puts()
是未知的。
因此,我们可以强制运行时链接器使用我们的 puts 代替:
$ gcc -o puts.so -shared -fPIC puts.c
$ LD_PRELOAD=./puts.so ./main
Hijacked puts: Hello, world!
相反,如果我们静态链接我们的原始二进制文件:
$ gcc -o main -static main.c
$ objdump -t main | grep 'main\|puts'
main: file format elf64-x86-64
00000000006c27c0 l O .data 0000000000000888 main_arena
0000000000000000 l df *ABS* 0000000000000000 main.c
00000000006c5580 l O .bss 0000000000000008 _nl_loaded_domains
00000000004957d0 g F __libc_freeres_fn 00000000000000d6 _nl_unload_domain
000000000041bcb0 g F .text 000000000000170c _nl_load_domain
00000000006c60e0 g O .bss 0000000000000008 _nl_domain_bindings
0000000000402050 w F .text 0000000000000189 puts
...
$ LD_PRELOAD=./puts.so ./main
Hello, world!
我们的覆盖不再起作用,因为puts()
是静态链接的,这导致符号在(静态)链接时被解析。
正如@FatalError 所说,您不能使用LD_PRELOAD
在main
上直接拦截,因为此函数已链接到您的二进制文件中。 因此,这不是库拦截的目标。
但是,您可以拦截调用 main 的 libc 函数。 这是诀窍,来自https://gist.github.com/apsun/1e144bf7639b22ff0097171fa0f8c6b1 :
/*
* Hook main() using LD_PRELOAD, because why not?
* Obviously, this code is not portable. Use at your own risk.
*
* Compile using 'gcc hax.c -o hax.so -fPIC -shared -ldl'
* Then run your program as 'LD_PRELOAD=$PWD/hax.so ./a.out'
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>
/* Trampoline for the real main() */
static int (*main_orig)(int, char **, char **);
/* Our fake main() that gets called by __libc_start_main() */
int main_hook(int argc, char **argv, char **envp)
{
for (int i = 0; i < argc; ++i) {
printf("argv[%d] = %s\n", i, argv[i]);
}
printf("--- Before main ---\n");
int ret = main_orig(argc, argv, envp);
printf("--- After main ----\n");
printf("main() returned %d\n", ret);
return ret;
}
/*
* Wrapper for __libc_start_main() that replaces the real main
* function with our hooked version.
*/
int __libc_start_main(
int (*main)(int, char **, char **),
int argc,
char **argv,
int (*init)(int, char **, char **),
void (*fini)(void),
void (*rtld_fini)(void),
void *stack_end)
{
/* Save the real main function address */
main_orig = main;
/* Find the real __libc_start_main()... */
typeof(&__libc_start_main) orig = dlsym(RTLD_NEXT, "__libc_start_main");
/* ... and call it with our custom main function */
return orig(main_hook, argc, argv, init, fini, rtld_fini, stack_end);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.