我的问题如下:
程序中指定的共享对象的地址是什么时候?链接期间?数据加载中?如果我想在我的程序中找到system
内libc
命令的内存地址,我可以在gdb
中轻松找到它,但是如果我不想带来编程到调试器?
此地址是否可以从运行更改为运行?是否还有其他静态分析工具可以查看运行时将库或函数加载到该程序的内存空间的位置?
编辑:我想在程序之外使用此信息(即使用objdump
之类的实用程序来收集信息)
答案 0 :(得分:62)
库由ld.so
加载(动态链接器或运行时链接器,即rtld,ld-linux.so.2
或ld-linux.so.*
,以防Linux; glibc的一部分)。它被声明为所有动态链接的ELF二进制文件的“解释器”(INTERP; .interp
部分)。因此,当您启动程序时,Linux将启动ld.so
(加载到内存并跳转到其入口点),然后ld.so
将程序加载到内存中,准备然后运行它。您也可以使用
/lib/ld-linux.so.2 ./your_program your_prog_params
ld.so
执行所有需要的ELF文件的实际open
和mmap
,程序的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 feature,则加载地址大多数时间都相同。现代Linux通常启用了ASLR,因此要禁用它,请使用echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
。
您可以在binutils中使用system
实用程序找到libc.so
内nm
函数的偏移量。我想,你应该使用nm -D /lib/libc.so
或objdump -T /lib/libc.so
和grep输出。
答案 1 :(得分:12)
答案 2 :(得分:8)
nm
上使用的libc.so
命令会显示system
中libc.so
符号的位置。但是,如果启用了ASLR,则会加载地址libc.so
,因此每次运行程序时system
的最终地址都会随机变化。即使没有ASLR,您也需要确定加载地址libc.so
并将system
的地址抵消该数量。
答案 3 :(得分:6)
如果您只想要一个函数的地址而不是硬编码名称,那么您可以dlopen()
主程序:
void *self = dlopen(NULL, RTLD_NOW);
dlsym(self, "system"); // returns the pointer to the system() function
如果您只想在编译时知道名称的函数的地址,只需使用void *addr = &system;
答案 4 :(得分:0)
我建议您的环境具有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