我想找到一种方法来提高我的拆包技能,我不是菜鸟,但我想念从简单到硬包装的步骤。
我看过很多视频教程,大部分时间我都会看到“单击 F9 x 次以达到 OEP”或“ESP 技巧”而没有按照我的意愿深入。我发现学习过程以这种方式缓慢。
我正在寻找论文或书籍以深入了解这门艺术,我的目标是能够以最佳方式面对恶意软件分析。
请指教,谢谢
我想找到一种方法来提高我的拆包技能,我不是菜鸟,但我想念从简单到硬包装的步骤。
我看过很多视频教程,大部分时间我都会看到“单击 F9 x 次以达到 OEP”或“ESP 技巧”而没有按照我的意愿深入。我发现学习过程以这种方式缓慢。
我正在寻找论文或书籍以深入了解这门艺术,我的目标是能够以最佳方式面对恶意软件分析。
请指教,谢谢
没有一篇论文或一本书可以解释拆包的艺术。这主要是由于所有不同的包装工需要不同的技术来打开它们。当然有一些通用方法适用于一些加壳器,但知道何时使用它们是从经验中获得的。恕我直言,学习解包的最佳方法是在调试器中跟随解包。我最喜欢的拆包作者是Haggar. 一旦您完成了一些教程,您将观察到指令和 API 序列的模式。一旦你看到这些模式,你应该尝试使用你之前学到的东西来解压样本。如果失败,您可以继续本教程,如果成功,您可以继续下一个教程。无论哪种方式,您都可以学习新事物或应用以前获得的知识。从长远来看,它将帮助您解压恶意软件。
拆包是一门艺术,因此没有明确的步骤来拆包任何目标。
几年前我遇到过你的情况。我理解汇编、代码注入和钩子等,但我无法理解解包。
关键是要分析地进行拆包。您有一个状态 A,它是一个(可能!)打包的可执行文件,并且您有一个所需的状态 B,其中包含您可以在例如 IDA 中分析的代码。您想找到状态切换发生的位置。
这听起来很一般,那是因为它是。尤其是在恶意软件解包中,代码解包时并不总是 100% 清晰。有时没有解压的二进制文件,而是注入的shellcode。有时你会得到 3 个解包阶段。
那么,这没有帮助。这就是为什么您从非常简单的方法开始学习模式的原因。
这就是你提到的ESP技巧发挥作用的地方。这是一个通常允许您跳过代码的技巧。通常,解包存根被 pushad/popad 包围,以免在实际代码运行之前污染环境。这是一种需要学习的模式——从保存执行状态开始(或多或少)——所以我们对之后发生的事情很感兴趣。
另一个想法:PE 可执行文件有一个标头。那么如果某个解包器对目标代码进行解包,它是否会恢复原始标头?答案出人意料地是肯定的!太好了,因为现在我们可以只观察标题的变化并且接近代码的最终形式。这可以通过在头中的某些字段上设置写入时的硬件断点来完成 - 例如 AddressOfEntryPoint,因为这是我们想知道的!
然后是所谓的 RunPE 加壳器(现在也称为“进程挖空”)——他们打破了解包的概念,就像在一个小存根中重建原始可执行文件,而是创建一个新的(可能不相关的)进程,然后将该新进程重写为原始二进制文件的状态。
那么我们如何处理呢?我们关注使用的 API。我们观察 CreateProcess(CREATE_SUSPENDED),观察 WriteProcessMemory,观察 ResumeThread。当然,有几十种变体(ZwWriteVirtualMemory、ZwResumeProcess、ZwCreateProcess 等)但关键步骤是相同的:创建一些新进程,修改它,恢复执行。
然后有一些例子本身根本不适合一个方案——如何处理它们?遵循他们的代码流程!一直看,直到看到可以使用的东西。有时你会从 WriteProcessMemory 得到一些转储的 shellcode,但那是“最终”阶段 B,没有别的。
这是一个很长的答案,但我的观点是:解包很简单 - 打包的代码转换为解包的代码。这些步骤之间没有什么神奇之处,因此请遵循代码并跳出框框思考。
有时,您只需要在 VirtualFree() 上设置一个断点即可捕获被释放的解压代码。有时您只需要在 VirtualAlloc() 上设置一个断点并观察那里写的内容。通过考虑状态 A 和 B 之间可能发生的事情,您会发现可以这么说的“伏击”解压代码的点。
这个答案主要适用于 Linux,因为那是我做大部分 RE 的地方。我认为您也可以将它用于 Windows。
首先,我假设没有应用反调试或反仿真技巧。这是我将如何解决这个问题。我的最终目标是尝试找到 OEP。我会尝试在 VM 中运行二进制文件,也许尝试使用 strace/procmon 看看它做了什么。例如:- 也许它从寄存器中读取一个值或尝试查看文件是否存在。如果是这样,我尝试调试二进制文件,捕获从注册表/文件读取的系统调用并查看进程映射。从这里我尝试推断,内存映射的哪些部分属于解包进程。此时,我再次尝试从程序的开始调试,试图达到OEP。通常,在执行所有这些操作时关闭 ASLR 是个好主意。
如果存在反调试技巧,不用说,熟悉和了解这些技巧会给您带来优势,因为您可以相对轻松地发现它们。
其他 RE 技巧,例如将区域的保护更改为 NX,以便在尝试执行时发生访问冲突;或者用 0xcc 淹没一个区域,以便在尝试执行它时发生 SIGTRAP 也可能很有用。
希望这可以帮助。