是否可以反向解码 x86-64 指令?

Is it possible to decode x86-64 instructions in reverse?

我想知道是否可以反向解码 x86-64 指令?

我需要这个用于运行时反汇编程序。用户可以指向内存中的随机位置,然后应该能够向上滚动并查看指定地址之前的指令。

我想通过反向解码来做到这一点。

x86指令的基本格式是这样的

现代 CPU 可以支持 VEX 和 EVEX 前缀。在 x86-64 中,开头可能还有 REX 前缀

看格式很容易看出指令不是回文,你不能从最后读。


关于判断任意地址属于哪条指令,遗憾的是也做不到,因为x86指令不是self-synchronizable,而且(一般)不对齐。您必须确切地知道指令的开始,否则指令将被不同地解码。

您甚至可以给出实际包含数据的地址,而 CPU/disassembler 只会将其解码为代码,因为没有人知道这些字节的实际含义。跳转到指令中间通常用于代码混淆。该技术过去也被用于节省代码大小,因为一个字节可以重复使用,并且根据它属于哪个指令具有不同的含义

也就是说,在许多情况下可能猜测,因为函数和循环通常对齐到 16 或 32 字节,并在周围填充 NOP

x86指令流不是自同步的,只能向前明确解码。您需要知道一个有效的解码起点。立即数的最后一个字节可以是 0x90,解码为 nop,或者通常 4 字节立即数或位移可以具有有效指令的字节序列,或任何其他重叠可能性ModRM/SIB 字节看起来像操作码。

如果您在未故意混淆的代码中进行正向解码,您通常会回到与 "correct" 指令边界同步的状态,因此您可以尝试将指令边界记住为已知的好点,并且检查从后退步骤候选起始地址的解码是否在您已知的良好点处具有指令边界。

IDK 如果你能更聪明地找到更多已知的好点,让更多的候选人也必须同意。

一定要用红色或灰色或其他颜色为用户突出显示向后解码的指令,这样他们就知道它不能保证可靠。


另一种方法是要求函数符号(外部函数,或任何带有调试信息的函数)。

GDB 不允许您向上滚动(在 layout reg 模式下),除非您在它知道起始地址的函数中。然后我猜它从函数起始地址解码,所以当它到达适合 window.

的部分时它知道指令边界

如果你想倒退,你必须disas 0x12345, +16从那里开始解码。然后你可以向下滚动,但是如果你弄错了 insn 边界,你就会得到垃圾。