我看到应该在何处加载libc的三个不同的输出。

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部分的地址)。

评论


我的情况下没有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



#2 楼

首先,ASLR将在每次调用时在(略有不同)地址加载库,以帮助防止恶意软件。这就是为什么lddgdb之间的地址不同,以及为什么每次运行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