我正在学习x86汇编编程。所以我开始了解gdb,objdump和IDA pro,这些是从二进制文件创建汇编的程序。我想知道他们如何从二进制文件创建程序集?当我在记事本中打开二进制文件时,它会显示很多符号,数字和字母。我怀疑他们是如何从已编译的二进制文件创建程序集的?
答案 0 :(得分:2)
程序集(大致)与机器代码 1 有1:1的对应关系,因此根据原则,没有什么太复杂的反汇编:一旦你有一块机器代码和地址在哪里必须加载,您从第一条指令开始并开始解码。
在RISC架构上,这项工作通常更容易,因为机器指令通常具有固定大小,通常非常规则 - 例如,“经典”ARM和PowerPC使用固定大小的32位指令,其中部分位指定汇编指令,参数等。在x86上,情况有点复杂,因为它是一个可变长度的指令集,并且因为它随着时间的推移不规则地进化。
通常,汇编指令由前缀的一个或多个字节组成(可以转换回汇编前缀,如rep
或lock
,指定指令是对默认的不同段或不同大小的数据进行操作,或者完全选择不同的子指令集 - 参见例如VEX前缀),一个操作码(指定指令的字节加上可能的部分参数),接下来是参数(有一些有规律的编码来指定immediates,寄存器或存储器操作数,以及它们的各种寻址模式)。有关常规x86指令格式的更详细说明,请参阅this nice diagram(以及一般该站点)。
一旦它解码了指令,反汇编程序必须解析相对地址/跳转(将它们应用到代码中的当前位置)并发出相应的程序集,可能为跳转目标组成标签名称(或者只是离开跳转目标为普通地址)。
现在,这只是低级部分,这是“原始”反汇编程序(如ndisasm
)可以执行的操作。但是,除了特殊情况(例如MS-DOS中的COM文件)之外,可执行文件不仅仅是CPU要执行的原始代码,而且是更加结构化的二进制格式。
通常,可执行文件包含多个部分,可以包含不同类型的数据。通常有一个汇编代码的部分(通常命名为.text
),以及程序数据的几个部分(可变和不可变,零初始化,合并资源,......)以及加载器的其他附件信息,例如动态链接库和重定位信息的依赖关系。更复杂的可执行检查工具(例如objdump,nm或dumpbin)可以解析可执行格式,解码它们的结构,并且 - 如果请求 - 反汇编它在代码段中找到的代码。
除此之外,像IDA这样的工具增加了一些智能 - 它们解析可执行格式,部分执行加载器的工作(将重定位应用到代码中),反汇编代码并对其执行大量分析 - 它尝试遵循代码流,传播类型信息(如果可用)(通常从OS API开始,其入口点众所周知),检查全局数据的访问模式以推断其类型,...
je
/ jz
)之间的区别显然也会丢失 - 反汇编程序通常只会在解码操作码时发出一个可能的同义词。 答案 1 :(得分:1)
更简洁的答案是,IDA Pro是一种递归下降"工具。这意味着,在识别二进制标题和节之后,它开始从文本段的开头(更具体地,在入口点)反汇编代码。接下来,它将开始跟随分支,以递归方式递减代码,尝试识别并遵循这些分支,而不是简单地假设代码从文本段的开头顺序排列。
这非常非常好,并且不像线性反汇编那样容易混淆,但它仍然不能通过跳转表和其他动态计算的分支来跟踪分支。