初识 Windows 下的 upx 脱壳

我对逆向还是了解得很少,因为要准备最近的考试才打算学学逆向,但在学习的过程中发现逆向也很有意思。

0x00 upx 脱壳

以往只在做 Pwn 题的过程中看到 Linux 下的 upx 壳,使用 upx -d file 命令往往就能把壳脱掉,但最近试着做 WIndows 下的逆向题,发现 upx 脱壳似乎还不是一行命令就搞定的事情,于是开始查资料学习。

0x01 逆向的一般步骤

  1. 寻找原始 OEP
  2. dump 内存到文件
  3. 修复文件

寻找原始 OEP

当程序加壳之后,壳会修改程序入口点,会先执行壳代码,会将原程序的入口点隐藏。我们把原程序的入口点称为原始 OEP。

简单记录一种寻找原始 OEP 的方法——平衡堆栈法(又称 ESP 定律,技巧法)。平衡堆栈法是最著名最常用的脱壳方法,其核心思想是利用堆栈平衡原理,在程序进入 OEP 时需恢复栈,从而回到断点。这一方法对于学过 Pwn 的选手来说还是比较基础的,就不多说了。

dump 内存到文件

dump 的目的是将内存内容保存到本地文件后进行静态分析。

修复文件

首先要了解一下 IAT(导入地址表),IAT 是 Windows 下 exe 文件格式中的一个字段,描述的是导入信息函数地址。它在文件中是一个 RVA 数组,在内存中是一个函数地址数组。

修复 IAT 是脱壳中比较重要的一步,不论是压缩壳还是加密壳,在脱壳过程中都需要修复 IAT,因为脱壳时会将内存中的数据转储(dump)到本地,保存成文件,而 IAT 在文件中是一个 RVA 数组,在内存中是一个函数地址数组,所以需要将转储出来的文件中的 IAT 修复成 RVA 数组的形式,这样程序才算是恢复。

0x02 实例

以 buu 上的逆向题目“新年快乐”为例。已知其加了 upx 壳,用 OllyICE 打开它。

image-20200718061118906

寻找原始 OEP

通过 ESP Law,可以很容易地找到原始 OEP。首先按 F7(或 F8)单步执行程序,此后寄存器会发生变化。

image-20200718063137215

在寄存器窗口中右键 ESP 的指向,选择在数据窗口中跟随,最后打下硬件访问断点。

image-20200719042452217

image-20200719042527211

接着按 F9 运行程序,可以看到反汇编窗口中有一条 jmp 指令,其跳向的地址就是我们要找的原始 OEP。

image-20200718064051783

dump 内存到文件

将程序执行到原始 OEP,再 dump 内存到文件。这里我使用的是 Scylla_v0.9.8。

image-20200719042858084

修复文件

同样使用 Scylla_v0.9.8 进行文件修复。

image-20200719043143279

最终会获得 新年快乐_dump_SCY.exe 文件,即为修复完毕的 dump 文件。使用 IDA 打开它,可以看到文件修复成功。

image-20200719043533775

0x03 参考资料

2019-2020 @lukbash