从问题来看,您似乎正在分析一个库函数。
要了解正在测量的功能是什么,您有 2 个选择:
1运行使用该库的程序gdb
并停在main
。此时,得到pid
该计划的PID=...
并执行“cat /proc/$PID/maps”。在那里你应该看到类似这样的东西:
➜ ~ ps
PID TTY TIME CMD
18533 pts/4 00:00:00 zsh
18664 pts/4 00:00:00 ps
➜ ~ PID=18533
➜ ~ cat /proc/$PID/maps
00400000-004a2000 r-xp 00000000 08:01 3670052 /bin/zsh5
006a1000-006a2000 r--p 000a1000 08:01 3670052 /bin/zsh5
006a2000-006a8000 rw-p 000a2000 08:01 3670052 /bin/zsh5
006a8000-006bc000 rw-p 00000000 00:00 0
...
7fa174cc9000-7fa174ccd000 r-xp 00000000 08:01 528003 /lib/x86_64-linux-gnu/libcap.so.2.22
7fa174ccd000-7fa174ecc000 ---p 00004000 08:01 528003 /lib/x86_64-linux-gnu/libcap.so.2.22
7fa174ecc000-7fa174ecd000 r--p 00003000 08:01 528003 /lib/x86_64-linux-gnu/libcap.so.2.22
7fa174ecd000-7fa174ece000 rw-p 00004000 08:01 528003 /lib/x86_64-linux-gnu/libcap.so.2.22
...
Here 7fa174cc9000
是基地址/lib/x86_64-linux-gnu/libcap.so.2.22
图书馆。所以你得到的所有地址readelf -s
将被该值抵消。知道基地址,您可以计算出文件中的原始偏移量。
IE。如果你得到了价值7fa174206370
库的基地址是7fa1741cf000
那么偏移量是7fa174206370 - 7fa1741cf000 = 37370
。在我的例子中是sigsuspend
来自 GLIBC:
94: 0000000000037370 132 FUNC WEAK DEFAULT 12 sigsuspend@@GLIBC_2.2.5
2 Run gdb
在使用这些库的程序上。它要么立即在内存中找到加载的库,要么需要指向.text
图书馆的部分。
> gdb
(gdb) attach YOUR_PID
(a lot of output about symbols)
(gdb) x/i 0x00007fa174206386
=> 0x7fa174206386 <sigsuspend+22>: cmp $0xfffffffffffff000,%rax
这样你就知道了0x7fa174206386
在里面sigsuspend
.
In case gdb
本身不加载任何符号(没有像这样的输出Reading symbols from ... Loading symbols for ...
附加后),您可以按照选项查找库的基地址1,然后添加到它的偏移量.text
section
➜ ~ readelf -S /lib/x86_64-linux-gnu/libcap.so.2.22 | grep '.text.'
[11] .text PROGBITS 0000000000001620 00001620
7fa174cc9000 + 0000000000001620
十六进制给出7FA174CCA620
,然后你通过附加gdb
如上所述并做
(gdb) add-symbol-file /lib/x86_64-linux-gnu/libcap.so.2.22 7FA174CCA620
然后你应该能够找到符号(通过x/i ADDRESS
如选项中所示1) 即使gdb
不会自行加载它们。
有什么不清楚的地方请追问,我会尽力解释。
澄清为什么会这样:
观察到的行为是由于库被编译为位置无关代码 https://wiki.gentoo.org/wiki/Hardened/Introduction_to_Position_Independent_Code。它使我们能够轻松支持动态库。 PIC 本质上意味着库的 ELF 有.plt
and .got
节并且可以加载到任何基地址。 PLT是过程链接表,它包含调用位于其他模块中的函数的陷阱,该陷阱首先进入程序解释器以允许其重新定位被调用的函数,然后在第一次调用后跳转到该函数。它之所以有效,是因为程序解释器更新了 GOT(全局偏移表),其中包含要调用的函数的地址。最初,GOT 被初始化,以便在第一次函数调用时跳转到程序解释器的函数,该函数执行当前调用函数的解析。
在 x86-64 上,PLT 条目通常如下所示:
0000000000001430 <free@plt>:
1430: ff 25 e2 2b 20 00 jmpq *0x202be2(%rip) # 204018 <_fini+0x201264>
1436: 68 00 00 00 00 pushq $0x0
143b: e9 e0 ff ff ff jmpq 1420 <_init+0x28>
首先jmpq
是跳转到地址,存储在GOT中的位置%rip + 0x202be2
:
[20] .got PROGBITS 0000000000203fd0 00003fd0
0000000000000030 0000000000000008 WA 0 0 8
%rip + 0x202be2
将0x204012
,并将其添加到库的基地址中,以生成与库实际加载位置相关的绝对地址。 IE。如果它加载于0x7f66dfc03000
,那么相应 GOT 条目的结果地址将是0x7F66DFE07012
。存储在该位置的地址是(在本例中)的地址free
功能。它由程序解释器维护以指向实际的free
in libc
.
有关这方面的更多信息可以找到here http://s.eresi-project.org/inc/articles/elf-rtld.txt.