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