libc
中的 system
命令的内存地址,我可以在 gdb
中轻松找到它,但是如果我不想将程序带入调试器怎么办?
这个地址会在每次运行时改变吗?是否有其他静态分析工具可以让我查看库或函数在运行时加载到此程序的内存空间的位置?
我想在程序外部获取这些信息(例如使用类似于 objdump
的实用程序来收集信息)。libc
中的 system
命令的内存地址,我可以在 gdb
中轻松找到它,但是如果我不想将程序带入调试器怎么办?
这个地址会在每次运行时改变吗?是否有其他静态分析工具可以让我查看库或函数在运行时加载到此程序的内存空间的位置?
我想在程序外部获取这些信息(例如使用类似于 objdump
的实用程序来收集信息)。库被ld.so
(动态链接器或运行时链接器,Linux中的ld-linux.so.2
或ld-linux.so.*
;glibc的一部分)加载。所有动态链接的ELF二进制文件都将其声明为“解释器”(INTERP;.interp
节)。因此,当您启动程序时,Linux将启动一个ld.so
(加载到内存并跳转到其入口点),然后ld.so
将程序加载到内存中,准备并运行它。您也可以使用以下命令启动动态程序
/lib/ld-linux.so.2 ./your_program your_prog_params
ld.so
会实际打开和映射所有所需的ELF文件,包括您的程序和所有所需库的ELF文件。此外,它还填充GOT和PLT表并进行重定位解析(在许多情况下使用间接调用将库中函数的地址写入调用站点)。
通过ldd
实用程序,可以获得某个库的典型加载地址。它实际上是一个bash脚本,该脚本设置了ld.so的调试环境变量(实际上是glibc的rtld的LD_TRACE_LOADED_OBJECTS=1
),然后启动程序。您甚至可以自己完成此操作,无需使用脚本,例如使用bash轻松更改单个运行的环境变量:
LD_TRACE_LOADED_OBJECTS=1 /bin/echo
ld.so
将看到这个变量,并解析所有需要的库并打印它们的加载地址。但是,如果设置了此变量,ld.so
实际上不会启动程序(对于程序或库的静态构造函数不确定)。如果ASLR特性被禁用,则大多数时候加载地址将相同。现代Linux通常启用ASLR,因此要禁用它,请使用echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
。
您可以使用binutils中的nm
实用程序在libc.so
内找到system
函数的偏移量。我认为,您应该使用nm -D /lib/libc.so
或objdump -T /lib/libc.so
并搜索输出。
gold
链接器和 binutils ld 链接器 ELF 部分作者的博客 www.airs.com/blog/archives/41 - osgx如果您只想获取函数的地址而不是硬编码名称,可以使用dlopen()
加载主程序:
void *self = dlopen(NULL, RTLD_NOW);
dlsym(self, "system"); // returns the pointer to the system() function
如果您只想在编译时知道函数的名称并获取其地址,可以简单地使用void *addr = &system;
nm
命令用于 libc.so
,可以显示 libc.so
中 system
符号的位置。然而,如果启用了 ASLR,每次运行程序时,libc.so
加载的地址以及最终的 system
地址都会随机变化。即使没有启用 ASLR,您也需要确定 libc.so
加载的地址并将 system
的地址偏移该数量。
我建议您的环境中应该有LD_LIBRARY_PATH路径。这个路径定义了共享库的位置。您可能还需要查看/etc/ld.so.conf文件。 请查看此帖子http://www.google.com/url?sa=t&source=web&cd=3&ved=0CCQQFjAC&url=http%3A%2F%2Fubuntuforums.org%2Fshowthread.php%3Ft%3D324660&ei=KqJpTey7JofEsAPE9_imBA&usg=AFQjCNEIbGGrTHp4fufRuj4Yfc58RTHcag&sig2=_9tdlyadMbPc-FcOdCko-w
prelink
,它会显著改变顺序。 - Ben Voigt