问题描述
我正在查看radare2 中的一些测试代码,但我无法理解反汇编程序如何计算调用指令跳转到的位置.考虑一下:
I'm looking at some test code in radare2, and I'm having trouble understanding how disassemblers figure how where a call instruction jumps to.Consider this:
在 0x00001090 puts() 被调用.我想自己解析与该指令关联的二进制文件 (e89bffffff),所以我通过 lib capstone 运行它并得到了这个:
at 0x00001090 puts() gets called. I wanted to parse the binary (e89bffffff) associated with that instruction myself, so I ran it through lib capstone and got this:
所以我们可以看到实际的操作数是 0xfb0.然后在 rasm2 中我们有:
so we can see the actual operand is 0xfb0. And then in rasm2 we have:
# rasm2 -a x86 -b 64 -d e8a1ffffff
call 0xffffffffffffffa6
这是不同的.我希望 libcapstone 和 rasm2 具有相同的输出.
which is different. I expected libcapstone and rasm2 to have the same output.
我的主要问题是,如何解释 0xfb0(或 0xffffffffffffffa6)以获取下一条指令地址?根据radare,在我的情况下,sym.imp.puts 位于 0x00001030.
My main question is, how do I interpret 0xfb0 (or 0xffffffffffffffa6) to get the next instruction address? In my case sym.imp.puts is at 0x00001030 according to radare.
推荐答案
如图所示 https://www.felixcloutier.com/x86/call,e8
操作码执行具有相对位移的调用.操作数是一个有符号的 32 位位移,它被添加到下一条指令的地址以获得绝对目标地址.这是为了便于编写与位置无关的代码,无论将其加载到内存中的何处,这些代码都将运行相同.
As shown at https://www.felixcloutier.com/x86/call, the e8
opcode executes a call with relative displacement. The operand is a signed 32-bit displacement which is added to the address of the next instruction to get the absolute target address. This is to make it easy to write position-independent code, that will run the same no matter where it is loaded in memory.
这里的位移操作数是9bffffff
.它是小端(就像 x86 上的所有内容一样)所以这是数字 0xffffff9b
或 -0x65
.
The displacement operand here is 9bffffff
. It's little-endian (like everything on x86) so this is the number 0xffffff9b
, or -0x65
.
在您的第一次反汇编中,call
指令后面的指令位于地址 0x00001095
,因此调用将转到 0x00001095 - 0x65 = 0x00001030
.反汇编器检查了符号表,发现这个地址对应于sym.imp.puts
,所以它显示的是那个而不是数字地址.
In your first disassembly, the instruction following the call
instruction is at address 0x00001095
, so the call will go to 0x00001095 - 0x65 = 0x00001030
. The disassembler has checked the symbol table and seen that this address corresponds to sym.imp.puts
, so it shows you that instead of the numerical address.
在你的第二次反汇编中,代码好像加载到了不同的地址,下面指令的地址是0x1015
,所以调用会去0x1015 - 0x65 =0x0fb0
.反汇编程序已为您完成此计算,并显示实际目标地址而不是位移.
In your second disassembly, the code seems to have been loaded at a different address, and the address of the following instruction is 0x1015
, so the call will go to 0x1015 - 0x65 = 0x0fb0
. The disassembler has done this calculation for you, and is showing you the actual target address rather than the displacement.
rasm2
只是给出了指令,没有找到它的地址的信息,所以它不能做这个计算.因此它只是告诉你位移.出于某种原因,它选择将其符号扩展到 64 位.此外,您似乎在给它 e8a1ffffff
而不是实际指令 e89bffffff
时打错了字,这就是您看到不同位移的原因.
rasm2
is just given the instruction, without information about the address where it was found, so it can't do this calculation. Thus it just tells you the displacement. For some reason it has chosen to sign-extend it to 64 bits. Also you seem to have made a typo in giving it e8a1ffffff
instead of the actual instruction e89bffffff
which is why you are seeing a different displacement.
这篇关于理解 x86-64 调用操作数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!