在 ELF 文件中定位全局偏移表

4

我正在解析一个ELF文件,想要找到.got节的偏移量?

我不想通过名称来查找该节,因为我不想依赖它。当我使用其他名称更改节名称时,二进制文件仍然有效。


通过code()使用elf.h或者通过命令行? - basav
不是在命令行中,也不是在运行时。我想解析ELF文件以找出.got节的偏移量,而不依赖于节名称(这可能不可靠)。 - kubuzetto
你为什么想要这样做? - ysdx
在某些系统上,这将给出已反汇编的全局偏移表:objdump -d -j .got path/to/yourlib.so - vulcan raven
1个回答

10

简短回答:一般情况下你无法找到全局偏移表(GOT)。

链接视图中的GOT

进程的链接视图由节头表给出。可以通过以下方式找到GOT:

$ readelf -S $elf
[...]
节头:
  [Nr] 名称              类型             地址              偏移量
       大小              EntSize          标志    链接  信息   对齐
  [29] .got              PROGBITS         00000000003a2d80  001a2d80
       0000000000000278  0000000000000008  WA       0     0     8
  [30] .got.plt          PROGBITS         00000000003a3000  001a3000
       0000000000000078  0000000000000008  WA       0     0     8

只能通过节名来识别GOT(实际上可以是任何内容)。GOT条目使用SHT_PROGBITS(与ELF文件的许多其他部分一样),因此无法使用节类型来识别它们。

此外,节头表在运行时不需要,并且不需要出现在ELF文件中。

执行视图

我们可以使用执行视图吗?

程序头表给出了执行视图。但是,在程序头表中,没有真正的(非PLT)GOT概念。运行时不关心GOT条目位于何处。它们可以散布在数据段中的任何位置*。重要的是正确的重定位存在于(运行时)重定位表中。

使用动态节

需要告诉动态链接器PLT GOT条目(.got.plt)的位置。这由动态节的DT_PLTGOT条目给出。但是,它仅提供GOT PLT表开头的(运行时,虚拟内存)位置:您无法获得其大小。

使用重定位表

您可以尝试检查重定位表:

  • 通过查看PLT重定位条目,您应该能够推断出PLT GOT的大小;

  • 通过查看非PLT重定位,您可能能够推断出非PLT GOT的位置和大小。

如果我查看x86_64上libc的非PLT重定位表,则会得到一堆R_X86_64_GLOB_DAT条目:

$ readelf -r $elf
[...]
0000003a2da0  052c00000006 R_X86_64_GLOB_DAT 00000000003a4708 stderr + 0
0000003a2da8  061400000006 R_X86_64_GLOB_DAT 00000000003a85d0 error_one_per_line + 0
0000003a2db0  06eb00000006 R_X86_64_GLOB_DAT 00000000003a57d0 __malloc_initialize_ho + 0
0000003a2db8  07f300000006 R_X86_64_GLOB_DAT 00000000003a4720 __morecore + 0
0000003a2dc8  02a400000006 R_X86_64_GLOB_DAT 00000000003a8998 __key_encryptsession_p + 0
0000003a2dd0  061000000006 R_X86_64_GLOB_DAT 00000000003a3ec8 __progname_full + 0
0000003a2dd8  049c00000006 R_X86_64_GLOB_DAT 00000000003a4010 __ctype32_tolower + 0
0000003a2de0  011900000006 R_X86_64_GLOB_DAT 00000000003a5fb8 _environ + 0
0000003a2de8  000300000006 R_X86_64_GLOB_DAT 0000000000000000 _rtld_global + 0
0000003a2df0  011000000006 R_X86_64_GLOB_DAT 00000000003a3ec0 __progname + 0
0000003a2df8  04ff00000006 R_X86_64_GLOB_DAT 00000000003a32c4 argp_err_exit_status + 0
0000003a2e08  04ce00000006 R_X86_64_GLOB_DAT 00000000003a8538 mallwatch + 0
0000003a2e10  00bc00000006 R_X86_64_GLOB_DAT 00000000003a87d8 __rcmd_errstr + 0
0000003a2e18  056400000006 R_X86_64_GLOB_DAT 00000000003a48e0 __vdso_clock_gettime + 0
[...]

我们已经找到了非PLT GOT的地址:

$ readelf -S $elf
[...]
  [29] .got              PROGBITS         00000000003a2d80  001a2d80
       0000000000000278  0000000000000008  WA       0     0     8

有4个缺失的GOT条目(我不知道为什么……)。

注意

(*):这意味着可能没有任何(非PLT)GOT。


很遗憾,您只是粘贴了输出结果,而没有相关的命令。 - sherlock
2
@Holmes.Sherlock:每个片段的第一行是命令。 - ysdx

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接