C 如何反转R_X86_64_跳转_插槽重新定位?

C 如何反转R_X86_64_跳转_插槽重新定位?,c,linker,shared-libraries,x86-64,elf,C,Linker,Shared Libraries,X86 64,Elf,我正在构建一个ELF二进制文件,它需要能够在运行时处理和反转自己的重新定位。(显然,反转将在单独的缓冲区中发生,而不是在原始代码页中。)这样做的目的是,可以对内存中的模块内容进行HMAC,并与从磁盘上的模块计算出的已知良好值进行比较,以确保没有发生损坏。我知道这有点不寻常,但这是我们必须遵守的标准要求 除了全局偏移表中发生的R\u X86\u 64\u JUMP\u槽重定位之外,我已经能够反转二进制文件中的所有重定位。查看我的测试模块的.rela.plt部分中带有readelf-a mylib.

我正在构建一个ELF二进制文件,它需要能够在运行时处理和反转自己的重新定位。(显然,反转将在单独的缓冲区中发生,而不是在原始代码页中。)这样做的目的是,可以对内存中的模块内容进行HMAC,并与从磁盘上的模块计算出的已知良好值进行比较,以确保没有发生损坏。我知道这有点不寻常,但这是我们必须遵守的标准要求

除了全局偏移表中发生的
R\u X86\u 64\u JUMP\u槽
重定位之外,我已经能够反转二进制文件中的所有重定位。查看我的测试模块的
.rela.plt
部分中带有
readelf-a mylib.so
的重定位条目,我看到了这些重定位:

Relocation section '.rela.plt' at offset 0x968 contains 20 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000005018  000100000007 R_X86_64_JUMP_SLO 0000000000000000 printf + 0
000000005020  002000000007 R_X86_64_JUMP_SLO 0000000000001ac5 processRelocations + 0
000000005028  000300000007 R_X86_64_JUMP_SLO 0000000000000000 memcpy + 0
000000005030  000400000007 R_X86_64_JUMP_SLO 0000000000000000 puts + 0 
...
这些偏移量指向全局偏移量表(特别是
.get.plt
),因此我可以使用
objdump-d-s-j.plt-j.get.plt mylib.so

Disassembly of section .got.plt:

0000000000005000 <_GLOBAL_OFFSET_TABLE_>:
    5000:       80 4e 00 00 00 00 00 00 00 00 00 00 00 00 00 00     .N..............
        ...
    5018:       10 10 00 00 00 00 00 00 20 10 00 00 00 00 00 00     ........ .......
    5028:       30 10 00 00 00 00 00 00 40 10 00 00 00 00 00 00     0.......@.......
...

Disassembly of section .plt:

0000000000001000 <.plt>:
    1000:       ff 35 02 40 00 00       pushq  0x4002(%rip)        # 5008 <_GLOBAL_OFFSET_TABLE_+0x8>
    1006:       f2 ff 25 03 40 00 00    bnd jmpq *0x4003(%rip)     # 5010 <_GLOBAL_OFFSET_TABLE_+0x10>
    100d:       0f 1f 00                nopl   (%rax)
    1010:       f3 0f 1e fa             endbr64
    1014:       68 00 00 00 00          pushq  $0x0
    1019:       f2 e9 e1 ff ff ff       bnd jmpq 1000 <.plt>
    101f:       90                      nop
    1020:       f3 0f 1e fa             endbr64
但是,符号表条目不是我想要的;我需要返回原始值
0x1020
,但我在符号表中的任何位置都看不到该值


如何在运行时反转这些重定位以找到它们的原始值?

您可以通过使用
-fno-plt
编译来避免这个问题,这样您就根本没有任何plt条目,并且相关的延迟绑定机制也不会发挥作用

呼叫*printf@GOTPCREL(%rip)
强制早期绑定:在进程启动时解析GOT条目。每次调用都是这样,一些发行版(如Arch GNU/Linux)已经在以这种方式编译它们的包了


TL:DR:这通常是一个很好的选择,只是在当前的GCC和clang发行版配置中,默认情况下它还没有启用。

您是否考虑过使用
-fno-plt
进行编译,所以您根本没有任何plt条目,希望没有相关的延迟绑定机制?(GCC将使用
调用*printf@GOTPCREL(%rip)
,强制早期绑定:在进程启动时解析get条目)@PeterCordes-Nice,这似乎已经成功了!但愿我以前知道这个选择!我仍然很好奇是否有一种方法可以真正扭转这些重新定位,但是
-fno-plt
至少暂时可以解决我的问题。谢谢如果你把它作为一个答案,如果没有人有更好的解决方案,我会接受。当然,是的,有趣的,至少是出于好奇,我想找到一个问题的答案,而不仅仅是一个避免问题的方法。
Symbol table '.dynsym' contains 34 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
   ...
   32: 0000000000001ac5   491 FUNC    GLOBAL DEFAULT   10 processRelocations