英特尔x86操作码参考?

41

有没有一种较为简便快速的方法来查找x86指令的含义(比如说,0xC8)?

查看Intel软件开发者手册不太方便...


英特尔手册确实在附录中有一个操作码表,但我同意它不如其他用于手动反汇编的资源易用。 - Peter Cordes
7个回答

59

2
请注意,该页面不再是“非常完整”的。它似乎在 AVX 之前停止了(例如尝试查找 vmovups)。尽管如此,它仍然是一个很好的参考,所以这是一个好答案。但是,如果人们想要“非常完整”的东西,我现在看到的唯一参考是 Sandpile,正如其他人提到的那样。虽然也有 AsmJit 的数据库,这也可能会有所帮助。最后,为了让任何没有向下滚动阅读其他答案的人受益:x86 在八进制中更易读,将位分组为[AA][BBB][CCC]。 - user541686

29

6
我见过的最令人兴奋的桌子。 - master-lame-master
1
为什么 XCHG EAX, ECX 是内存操作? - l4m2
1
@l4m2 可能是因为 EAX 是一个寄存器。 - John Smith
@l4m2:这是错误分类。它不执行任何计算,只是数据移动,但是对于0x90..7 xchg eax, reg单字节编码的数据移动不能包括数据内存。0xb? mov操作码也不会将imm8或imm32放入寄存器中。此外,cwdcdq显然是ALU指令,将EAX符号扩展为EDX:EAX。等一下,那个表格甚至都不正确。0x98是CWDE(并带有66前缀的CBW)。0x99是CDQ(并带有66前缀的CWD)。 - Peter Cordes
@l4m2:所以我想我们可以把红色视为实际上是“数据移动”,包括像bswap这样的洗牌操作。但是0x98被错误地标记为CWD,实际上它是CWDE,并且显然是ALU,根据另一个寄存器的最高位设置一个寄存器。此外,CMPS和SCAS并不完全是“控制流”,它们既涉及内存又涉及ALU。例如,repe scasb是一种无分支(而且慢)的memchr。如果你必须选择其中一种颜色,我不知道。我猜他们的“控制流和条件”包括某些原因的标志设置/读取,即使那只是ALU。 - Peter Cordes

15

虽然英特尔软件开发手册本身不太方便查找,但是这个手册中的操作码表可能会有所帮助。请查看附录A“操作码映射”在手册的卷2A、2B、2C和2D,这可能会很有用:

Appendix A Opcode Map Table of Contents


1
可能只是我自己的问题,但我觉得附录有点令人困惑。:\ 不过还是谢谢。 - user541686
我添加了一个PDF手册的直接链接和附录A的目录截图。我从这个入口页面找到了它 > https://software.intel.com/content/www/us/en/develop/articles/intel-sdm.html#combined,该页面链接到了这里的4部分综合手册 > https://software.intel.com/content/www/us/en/develop/download/intel-64-and-ia-32-architectures-sdm-combined-volumes-2a-2b-2c-and-2d-instruction-set-reference-a-z.html,以防链接需要更新。 - Elijah Lynn

9

此外还有asmjit/asmdb项目,提供了以类JSON格式的公共领域X86/X64数据库(实际上是一个节点模块,可以从节点中require()它或在浏览器中包含它)。它专为额外处理而设计(例如编写验证器、汇编器、反汇编器),但也很容易只打开数据库文件并对其进行探索。

AsmDB带有一个名为x86util.js的工具,可以将x86数据库索引到更友好的表示形式中,可用于实际处理。让我们在node.js中编写一个简单的工具,打印出所有具有与提供的操作码字节相同的指令:

const asmdb = require("asmdb");
const x86isa = new asmdb.x86.ISA();

function printByOpCode(opcode) {
  x86isa.instructions.forEach(function(inst) {
    if (inst.opcodeHex === opcode) {
      const ops = inst.operands.map(function(op) { return op.data; });
      console.log(`INSTRUCTION '${inst.name} ${ops.join(", ")}' -> '${inst.opcodeString}'`);
    }
  });
}

if (process.argv.length < 3)
  console.log("USAGE: node x86search.js XX (opcode)")
else
  printByOpCode(process.argv[2]);

试一试:

$ node x86search.js A9
INSTRUCTION 'pop gs' -> '0F A9'
INSTRUCTION 'test ax, iw' -> '66 A9 iw'
INSTRUCTION 'test eax, id' -> 'A9 id'
INSTRUCTION 'test rax, id' -> 'REX.W A9 id'
INSTRUCTION 'vfmadd213sd xmm, xmm, xmm/m64' -> 'VEX.DDS.LIG.66.0F38.W1 A9 /r'
INSTRUCTION 'vfmadd213sd xmm, xmm, xmm/m64' -> 'EVEX.DDS.LIG.66.0F38.W1 A9 /r'
INSTRUCTION 'vfmadd213ss xmm, xmm, xmm/m32' -> 'VEX.DDS.LIG.66.0F38.W0 A9 /r'
INSTRUCTION 'vfmadd213ss xmm, xmm, xmm/m32' -> 'EVEX.DDS.LIG.66.0F38.W0 A9 /r'

$ node x86search.js FF
INSTRUCTION 'call r32/m32' -> 'FF /2'
INSTRUCTION 'call r64/m64' -> 'FF /2'
INSTRUCTION 'dec r16/m16' -> '66 FF /1'
INSTRUCTION 'dec r32/m32' -> 'FF /1'
INSTRUCTION 'dec r64/m64' -> 'REX.W FF /1'
INSTRUCTION 'fcos ' -> 'D9 FF'
INSTRUCTION 'inc r16/m16' -> '66 FF /0'
INSTRUCTION 'inc r32/m32' -> 'FF /0'
INSTRUCTION 'inc r64/m64' -> 'REX.W FF /0'
INSTRUCTION 'jmp r32/m32' -> 'FF /4'
INSTRUCTION 'jmp r64/m64' -> 'FF /4'
INSTRUCTION 'push r16/m16' -> '66 FF /6'
INSTRUCTION 'push r32/m32' -> 'FF /6'
INSTRUCTION 'push r64/m64' -> 'FF /6'

此外,还有一些命令行工具可用于快速和粗略的反汇编,但这些工具需要完整的指令(与仅有操作码字节相比),以下是一些提示:
使用LLVM项目中的llvm-mc:
$ echo "0x0f 0x28 0x44 0xd8 0x10" | llvm-mc -disassemble -triple=x86_64 -output-asm-variant=1
.text
movaps xmm0, xmmword ptr [rax + 8*rbx + 16]

使用来自nasm项目的ndisasm:

$ echo -n -e '\x0f\x28\x44\xd8\x10' | ndisasm -b64 -
00000000 0F2844D810 movaps xmm0,oword [rax+rbx*8+0x10]

同一作者还有一个AsmGrid项目。这是一个正在进行中的在线AsmDB浏览器,使用颜色来可视化每个指令的各种属性。


8

寻找操作码的快速参考是 sandpile 。 我只需要两次点击就可以查找出0xc8是什么(顺便说一下,它是 enter)。


5

Sandpile可能是您正在寻找的内容。但是,查看x86编码的最佳方法不是十六进制,而是八进制。突然之间,x86不再那么难看,并且有些讲得通了。

关于这个问题的经典解释可在1992年的Usenet alt.lang.asm上获得,然而,今天已经在github上提供。


1
嗯,有趣。x86有8个寄存器,一些操作码使用低3位来编码目标寄存器(包括inc r32dec r32xchg r32,eaxmov r32,imm32)。这使得在其他指令的编码中也自然地有3位的分组。 - Peter Cordes

3

另一种方法是使用调试器(gdb,windbg,ollydbg等)或反汇编器(IDA),然后在可写内存区域中设置字节序列。最后,在该字节序列的起始地址处进行反汇编。
这看起来很复杂,但在某些破解/反向工程的情况下非常有用。


hiew是另一个功能强大的控制台反汇编器(具有内联命令汇编的能力),完美地满足所有基本的破解需求。我建议在FAR管理器中作为二进制编辑器运行它。 - master-lame-master

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接