1.4 反编译
逆向工程的一个较新的创新是使用反编译器。反编译器比反汇编器更进一步。反汇编器只是显示程序的人类可读的汇编代码,而反编译器则试图从编译的二进制文件中重新生成等价的C/C++代码。
反编译器的一个优点是通过生成伪代码显著减少和简化反汇编的输出。当快速浏览一个函数以从宏观层面上了解程序正在执行什么操作时,这可以使阅读更加容易。
当然,反编译的缺点是在这个过程中可能会丢失重要的细节。此外,由于编译器在从源代码到可执行文件的转换过程中本身是有损失的,因此反编译器不能完全重建原始源代码。符号名称、局部变量、注释以及大部分程序结构在编译过程中会被破坏。同样,如果存储位置被积极优化的编译器重复使用,那么试图自动命名或重新标记局部变量和参数的做法也会产生误导。
让我们看一个C函数的例子,使用GCC编译它,然后用IDA Pro和Ghidra的反编译器进行反编译,以显示实际的情况。
图1.7显示了Linux源代码库中ihex2fw.c[6]文件中一个名为file_record的函数。
在Armv8-A架构上编译C文件(没有任何特定的编译器选项)并将可执行文件加载到IDA Pro 7.6中后,图1.8显示了由反编译器生成的file_record函数的伪代码。
图1.9显示了Ghidra 10.0.4对同一函数的反编译输出。
在这两种情况下,如果我们仔细观察,便可以看到原始代码的影子,但是这些代码远不如原始代码易读和直观。换句话说,虽然在某些情况下反编译器可以为我们提供程序的高层次概述,但它绝不是万无一失的,也无法替代深入研究给定程序的汇编代码。
图1.7 ihex2fw.c源文件中file_record函数的源代码
图1.8 IDA Pro 7.6对编译后的file_record函数的反编译输出
图1.9 Ghidra 10.0.4对编译后的file_record函数的反编译输出
话虽如此,反编译器在不断发展,并且越来越擅长重构源代码,特别是对于简单的函数。虽然,使用你想在更高层次上进行逆向工程的函数的反编译器输出是一个有用的辅助,但是当你想要更深入地了解正在发生的事情时,请不要忘记查看反汇编输出。
[1]Planning a Computer System, Project Stretch, McGraw-Hill Book Company, Inc., 1962. (http://archive.computerhistory.org/resources/text/IBM/Stretch/pdfs/Buchholz_102636426.pdf)
[2]http://ftp.gnu.org/old-gnu/Manuals/gas-2.9.1/html_chapter/as_7.html
[3]https://web.mit.edu/gnu/doc/html/binutils_5.html
[4]https://ghidra-sre.org
[5]https://hex-rays.com/ida-pro
[6]https://gitlab.arm.com/linux-arm/linux-dm/-/blob/56299378726d5f2ba8d3c8cbbd13cb280ba45e4f/firmware/ihex2fw.c