记录一下脱一些简单压缩壳的过程(主要是找 OEP)。

压缩壳和加密壳

  • 在理解什么是压缩壳的时候,先了解什么是壳。壳可以简单理解为就是在 PE 文件中包含了代码,而又不影响 PE 文件的执行。其中压缩壳是让 PE 文件变小的壳。在运行加了压缩壳的程序时,壳先对程序进行解压缩,然后再运行源程序。
  • 加密壳主要就是针对软件的加密保护,也有一些人用加密壳来做一些木马的免杀,导致一些杀软件查到该壳就误报病毒。加密壳的种类有很多,如果手工脱和修复,即使对高手来脱,也需要费很大力气。

压缩壳的原理(以 UPX 为例)

压缩壳将程序的 .text 段和 .data 段进行压缩,不改变 .rsrc 段,并在运行时将对应的 .text 段和 .data 段解压缩来还原程序。

使用工具

  • 调试工具:Ollydbg
  • 查壳工具:ExeInfo / PEID
  • 脱壳工具:LordPEImportRE

OD 快捷键:

快捷键 功能
F7 单步步入
F8 单步步过
F4 运行到选定位置
F2 设置断点
Ctrl+F2 重新开始
F9 运行
Shift+F9 忽略异常运行
Alt+F9 执行到用户代码

脱壳

LordPE

LordPE 用来将运行时的程序 dump 出来:

  1. 找到程序右键,修正镜像大小
  2. 完整转存

ImportREC

ImportREC 用来修复原始程序的 IAT:

  1. 找到程序,输入找到的 OEP 的值;
  2. 点击 IAT自动搜索
  3. 获取导入表
  4. 显示无效的,如果有无效的表清除即可;
  5. 修正转储

查找 OEP

压缩壳的流程清楚了,修复 IAT 的过程也有了,我们只需要找到 OEP,就能完整地脱去一个压缩壳。

单步执行法

单步执行法,通过单步执行一步一步,找到 OEP(程序入口点)。如果遇到向下的跳转则默认跳转:

遇到向上的跳转则直接执行到下一条语句,避免陷入循环,即 F4:

最后执行到 POPAD 处会有一个大范围的 JMP,即转到 OEP。

ESP 定律法(堆栈平衡法)

利用压缩前后 ESP 不变的定律。在指令 PUSHAD 时单步一下,会发现寄存器中只有 ESP 发生变化:

然后右键 ESP 的值,跟随数据窗口:

 接下来在数据窗口中选择 ESP 的值,并设置硬件访问断点,即在下次对 ESP 寄存器有读操作时被断下:

同样也可以通过 dd xxxxxxxx 或者 hr xxxxxxxx 设下硬件断点,在下方 command 处输入:

然后 F9 继续执行到 POPAD 后,删去硬件断点:

单步到 OEP。

特殊的 ESP 定律法

不遵循 ESP 不变的定律,FSG2.0 专用的方法。单步走到 POPAD 的下一条指令,观察堆栈窗口从上往下数第四个地址的值即为 OEP 的地址。右键在反汇编窗口跟随:

下硬件断点后 f9 运行,到达 OEP。

二次内存镜像法

以 UPX 为例。进入内存段中,先找到程序段的第一个 .rsrc,并设下断点后 Shift+F9 忽略异常执行,此处断下来后,压缩壳已经把所有的数据都解压缩了:

再在 UPX0 段下断,即恢复后的代码段,再重复上面的操作:

然后按照单步执行法往下走就能看到 POPAD 还有 JMP:

一步直达法

以 UPX 为例。在遇到指令 PUSHAD 后,通过经验可以判断必存在 POPAD 来恢复通用寄存器,直接 Ctrl+F 搜索指令找到 OEP:

模拟跟踪法

以 ASPack 为例。先进入内存中,找到 SFX:

在命令框输入 tc eip<xxxxxxxx(即追踪 EIP 小于指定地址时的代码,也就是程序的代码段):

会看到 OD 左上角变成了跟踪:

等待一段时间就会跳转到 OEP。

SFX 模拟跟踪法

以 ASPack 为例。进入选项->调试设置Alt+O):

一般情况选择块方式跟踪或者字节方式,这里选择前者:

确定后,重新载入(Ctrl+F2),OD 会自动地去查找到 OEP。

最后一次异常法

以 PECompact 为例。先在调试选项中忽略所有异常。重新载入后,执行 m 次 shift+f9,直到程序跑飞。然后重新载入程序,执行 m-1 次 shift+f9。在堆栈窗口中找到 SE 句柄,然后 Ctrl+G 转到 SE 句柄:

0045DE74    B8 F9CB45F0     mov eax,0xF045CBF9
0045DE79    8D88 9E120010   lea ecx,dword ptr ds:[eax+0x1000129E]
0045DE7F    8941 01         mov dword ptr ds:[ecx+0x1],eax
0045DE82    8B5424 04       mov edx,dword ptr ss:[esp+0x4]
0045DE86    8B52 0C         mov edx,dword ptr ds:[edx+0xC]
0045DE89    C602 E9         mov byte ptr ds:[edx],0xE9
0045DE8C    83C2 05         add edx,0x5
0045DE8F    2BCA            sub ecx,edx                              ; ntdll_1.7720353D
0045DE91    894A FC         mov dword ptr ds:[edx-0x4],ecx           ; qqspirit.0045DE74
0045DE94    33C0            xor eax,eax
0045DE96    C3              retn
0045DE97    B8 78563412     mov eax,0x12345678                       ; 下断点

随后执行到断点处,单步跟到 OEP。

修复

有时候脱完壳却不能运行程序,需要修复 IAT。首先载入 OD,在 OEP 往下找 Call:

找到后在命令框处输入 d xxxxxx

在数据窗口中,往上查找,直到数据为 0,记录下 IAT 地址;往下也同样:

在 ImportREC 中修改 OEP 后,不采取自动获取的方式,手动输入 IAT 起始地址和大小,偷懒的办法是大小直接输 1000:

然后清除掉无效的,转储一下得到完整程序。

参考网站

https://www.cnblogs.com/hongyuyingxiao/p/9630173.html
https://findream.github.io/2018/07/15/%E5%B8%B8%E8%A7%81%E5%A3%B3%E7%9A%84%E8%84%B1%E5%A3%B3%E6%80%9D%E8%B7%AF/
https://www.cnblogs.com/iBinary/p/7764483.html


re

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!

2018-信息安全铁人三项赛总决赛-数据赛
简单虚拟机指令类题目分析