6 反汇编二进制文件

6 反汇编二进制文件
foresta.yang反汇编二进制文件
已经了解了如何编译二进制文件,那么让我们来看一下编译汇编阶段生成的对象文件内容。之后,我将会反汇编二进制可执行文 件,显示可执行文件内容与对象文件的内容有何不同。
查看对象文件
使用objdump实用程序来展示如何进行反汇编。objdump是一个简单、易用的反汇编程序,包含在大多数Linux发行版中,非常适合快速了解二进制文件中包含的代码和数据。


此处,调用了objdump两次。
第一次,在 ❶处,调用objdump显示.rodata节的内容。.rodata节代表的是“只 读数据”,二进制文件中所有的常量都存储在该节,包括“Hello, world!”字符串。注意,.rodata节的内容是由 ASCII编码的字符串组成的,显示在左侧的输出中。在右侧,你可以看到相同字节的可读表示。
第二次在❷处调用objdump,以Intel语法反汇编对象文件的所有代码。正如你所看到的,结果仅包含main函数❸的代码,因为这是源文件中定义的唯一函数。大多数情况下,输出与先前由编译阶段生成的汇编 代码非常接近,它采用了一些汇编级宏。有趣的是,指向“Hello, world!”字符串的指针在❹处被置零。使用puts将字符串输出到屏幕的后续调用❺也指向无意义的位置,偏移19,在main函数的中间位置。
这是因为对象文件中的数据和代码引用尚未完全解析,因为编译器不知道最终文件加载的基址。这就是为什么在对象文件中尚无对puts调用的正确解析。对象文件正在等待链接器为此引用填充正确的值。可以通过readelf显示对象文件中存在的所有重定位符号来确认这一点,

在❶处的重定位符号告诉链接器应该解析对字符串的引用,使其指向在.rodata节中结束的任意位置。相似地,在❷处的重定位符号告诉链接器应该解析对puts的引用。
检查完整的二进制执行体
从带有符号的二进制文件示例开始,然后再到已剥离的相同文件,看看反汇编后的输出差异。从objdump输出可以看到,反汇编的对象文件和二进制文件之间存在巨大差异。



可以看到二进制文件比对象文件有更多的代码。其中不再只是main函数,甚至不再只是单个代码节。二进制文件现在有多个节了, 如.init❶、.plt❷以及.text❸等。这些节均包含函数的代码,如程序初始化或者用于调用共享库的存根(stub)。
.text节是主要代码节,其中包含main函数❹,还包含许多其他函数,如_start,这些函数负责为main函数等设置命令行参数、运行时环境以及在main之后进行清理之类的任务。这些函数被称为标准函数,存在于GCC生成的任何ELF二进制文件中。

反汇编剥离的二进制文件尽管仍然可以清楚地区分不同的节(标记为❶、❷和❸),但所有函数都已合并成一大段代码。_start函数从❹处开始,而deregister_tm_clones函数从❻处开始。main函数从❼处开始,到❽处结束,但是在所有这些情况下,没有什么可以指示这些标记的指令代表函数的开始。唯一的例外是.plt节中的函数,它们的名称仍然和以前一样,如你在❺处对 _libc_start_main的调用中所看到的。