我正在研究C中的一个项目,我遇到了一个问题。我正在尝试对x86_64指令进行硬编码,但内存地址不是很正确。真的,问题本身很简单;我只是想弄清楚它的解决方案。
在GDB中,我得到以下内容:
(gdb) x /7ib f
...
0x7ffff7ff7005: callq 0x80000040072b`
这很好,除了一件事:根据GDB,我想要的地址是0x40072b
(在相关的注释中,出于好奇,为什么是内存地址f
这么高?)我该如何解决这个问题?作为参考,这里是我正在处理的部分的十六进制(只有这六个字节):
(gdb) x /6xb 0x7ffff7ff7005
0x7ffff7ff7005: 0x48 0xe8 0x20 0x97 0x40 0x08
感谢您提供的任何帮助。
更新
有人要求我解释我如何提出这种抵消:
以下是我正在处理的内容:我想实现一种方法让我在C中使用closures,我试图通过实现我在this article中找到的内容来实现我的基础是最终的......是的,我知道这个解决方案将是特定于架构的。
本质上,它将thunk编码为一个打包结构,其中包含必要的操作码以加载环境并在内存中调用所需函数的位置,然后(令Dennis Ritchie的鬼魂沮丧)被转换为{ {1}},定义为
cfunc
之后,它被称为普通函数。
它通过创建thunk typedef void (* cfunc)();
并在一两个其他事项中使用以下行计算struct
GAS操作的偏移量来完成此操作:
callq
我知道这是可行的,因为它实际上在32位模式下编译原始代码时有效。我想要做的是修改代码以在64位模式下工作。我假设我需要用某种值填充偏移量,以使其指向正确的内存地址,但我不确定该值是什么。那,或者可能有另一种编写调用操作码的方法,我可以使用它来指向正确的内存地址。
答案 0 :(得分:2)
0x48 0xe8 0x20 0x97 0x40 0x08
转换为:
48 e8 20974008
| | |
| | +------ Offset (As of opcode)
| +----------- Opcode (CALL)
+-------------- REX prefix
0100 1000
| ||||
| |||+-- B - Extension to MODRM.rm or SIB.base
| ||+--- X - Extension to SIB.index
| |+---- R - Extension to MODRM.reg
| +----- W - 64-bit operand size, else (usually) 32-bit
+-------- Fixed bit pattern
换句话说:64位操作数大小。
查看instruction manual一个查找:
CALL e8 cd
拨打附近, 相对,置换相对到下一条指令。在64位模式下,32位位移符号扩展为64位。
其中:
cd - 操作码后面的4字节值。该值用于指定代码段寄存器的代码偏移量和可能的新值。
cd 就是这种情况:
20 97 40 08
从小到大的顺序我们得到:
08409720 + 6
我们加6,因为偏移是相对于下一条指令。因为指令是六个字节。
0x48 0xe8 0x20 0x97 0x40 0x08
换句话说:
callq fun_08409726
在打印出来的GDB中:
(gdb) x /7ib f
...
0x7ffff7ff7005: callq 0x80000040072b`
您可以通过以下地址获取地址0x7ffff7ff7005
的偏移量:
0x7ffff7ff7005 + 0x08409726 = 0x80000040072b
| | |
| | +-------- Result address (same as in GDB).
| +----------------------- The offset we calculated above.
+-------------------------------------- Memory offset of the instruction.
GDB可能会发生一些事情,但这看起来不太合适。
(虚拟)地址0x000080000040072b
高于0x00007fffffffffff
。地址的原因是由指令偏移引起的。现在如何生成此偏移量。 (正如你所说“我正在尝试对x86_64指令进行硬编码”)你可能最了解自己。