在ELF文件中find全局偏移表

我怎样才能find我parsing的ELF文件中.got节的偏移量?

我不想按名称search该部分,因为我不想依赖它。 当我用别的东西改变段名时,二进制文件仍然有效。

简短的回答:在一般情况下,你不能。

在链接视图中的GOT

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

 $ readelf -S $ elf
 [...]
章节标题:
   [Nr]名称类型地址偏移量
       大小EntSize标志链接信息对齐
   [29] 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的位置和大小。

如果我正在查看libc的非PLT重定位表(在x86_64上),我得到了一堆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] PROGBITS 00000000003a2d80 001a2d80
        0000000000000278 0000000000000008 WA 0 0 8

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

注意

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