以通用方式解压二进制文件

逆向工程 反编译 开箱 聚乙烯
2021-06-22 00:37:16

我发现越来越多的二进制文件被 exe 保护程序打包,例如 upx、aspack 等。我尝试遵循一些关于如何解压缩它们的教程,但示例通常很容易,而我的目标则不然。

我正在寻找好的资源以及有关如何解压缩目标的任何提示/技巧。

3个回答

解包通用包装器或加密器通常涉及以下步骤:

1. 跟踪代码,可能会逃避或绕过反调试检查。

这对于简单的打包程序来说并不困难,但对于更高级的打包程序可能会很棘手。它们可能会使用时序检查 ( rdtsc)、基于异常的控制传输、使用调试寄存器进行计算等。在这里使用 VM 或仿真器通常有助于对抗其中的大多数。

2. 找到原始入口点(OEP)

有很多方法可以做到这一点。有时,当它跟随一大块循环代码并且没有任何合理的关注时,跳转到 OEP 是显而易见的。或者,如果您熟悉不同编译器生成的入口点,您可能会认出 OEP 中的代码。其他几个技巧:

  1. 如果打包程序在解包之前保存了原始寄存器,请在它们在堆栈中的位置设置一个硬件断点 - 这样您就可以在跳转到 OEP 之前恢复它们时立即中断。

  2. 如果在跟踪期间您可以识别正在写入解包代码的内存,请在该内存范围内设置页面执行断点 - 它将在跳转后触发。IDA 允许你设置这样的断点,我认为 OllyDbg 也是如此。

  3. 在启动代码使用的常见 API 上设置断点,例如GetCommandLineGetVersionEx这不会让您获得确切的 OEP,但您通常可以返回调用堆栈并或多或少地轻松找到它。

3. 转储解压后的代码

如果您使用的是 IDA,则实际上不需要将文件转储到单独的文件中 - 拍摄内存快照就足够了,将字节从内存复制到数据库,以便您稍后分析它们。这里要记住的一件事是,如果打包程序使用动态分配的内存,则需要将其标记为“加载程序”,以便将其包含在快照中。更多在这里

4. 恢复进口

我不是很熟悉它是如何在 Olly 或其他调试器中完成的,但是 AFAIK 您需要在转储中使用 ImpREC 之类的工具,并在内存中使用该进程的副本。

在 IDA 中它更简单(IMO)。您只需要找到导入表并根据指针当前指向的函数重命名指针(这应该在调试器处于活动状态时完成)。您可以使用renimp.idc脚本或 UUNP“手动重建功能”(请参阅此处)。

为了查找导入表,我有时会使用两个技巧:

  • 在 OEP 的启动代码中进行一些调用以查找外部 API,这将引导您进入导入表。通常表的开始和结束是显而易见的。

  • 在解包过程中,在 GetProcAddress 上设置断点并查看结果写入的位置。但是,这不适用于使用导出目录手动导入结果的打包程序。将读取 BP 放在 kernel32 的导出表上可能会有所帮助。

5. 清理

这是可选的,但它可能有助于删除只会分散您注意力的打包程序代码的剩余部分。在 IDA 中,如果您识别使用的编译器,您还应该应用编译器 FLIRT 签名。

6. 制作一个解压的可执行文件

我不执行此步骤,因为我很少需要运行解压文件,但通常您通常需要修复 PE 标头,以便文件中该部分代码的偏移量与转储中的偏移量相匹配。


现在,上面的步骤没有涵盖许多变化和技巧。例如,一些加壳器最初并没有完全解析导入,而是跳转到在第一次调用时解析导入的存根,然后修补它,以便下次直接进入目标。然后是“被盗代码”方法,这使得查找和恢复 OEP 变得更加困难。有时,打包程序会运行自己的副本并对其进行调试,因此您无法将自己的调试器附加到它(这可以通过使用模拟器或不使用调试 API 的调试器(如英特尔 PIN)来解决)。尽管如此,概述的步骤可以涵盖相当多的内容。

我将以 Elias 制作的视频结束,该视频展示了打开 Lighty Compressor 的过程:https : //www.hex-rays.com/video/bochs_video_2.html

伊戈尔的回答非常好。然而,概述的技术依赖于这样的假设,即在某个时候可执行文件在内存中解压缩。这并不总是正确的当由模拟器在运行时执行时,虚拟化混淆器将原始二进制文件编译成自定义指令集。如果您遇到以这种方式混淆的二进制文件,您别无选择,只能从自定义指令集编写反汇编程序到您理解的指令集。

Blackstorm 门户有大量开箱教程 Blackstorm 门户教程

Tuts4You 还有一大堆开箱教程 Tuts4You

一开始我花了很长时间,但随着时间的推移,打开包装变得容易多了,但需要很多耐心和练习。