如何编写反汇编程序?[关闭]


68

我有兴趣将x86分解器编写为一个教育项目。

我发现的唯一真正的资源是Spiral Space的“如何编写反汇编程序”。尽管这对反汇编程序的各个组件进行了很好的高级描述,但我对一些更详细的资源感兴趣。我也快速浏览了NASM的源代码,但这是一个值得借鉴的重要内容。

我意识到这个项目的主要挑战之一是我将要处理的相当大的x86指令集。我也对基本结构,基本反汇编程序链接等感兴趣。

谁能指出我编写x86反汇编程序的详细资源?


对于初学者来说,stackoverflow.com / questions / 82432 /…中的答案不是答案,而是很好的阅读。
爪子

Answers:


66

请看《80386程序员参考手册》的17.2节。反汇编程序实际上只是光荣的有限状态机。拆卸步骤为:

  1. 检查当前字节是一个指令前缀字节(F3F2,或F0); 如果是这样,那么您就有一个REP/ REPE/ REPNE/LOCK前缀。前进到下一个字节。
  2. 检查当前字节是否为地址大小的字节(67)。如果是这样,如果当前处于32位模式,则以16位模式解码指令其余部分中的地址,如果当前处于16位模式,则以32位模式解码地址。
  3. 检查当前字节是否为操作数大小的字节(66)。如果是这样,如果当前处于32位模式,则以16位模式解码立即操作数,如果当前处于16位模式,则以32位模式解码立即操作数。
  4. 检查是否当前字节的跨段字节(2E363E2664,或65)。如果是这样,请使用相应的段寄存器代替默认段寄存器来解码地址。
  5. 下一个字节是操作码。如果操作码为0F,则它是扩展操作码,并读取下一个字节作为扩展操作码。
  6. 根据特定的操作码,读入并解码Mod R / M字节,比例索引基(SIB)字节,位移(0、1、2或4字节)和/或立即数(0、1) ,2或4个字节)。这些字段的大小取决于操作码,地址大小覆盖和先前解码的操作数大小覆盖。

操作码告诉您正在执行的操作。可以从Mod R / M,SIB,位移和立即值的值解码操作码的参数。由于x86的复杂性,存在很多可能性和很多特殊情况。请参阅上面的链接以获得更详尽的说明。


2
英特尔手册说Groups 1 through 4 may be placed in any order relative to each other,因此步骤1-4的顺序可能不正确
szx 2013年

2
这对于x86是正确的,但对于x86_64或现代指令集(例如AVX / AVX2
则不适用

22

我建议您检查一些开源反汇编程序,最好是distorm,尤其是“ disOps(指令集数据库)”(在页面上按Ctrl +查找)。

文档本身包含有关操作码和指令的多汁信息。

引用 https://code.google.com/p/distorm/wiki/x86_x64_Machine_Code

80x86指令:

80x86指令分为多个元素:

  1. 指令前缀会影响指令操作的行为。
  2. 强制前缀用作SSE指令的操作码字节。
  3. 操作码字节,可以是一个或多个字节(最多3个完整字节)。
  4. ModR / M字节是可选的,有时可能包含操作码本身的一部分。
  5. SIB字节是可选的,表示复杂的内存间接形式。
  6. 位移是可选的,它是字节大小(字节,字,长)变化的值,并用作偏移量。
  7. 立即数是可选的,它用作从可变大小的字节(字节,字,长)构建的通用数字值。

格式如下:

/-------------------------------------------------------------------------------------------------------------------------------------------\
|*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中进行了说明

引用:

解码阶段

  1. [前缀]
  2. [获取操作码]
  3. [过滤器操作码]
  4. [提取操作数]
  5. [文字格式]
  6. [十六进制转储]
  7. [解码指令]

每个步骤也进行了说明。


保留原始链接是出于历史原因:

http://code.google.com/p/distorm/wiki/x86_x64_Machine_Codehttp://code.google.com/p/distorm/wiki/diStorm_Internals


1
+1这些是一些很棒的指针
爪子

2
“可选的强制前缀”看起来很有趣。
Calmarius 2012年

1
看起来链接已死
szx

6

从已经组装好的一些小程序开始,它会为您提供生成的代码和说明。为自己获取有关指令体系结构的参考,并手动处理带有体系结构参考的一些生成的代码。您会发现指令具有非常典型的inst op op op结构具有不同数量的操作数。您需要做的就是翻译代码的十六进制或八进制表示以匹配指令。稍微玩一下就会发现它。

该过程是自动化的,是反汇编程序的核心。理想情况下,您可能需要内部构造一个指令结构数组(如果程序很大,则可以在外部构造)。然后,您可以将该数组转换为汇编器格式的指令。


4

您需要从中加载操作码表。

基本的查询数据结构是一个特例,但是如果您不太在意速度,那么表就足够好了。

要获取基本操作码类型,请从表上的match开始。

有几种解码寄存器参数的常用方法。但是,有足够的特殊情况要求大多数情况下单独实施。

由于这是教育性的,因此请查看ndisasm。


2

Checkout objdump源代码-这是一个很棒的工具,它包含许多操作码表,并且它的源代码可以为制作自己的反汇编程序提供良好的基础。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.