识别编译器产生的汇编程序中的某些组件

逆向工程 部件 编译器 反编译器
2021-06-12 17:08:54

这是我的问题:

给定一个标记的C代码组件,我如何在编译器生成的汇编程序中找到其对应的汇编指令?

如果标记的组件是一个函数应该很容易,只要没有重叠的汇编程序,我们就可以在编译器生成的代码中进行线性搜索并识别该函数。

那么标记的组件是一个循环语句呢?甚至是算术语句?这个时候有什么好的解决办法吗?

谁能给我一些帮助?谢谢!

1个回答

TL;DR:希望有一些神奇的数字,或者你可以外部参照的字符串常量,或者你需要做大量的手工工作。

搜索不包含非常具体的幻数的算术语句,或搜索没有任何周围上下文的循环,注定会失败。您的程序中有太多代码太相似了。所以你至少应该尝试找到你的函数,然后将反汇编的函数与你的源代码相匹配。

但是,您应该稍微澄清一下您的用例。你有什么?你在找什么?

例如,如果你有完整的源代码,用调试信息编译你的程序,你就拥有了你需要的一切。但这不是 RE 的问题。

或者,您拥有完整的源代码,已将二进制文件交付给客户,但出于某种原因,您希望客户修补二进制文件而不是向他们发送新版本。在这种情况下,使用相同的编译器设置重新编译相同版本的程序应该会产生一些二进制代码,除了全局变量引用和跳转目标之外,应该与您交付的二进制代码相同。比较部分字节序列应该可以解决问题,这或多或少是 IDA 的 FLIRT 和许多防病毒程序的工作方式。尽管如此,仍然不是 RE 的问题。

或者,您有一个二进制文件,并怀疑它包含一些开源库。将二进制文件与您自己编译的库版本进行比较可能对您没有帮助,因为除非您使用完全相同版本的库、编译器版本、编译器标志以及可能的月相,否则您的编译器将不会产生什么原始编译器产生。在这种情况下,幻数或字符串外部参照有时会有所帮助。例如,在这个问题中,OP 正在寻找库的哪一部分进行了一些 TEA 加密。在他的情况下,这很容易,因为他有一个带有导出符号的 .so,但如果他没有,搜索字节序列0x9e3779b9和/或0xC6EF3720可以提供帮助。这是什么binwalk做。此外,这些库通常有错误消息字符串,查找它们和它们的外部参照会将您引导到函数的编译版本。如果幸运的话,源代码中有一些assert()类似宏在发布编译期间没有被注释掉,在这种情况下,源代码和二进制文件之间的匹配非常好。

如果这不起作用,事情就会开始变得棘手。有一次当我遇到类似的问题时,我最终编写了一个 IDA 脚本,该脚本计算call每个函数语句数,以及向后跳转的次数,即循环。我在我想要重新编译的二进制文件上运行了这个,也在我正在寻找的代码上运行了这个。然后,我根据函数的调用次数、循环次数以及它们在源代码中的各自位置手动匹配函数。您可能可以尝试变得聪明并自动进行匹配,具体取决于您需要它的频率。

如果编译器优化了很多,你真的需要手动分析很多东西。如果你的函数很小,它可能会被编译器内联,你正在寻找的算术表达式突然在几十个地方重复。您的循环可能会展开,因此没有可找到的循环。

并且该软件的创建者可能已经修改了原始源,因此您无法再将其与二进制文件匹配。一年前我反转了一些软件,它从某个地方获取一些加密的 HTML 并将其呈现为位图。从二进制文件中的字符串,很容易确定该软件使用了dill进行渲染的代码。但我只是无法将二进制代码与源代码匹配 - 首先,因为我不知道使用的是哪个版本的 dillo,其次,因为他们修改了代码以根据需要即时解密,并在他们不再需要解密的 HTML 时立即用垃圾覆盖它。所以每个字符比较和每个标准字符串函数调用(可能)在源代码中被替换,然后替换被内联(或者首先是宏)。这破坏了我的循环计数、子程序调用计数和所有内容 - 我认为没有任何好的、自动化的方法来解决这种混乱。