我的情况是,我只得到一个动态链接的、非剥离的 ELF 可执行文件,其中包含一些我想在自己的二进制文件中调用的函数(文本段中的符号)。
让我们考虑一个简化的例子。假设我们有一个 ELF 可执行文件
executable
(由 gcc -o executable executable.c
编译而来)和一个主 C 文件 main.c
。
// executable.c
// gcc -o executable executable.c
// We will only have the `executable` and the source is unavailable
foobar() { return 87; }
main() { return 0; }
通过
nm executable
,我们可以验证它是否具有以下符号:
0000000000003e00 d _DYNAMIC
0000000000003fc0 d _GLOBAL_OFFSET_TABLE_
0000000000002000 R _IO_stdin_used
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
00000000000020e8 r __FRAME_END__
0000000000002004 r __GNU_EH_FRAME_HDR
0000000000004010 D __TMC_END__
000000000000038c r __abi_tag
0000000000004010 B __bss_start
w __cxa_finalize@GLIBC_2.2.5
0000000000004000 D __data_start
00000000000010e0 t __do_global_dtors_aux
0000000000003df8 d __do_global_dtors_aux_fini_array_entry
0000000000004008 D __dso_handle
0000000000003df0 d __frame_dummy_init_array_entry
w __gmon_start__
U __libc_start_main@GLIBC_2.34
0000000000004010 D _edata
0000000000004018 B _end
0000000000001148 T _fini
0000000000001000 T _init
0000000000001040 T _start
0000000000004010 b completed.0
0000000000004000 W data_start
0000000000001070 t deregister_tm_clones
0000000000001129 T foobar
0000000000001120 t frame_dummy
0000000000001138 T main
00000000000010a0 t register_tm_clones
// main.c
#include <stdio.h>
extern foobar();
main()
{
printf("%d\n", foobar());
return 0;
}
显然,如果我像这样直接链接它
gcc -o main main.c executable
,最终会得到_init
、_start
、main
等的多个定义。使用较新版本的编译器/链接器,它甚至说: cannot use executable file 'executable' as input to a link
。
那么我们能否将 C 文件编译为链接可执行文件中特定符号的二进制文件(或库)?或者是否存在一些方法可以从可执行文件中提取这些符号?
谢谢!
通过
,我们可以验证它是否具有以下符号:nm executable
您还应该运行
nm -D executable
来查看哪些(如果有)已定义的符号被导出用于动态链接。
如果
foobar
is 已导出,则您的任务很简单:创建一个调用 foobar
的共享库并使用 LD_PRELOAD
来“注入”它。
但有可能
foobar
not 导出,在这种情况下调用它很困难:您必须使用即时编译有效地生成对 foobar
的调用。
如果您只需要解决方案适用于特定的可执行文件(IOW,如果您提前知道要调用的函数的地址),并且该可执行文件不是 PIE,则此任务会更容易。