case 0x00: case 0x01: case 0x02: case 0x03:
case 0x08: case 0x09: case 0x0A: case 0x0B:
case 0x10: case 0x11: case 0x12: case 0x13:
case 0x18: case 0x19: case 0x1A: case 0x1B:
case 0x20: case 0x21: case 0x22: case 0x23:
case 0x28: case 0x29: case 0x2A: case 0x2B:
case 0x30: case 0x31: case 0x32: case 0x33:
case 0x38: case 0x39: case 0x3A: case 0x3B:
{
Instruction->Opcode = *currentCode;
Instruction->dFlag = (*currentCode >> 1) & 1;
Instruction->wFlag = (*currentCode) & 1;
sprintf(mnemonic, ArithmeticMnemonic[(*currentCode >> 3) & 0x1F]);
currentCode++;
currentCode = ParseRegModRM(currentCode, Instruction, operand1, operand2);
break;
}
00401000 > - 70 FE jo short 00401000 0111 [000]0
00401002 - 72 FE jb short 00401002 0111 [001]0
00401004 - 74 FE je short 00401004 0111 [010]0
00401006 - 76 FE jbe short 00401006 0111 [011]0
00401008 - 78 FE js short 00401008 0111 [100]0
0040100A 7A FE jpe short 0040100A 0111 [101]0
0040100C - 7C FE jl short 0040100C 0111 [110]0
0040100E - 7E FE jle short 0040100E 0111 [111]0
00401011 - 71 FE jno short 00401011 0111 [000]1
00401013 - 73 FE jnb short 00401013 0111 [001]1
00401015 - 75 FE jnz short 00401015 0111 [010]1
00401017 - 77 FE ja short 00401017 0111 [011]1
00401019 - 79 FE jns short 00401019 0111 [100]1
0040101B 7B FE jpo short 0040101B 0111 [101]1
0040101D - 7D FE jge short 0040101D 0111 [110]1
0040101F - 7F FE jg short 0040101F 0111 [111]1
case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77:
case 0x78: case 0x79: case 0x7A: case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F:
{
Instruction->Opcode = *currentCode;
sprintf(mnemonic, "%s", *currentCode & 1 ? JnxxMnemonic[(*currentCode >> 1) & 7] : JxxxMnemonic[(*currentCode >> 1) & 7]);
currentCode++;
sprintf(operand1, "short %X", Instruction->LinearAddress + *((char*)currentCode) + currentCode - Code + 1);
currentCode++;
break;
}
后面可以看到一些反汇编引擎使用的表格设计,添加表项内容的“努力”不会比写这样的代码简单到哪里去。这里还需要说明的是第四部分总结的“规律”其实在Intel 64 and IA-32 Architectures Software Developer's Manual 2B Instruction Set Reference 的附录B中都有官方定义,而且B中总结地更全面(这里为前面的无知羞愧一下)。
8.2 查表
汇编/反汇编过程就是一个查表过程,这里不同的汇编/反汇编程序使用的方式各不相同。但是所有的指令表都来自于官方定义的那几张表格,我学习了这些怪异的表格(要说效率性,intel把这张表设计得很高;说指令信息的完整性,无疑这些表最全;说指令范围,这些表覆盖了intel所有已定义和尚未定义的指令,但是这些的代价就是表格的诡异,把这些表格用通用的数据结构表示,是对数据结构设计的很好的考验),下面我把相关部分Intel 64 and IA-32 Architectures Software Developer's Manual 2B Instruction Set Reference附录A 总结(翻译)一下:
如果要写一个反汇编引擎,Intel 64 and IA-32 Architectures Software Developer's Manual 2B Instruction Set Reference的附录A和B是必须完整地学习和了解的。水平有限(intel手册上讲解得更专业明白),我就不再多指手划脚了。感兴趣的朋友看官方手册能更明白。
8.3 “好”的反汇编引擎
从机器码到汇编指令助记格式不是一个太难得过程(可能需要一些时间编码),但是打造一个“好”的反汇编引擎可能需要花费些心思,我理解的“好”如下:
(1)能反编译个中各种CPU模式及子模式下的代码:IA-32, IA-32E(64位和兼容模式)。为了过程的简化(其实是水平有限)在过去的一些总结报告中我并没有提到IA-32E的两种子模式,这部分的知识官方手册Instruction Set Reference A上讲解得很明白。一个完整的反汇编引擎是必须首先考虑到这些模式问题的。
(2)效率高,绝对不能使“搜索”表。汇编(此法分析以后)和反汇编过程有相同性,指令表信息冗余小。
(3)解析的结果中能包含所有的信息(指令各部分的值,各部分的属性等等),并能提供不同格式的反汇编串(intel格式AT&T等)。
重要:
由于这只是本人水平有限,而且这只是在学习过程中的一些总结,肯定有很多描述不准确的地方,有问题请大家及时纠正。这些总结请结合前辈的一些教程(sivn, luocong, art of disassembly)来看,希望对那些对指令格式感兴趣的朋友入门能有些帮助。编写完整的反汇编引擎或虚拟机引擎,强烈建议认真学习官方手册。最后,欢迎大家批评讨论。