0x004012d0 <main+0>: push %ebp
0x004012d1 <main+1>: mov %esp,%ebp
0x004012d3 <main+3>: sub $0x28,%esp
如果地址不可用,我们可以自己计算吗?
我的意思是我们只有这个:
push %ebp
mov %esp,%ebp
sub $0x28,%esp
0x004012d0 <main+0>: push %ebp
0x004012d1 <main+1>: mov %esp,%ebp
0x004012d3 <main+3>: sub $0x28,%esp
如果地址不可用,我们可以自己计算吗?
我的意思是我们只有这个:
push %ebp
mov %esp,%ebp
sub $0x28,%esp
字节数是相邻指令之间的地址差:
0x004012d0 <main+0>: push %ebp ;1 byte
0x004012d1 <main+1>: mov %esp,%ebp ;2 bytes
0x004012d3 <main+3>: sub $0x28,%esp
如果您只有文本,请转到此处:http ://www.swansontec.com/sintel.html 和此处:http: //faydoc.tripod.com/cpu/conventions.htm并计算每条指令、前缀和操作数
您不一定能从助记符中确定指令大小。以下是一些特殊情况:
如果您在 16 位段中,则mov eax, 0
需要0x66
前缀,而在 32 位段中则不需要。您需要知道段的大小。
在 32 位或 16 位模式下,您可以编码add eax, 1
为0x40
( inc eax
) 或0x83 0xc0 0x01
( add eax, 1
)。也就是说,有一些助记符可以用不止一种方式编码。
内存操作数[eax]
可以编码eax
为基数或索引。如果它是索引,您将在 MOD/RM 之后有一个额外的 SIB 字节。
在 64 位模式下,您可以使用 REX 前缀0x4x
对寄存器进行编码r8
- r15
。但是,您可以将0x40
其用作某种空 REX 字节,这将为您的指令添加另一个字节。
即使显式段与隐式段相同,也可以使用段覆盖。
还有许多其他方法可以使用更多或更少的字节对指令进行编码。一个好的汇编器应该总是使用最短的,但架构肯定不需要它。好消息是,如果您学习英特尔 IA-32 软件开发人员手册第 2 卷,您应该能够自己解决。
第一条指令位于 [main+0] 处,第二条位于 [main+1] 处,因此第一条指令为 1 个字节。第三条指令在 [main+3],所以第二条指令是两个字节。您无法从清单中看出第三条指令有多长,因为它没有显示 4. 指令的地址。
如果可能,让汇编器生成一个列表。这将显示您的源代码,接下来是指令的二进制表示,您需要做的就是计算有多少字节,然后得到大小。
如果您有文本形式的汇编代码,则必须使用汇编程序来获取
二进制表示,从而获得指令的大小。当然,这取决于硬件。
例如,这是一个80x86 32 位汇编器开源代码(OllyDbg v1.10)。