目录
- 一、准备 🧐
- 二、疑问 🔍
- 三、回答 💡
- 四、总结 📃
本文在调试过程中发现
ldd
和
(gdb) info sharedlibrary
显示不同的动态库加载基地址,然后查了一些资料后,找到了这篇帖子【
传送门】,现做一下复现,但是还是不知道
ldd <目标文件>
这个命令打印的地址是什么地址,如果有哪位大佬知晓,望不吝相告,谢谢。
一、准备 🧐
/* test.c */
#include <stdio,h>
int main(int argc, const char *argv[])
{
printf("hello world\n");
while(1);
}
编译:gcc -m32 -no-pie -fno-stack-protector -z execstack -o test test.c
-m32:生成32位的可执行文件。
-no-pie:关闭可执行文件位置无关代码,默认是关闭的,所以可不加,有些加上该选项后还会报错。
-fno-stack-protector:关闭Stack Protector/Canary(栈保护)
-z execstack:关闭DEP/NX(堆栈不可执行)
-o:输出
test:编译生成文件的文件名
test.c:编译前的源文件
查看ASLR:cat /proc/sys/kernel/randomize_va_space
,如果为0表示处于关闭状态。
切换至root用户,关闭ASLR:echo 0 > /proc/sys/kernel/randomize_va_space
,当需要开启时,将 0 换成 1 或 2 即可。
这里复现时需要关闭掉 ASLR!!!
二、疑问 🔍
方式一、根据 ldd
命令可知 libc
的加载地址为 0xb7e40000
方式二、使用 GDB
调试命令 info sharedlibrary
可知 libc
的加载地址为 0xb7e34f70
方式三、当我们用手动的方式通过符号计算动态加载基地址,首先通过 GDB
获得 system
函数加载的基地址:0xb7e5d0b0
。
使用 IDA Pro
软件查看 system 函数在动态库中的偏移,得到 0x0003F0B0
,则动态库加载基地址为:0xb7e5d0b0 - 0x0003F0B0 = 0xb7e1e000
总共获得了三种结果,所以哪一种结果是正确的?
方式一:0xb7e40000
方式二:0xb7e34f70
方式三:0xb7e1e000
三、回答 💡
方式三获得的地址正确
首先,ldd
命令并不能准确的确定动态库加载基地址,至于这个地址是什么的地址,目前还不知道。如果要获得动态库加载基地址,需要用到环境变量 LD_TRACE_LOADED_OBJECTS
。(这里需要关闭ASLR,不然每次查找基地址时都会发生变化,也正是由于这种变化才能保护程序不容易被攻破。)
用法:
LD_TRACE_LOADED_OBJECTS=1 <可执行程序> | grep libc
例如:LD_TRACE_LOADED_OBJECTS=1 ./test | grep libc
(少./
可能出错)
其次,如何查看程序在运行时动态库加载的基地址?
方法一:运用
/proc/<进程号>/maps
,这里以libc.so.6(该动态库为libc-2.15.so的软链接)为例子,
- ① grep libc /proc/<进程号>/maps | head -n1
- ② cat /proc/<进程号>/maps | grep libc
方法二:在 GDB 调试中,使用
info proc mapping
查看。
验证:
已经知道动态库加载基地址的正确地址,那 info sharedlibrary
的地址是什么?
通过以下命令,查看代码段在动态库中的偏移地址为0x00016f70
。
在开启ASLR的情况下,动态库的每次加载地址都是随机的,但是当通过GDB进行调试的时候,会关闭ASLR功能。 通过 GDB 中的 info proc mapping
命令查看动态库加载的基地址为0xb7e1e000
,通过 info sharedlibrary
命令查看动态库时的地址 0xb7e34f70
是什么地址?
如果将这三个数据进行一次运行,结果会很明了:0xb7e34f70 = 0xb7e1e000 + 0x00016f70
,因此,可以推断出 info sharedlibrary
命令查看动态库代码段加载的基地址。
四、总结 📃
-
ldd <目标文件>
方式并不能准确的查看某个动态库的加载基地址,目前该命令所显示的地址是什么地址还不明确。 - 查看动态库的加载基地址方式有如下几种:
①LD_TRACE_LOADED_OBJECTS=1 <可执行程序> | grep <动态库名>
② 运用/proc/<进程号>/maps
③ 在 GDB 调试中,使用info proc mapping
查看 - 如果系统开启 ASLR,则每次的加载地址都是变化的,但是GDB调试时会将该功能禁止。
- 在 GDB 调试中,
info sharedlibrary
命令查看的是动态库代码段的起始地址。
参考:
Why does `ldd` and `(gdb) info sharedlibrary` show a different library base address? 🚀