ldd
显示了libc在0xf7e9e000
的加载地址$ ldd ~/my_tool
linux-gate.so.1 => (0xf7ffe000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf7e9e000)
/lib/ld-linux.so.2 (0x56555000)
gdb告诉我它加载在
0xf7e96c60
(gdb) info sharedlibrary
From To Syms Read Shared Object Library
0xf7fe1820 0xf7ff805f Yes (*) /lib/ld-linux.so.2
0xf7e96c60 0xf7f9643c Yes (*) /lib/i386-linux-gnu/libc.so.6
,当我根据符号手动计算基址时:
(gdb) print system
= {<text variable, no debug info>} 0xf7ebb6b0 <system>
>
我得到这个地址:
0xf7ebb6b0-0x003b6b0 = 0xf7e80000
为什么?
calculated: 0xf7e80000
gdb: 0xf7e96c60
ldd: 0xf7e9e000
#1 楼
ldd
由于某些原因,程序
ldd
是错误的。首先,
ldd
并不准确确定装载地址。使用环境变量LD_TRACE_LOADED_OBJECTS
。 其次,如Guntram所示,启用ASLR后
ldd
永远不会正确。如果您具有sudo
访问权限,则可以禁用此功能。$ LD_TRACE_LOADED_OBJECTS=1 /bin/bash | grep libc
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f44dae1b000)
$ LD_TRACE_LOADED_OBJECTS=1 /bin/bash | grep libc
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9b35341000)
$ LD_TRACE_LOADED_OBJECTS=1 /bin/bash | grep libc
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fef18efd000)
$ echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
0
$ LD_TRACE_LOADED_OBJECTS=1 /bin/bash | grep libc
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ffff75e7000)
$ LD_TRACE_LOADED_OBJECTS=1 /bin/bash | grep libc
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ffff75e7000)
$ LD_TRACE_LOADED_OBJECTS=1 /bin/bash | grep libc
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ffff75e7000)
您可以通过在后台启动bash实例并检查其maps文件来验证这一点。 />
$ bash &
[1] 30398
[1] + 30398 suspended (tty input) bash
$ grep libc /proc/30398/maps | head -n1
7ffff75e7000-7ffff77a2000 r-xp 00000000 08:01 525269 /lib/x86_64-linux-gnu/libc-2.19.so
info sharedlibrary
info sharedlibrary
报告的地址是.text
区域的地址。请注意,我拥有的libc,.text位于
0x1f4a0
。$ readelf --wide --section-headers /lib/x86_64-linux-gnu/libc-2.19.so | grep text
[12] .text PROGBITS 000000000001f4a0 01f4a0 145c23 00 AX 0 0 16
在GDB中,如果我们查看
libc
的加载地址,我们会看到它已加载在0x7ffff7a14000
。如果系统上启用了ASLR,则每次运行程序时,此更改都会更改。如果您在GDB下运行它,还将禁用ASLR。在运行目标之前运行命令set disable-randomization off
,您会观察到它每次运行都会发生变化。 gdb-peda$ info proc mapping
...
0x7ffff7a14000 0x7ffff7bcf000 0x1bb000 0x0 /lib/x86_64-linux-gnu/libc-2.19.so
0x7ffff7bcf000 0x7ffff7dcf000 0x200000 0x1bb000 /lib/x86_64-linux-gnu/libc-2.19.so
0x7ffff7dcf000 0x7ffff7dd3000 0x4000 0x1bb000 /lib/x86_64-linux-gnu/libc-2.19.so
0x7ffff7dd3000 0x7ffff7dd5000 0x2000 0x1bf000 /lib/x86_64-linux-gnu/libc-2.19.so
...
如果从
0x1f4a0
区域添加.text
偏移量,则得到0x7ffff7a334a0
。如果我们看一下info sharedlibrary
,我们将确切地看到该地址。 但是,这在FreeBSD上不可用,因为GDB不支持获取模块基地址所必需的特定于FreeBSD的API。相反,您必须使用
info proc mapping
命令并亲自执行翻译(通过减去info proc mapping
部分的地址)。#2 楼
首先,ASLR将在每次调用时在(略有不同)地址加载库,以帮助防止恶意软件。这就是为什么ldd
和gdb
之间的地址不同,以及为什么每次运行gdb
时它们甚至都不同的原因。如果我只是grep表示我系统上的libc可执行段(64位,如我没有一个方便的32位系统):
$ grep 'r-xp.*libc-2.19' /proc/*/maps|head
/proc/10987/maps:7fe455b72000-7fe455d2d000 r-xp 00000000 08:16 23461990 /lib/x86_64-linux-gnu/libc-2.19.so
/proc/11880/maps:7f029dc1f000-7f029ddda000 r-xp 00000000 08:16 23461990 /lib/x86_64-linux-gnu/libc-2.19.so
/proc/11884/maps:7f25a9c25000-7f25a9de0000 r-xp 00000000 08:16 23461990 /lib/x86_64-linux-gnu/libc-2.19.so
/proc/15715/maps:7ffc713da000-7ffc71595000 r-xp 00000000 08:16 23461990 /lib/x86_64-linux-gnu/libc-2.19.so
/proc/17705/maps:7fe9db80c000-7fe9db9c7000 r-xp 00000000 08:16 23461990 /lib/x86_64-linux-gnu/libc-2.19.so
/proc/18558/maps:7fc248544000-7fc2486ff000 r-xp 00000000 08:16 23461990 /lib/x86_64-linux-gnu/libc-2.19.so
/proc/20156/maps:7f0f8eb13000-7f0f8ecce000 r-xp 00000000 08:16 23461990 /lib/x86_64-linux-gnu/libc-2.19.so
/proc/2139/maps:7fba4c097000-7fba4c252000 r-xp 00000000 08:16 23461990 /lib/x86_64-linux-gnu/libc-2.19.so
/proc/2215/maps:7f934ed76000-7f934ef31000 r-xp 00000000 08:16 23461990 /lib/x86_64-linux-gnu/libc-2.19.so
/proc/2224/maps:7f064d98f000-7f064db4a000 r-xp 00000000 08:16 23461990 /lib/x86_64-linux-gnu/libc-2.19.so
您会看到每个进程对同一个库的映射都有些不同。
也,加载器在加载库时会为其创建几个内存段。 ELF文件中的段被读入这些共享内存段,包括一些头。这就是为什么代码起始地址与段起始地址不同的原因。
例如,在我的系统上:
(gdb) info sharedLibrary
From To Syms Read Shared Object Library
0x00007ffff7a334a0 0x00007ffff7b790c3 Yes /lib/x86_64-linux-gnu/libc.so.6
和
cat /proc/26271/maps
7ffff7a14000-7ffff7bcf000 r-xp 00000000 08:16 23461990 /lib/x86_64-linux-gnu/libc-2.19.so
7ffff7bcf000-7ffff7dcf000 ---p 001bb000 08:16 23461990 /lib/x86_64-linux-gnu/libc-2.19.so
7ffff7dcf000-7ffff7dd3000 r--p 001bb000 08:16 23461990 /lib/x86_64-linux-gnu/libc-2.19.so
7ffff7dd3000-7ffff7dd5000 rw-p 001bf000 08:16 23461990 /lib/x86_64-linux-gnu/libc-2.19.so
因此,您会看到代码段(可执行的代码,即设置了x位)的内存映射范围为7ffff7a14000-7ffff7bcf000,但该区域实际加载的代码只是7ffff7a334a0-7ffff7b790c3的子集。
您可以在这里找到更详尽的解释。
评论
我的情况下没有ASLR。我在原始问题中发布的示例每次都是不变的。
– Samuirai
2014年12月4日上午11:42
评论
我的情况下没有ASLR。我在原始问题中发布的示例每次都是不变的。
– Samuirai
2014-12-04 11:42
我的回答解决了这个问题。信息共享库打印.text区域的地址,而不是moduel基数。
–扎克(Jach)步枪
2014年12月17日在21:20
平安这是答案。 tl; dr在最后。您需要“信息处理映射”。
–扎克(Jach)步枪
15年4月15日在16:42
@ZachRiggle ping,您能为为什么ldd“不准确”添加解释吗?另外,使用LD_TRACE_LOADED_OBJECTS = 1并不能改善这种情况:实际上,从man ldd读取时,调用ldd等效于显式调用设置了LD_TRACE_LOADED_OBJECTS变量的加载程序-因此,ldd并未使用它。 pastebin.com/raw/06bQjui5
–朱塞佩·克里诺(GiuseppeCrinò)
16年7月29日在15:58
@guiscri:回想一下,我不确定为什么要发表这个声明。我希望这是有原因的,但是已经两年了,我已经忘记了。 ldd foo和LD_TRACE_LOADED_OBJECTS foo在功能上应等效。无论哪种情况,您都不应依赖它作为模块地址。
–扎克(Jach)步枪
16年8月11日在21:03