我有兴趣将 x86 dissembler 编写为一个教育项目。
我找到的唯一真正的资源是 Spiral Space 的“如何编写反汇编程序”。虽然这对反汇编程序的各种组件进行了很好的高级描述,但我对一些更详细的资源感兴趣。我还快速浏览了NASM 的源代码,但这有点值得学习。
我意识到这个项目的主要挑战之一是我将不得不处理相当大的 x86 指令集。我也对基本结构、基本反汇编链接等感兴趣。
任何人都可以向我指出有关编写 x86 反汇编程序的任何详细资源吗?
查看80386 Programmer's Reference Manual 的第17.2 节。反汇编器实际上只是一个美化的有限状态机。拆解步骤如下:
F3
、、F2
或F0
);如果是这样,那么你有一个REP
// REPE
/前缀REPNE
。LOCK
前进到下一个字节。67
)。如果是这样,如果当前处于 32 位模式,则以 16 位模式解码指令其余部分中的地址,或者如果当前处于 16 位模式,则以 32 位模式解码地址66
)。如果是这样,如果当前处于 32 位模式,则以 16 位模式解码立即操作数,或者如果当前处于 16 位模式,则以 32 位模式解码立即操作数2E
、36
、3E
、26
、64
或65
)。如果是这样,请使用相应的段寄存器而不是默认的段寄存器来解码地址。0F
,则为扩展操作码,读取下一个字节作为扩展操作码。操作码告诉您正在执行的操作。操作码的参数可以从 Mod R/M、SIB、位移和立即值的值中解码。由于 x86 的复杂性,存在很多可能性和很多特殊情况。有关更详尽的说明,请参阅上面的链接。
我建议查看一些开源反汇编程序,最好是distorm,尤其是“disOps(指令集数据库)”(ctrl+在页面上查找)。
文档本身充满了关于操作码和指令的丰富信息。
引用自 https://code.google.com/p/distorm/wiki/x86_x64_Machine_Code
80x86 指令:
一条 80x86 指令被划分为多个元素:
- 指令前缀,影响指令操作的行为。
- 强制前缀用作 SSE 指令的操作码字节。
- 操作码字节,可以是一个或多个字节(最多 3 个完整字节)。
- ModR/M 字节是可选的,有时可能包含操作码本身的一部分。
- SIB 字节是可选的,表示复杂的内存间接形式。
- 位移是可选的,它是一个不同大小的字节(字节,字,长)的值,用作偏移量。
- 立即数是可选的,它用作从不同大小的字节(字节、字、长)构建的通用数值。
格式如下所示:
/-------------------------------------------------------------------------------------------------------------------------------------------\ |*Prefixes | *Mandatory Prefix | *REX Prefix | Opcode Bytes | *ModR/M | *SIB | *Displacement (1,2 or 4 bytes) | *Immediate (1,2 or 4 bytes) | \-------------------------------------------------------------------------------------------------------------------------------------------/ * means the element is optional.
https://code.google.com/p/distorm/wiki/diStorm_Internals中解释了数据结构和解码阶段
引用:
解码阶段
- [前缀]
- [获取操作码]
- [过滤操作码]
- [提取操作数]
- [文本格式]
- [十六进制转储]
- 【解码指令】
还解释了每个步骤。
由于历史原因,保留原始链接:
http://code.google.com/p/distorm/wiki/x86_x64_Machine_Code和http://code.google.com/p/distorm/wiki/diStorm_Internals
从一些已经组装好的小程序开始,它会为您提供生成的代码和指令。为自己获取指令架构的参考,并通过架构参考手动完成一些生成的代码。您会发现指令具有非常典型的inst op op op结构,具有不同数量的操作数。您需要做的就是翻译代码的十六进制或八进制表示以匹配指令;稍微玩一下就会发现。
该过程是自动化的,是反汇编程序的核心。理想情况下,您可能希望在内部(或在外部,如果程序非常大)构建指令结构数组。然后,您可以将该数组转换为汇编格式的指令。
您需要一个操作码表来加载。
基本的查找数据结构是 trie,但是如果您不太关心速度,则表会做得很好。
要获取基本操作码类型,请从表上的匹配开始。
有几种解码寄存器参数的常用方法;但是,有足够多的特殊情况需要单独实施其中的大部分。
由于这是教育性的,请查看 ndisasm。
检查 objdump源- 这是一个很棒的工具,它包含许多操作码表,它的源可以为制作自己的反汇编程序提供一个很好的基础。