为什么 ‘ldd’ 和 ‘(gdb) info sharedlibrary’ 显示不同的动态库基地址?


本文在调试过程中发现 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:编译前的源文件

查看ASLRcat /proc/sys/kernel/randomize_va_space,如果为0表示处于关闭状态。

切换至root用户,关闭ASLRecho 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 命令查看的是动态库代码段的起始地址。

参考:
[1]: Why does `ldd` and `(gdb) info sharedlibrary` show a different library base address? 🚀
[2]: linux动态库运行时函数地址怎么查看器,查看正在运行的动态链接的程序中,某个动态库中函数的虚拟地址… 🚀

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值