以字节为单位确定指令的长度

逆向工程 拆卸 x86 x64 机器码
2021-06-25 06:23:08

在哪里可以找到带有(十六进制)操作码和指令的长度/大小(以字节为单位)的 x86 指令(和 x64 指令)列表,例如:

  • 0x90= NOP= 1字节
  • 0xE9= JMP= 5字节
  • 0x8B= MOV= 2字节
  • 0x55= PUSH= 1字节
  • 0x6A= PUSH= 2字节
  • 0x68= PUSH= 5字节

不确定所有这些是否正确。

我一直在使用这个美妙的列表来查看指令及其操作码,但它不包含每个操作码的完整长度/大小(以字节为单位)。

让我更困惑的是它在开头提到“一字节操作码”和“两字节操作码”。JMP命令将是 5 个字节(JMP命令1 个字节,跳转距离 4 个字节)。

编辑

我本身并不特别需要一个列表。总的来说,我只是在寻找一种推断指令长度的方法。

3个回答

与使用列表不同,使用小型便携的长度反汇编器可能会更有效,例如https://github.com/greenbender/lend

不出所料,最终列表可在这些处理器的英特尔手册中找到。这些可从英特尔网站免费下载。你最想要的,或者说首先,是操作码映射。这一点非常重要,通常(如果不总是)在软件开发人员手册、程序员参考手册或其他任何内容的附录 A 中。

操作码映射按第一个字节排序,并为您总结指令如何继续。例如,在这里您会发现 0x8B 不仅仅是一个 MOV,而是一个字或双字(取决于操作数大小属性)从有效地址到通用寄存器的 MOV,因此操作数可以有一个范围格式(其编码细节在另一个附录中)使得整个指令至少为 2 个字节,但可能长达 7 个字节(作为一个 mod r/m 字节、一个可选的 sib 字节和一个可选的位移)。

至于一字节和两字节的操作码——现在甚至更长——这些只是指指令开始处的字节,它们是开始指令所必需的,但是操作数后面可能有很多字节。最初,只有一字节的操作码(除非我们计算到协处理器的转义)。随着映射的填充,0x0F 被选为引入两字节操作码。例如,SMSW 指令总是从 0x0F 0x01 开始,不管它的操作数是什么。(总是还有第三个字节,它将 SMSW 与其他以 0x0F 0x01 开头的指令区分开来,但是当您仔细阅读手册时,我将对此的理解留作练习。)

制作这样的列表是不可能的(取决于像 8B 这样的字节之后的内容,它可能比 2 个字节长得多)。我建议您使用反汇编库,因为几乎所有人都会计算长度,您可以从那里访问它。有一些字节将寄存器/数字作为唯一的操作数,但即使在这些情况下,前缀也可以改变它们的行为。