记录一下脱一些简单压缩壳的过程(主要是找 OEP)。
压缩壳和加密壳
- 在理解什么是压缩壳的时候,先了解什么是壳。壳可以简单理解为就是在 PE 文件中包含了代码,而又不影响 PE 文件的执行。其中压缩壳是让 PE 文件变小的壳。在运行加了压缩壳的程序时,壳先对程序进行解压缩,然后再运行源程序。
- 加密壳主要就是针对软件的加密保护,也有一些人用加密壳来做一些木马的免杀,导致一些杀软件查到该壳就误报病毒。加密壳的种类有很多,如果手工脱和修复,即使对高手来脱,也需要费很大力气。
压缩壳的原理(以 UPX 为例)
压缩壳将程序的 .text
段和 .data
段进行压缩,不改变 .rsrc
段,并在运行时将对应的 .text
段和 .data
段解压缩来还原程序。
使用工具
- 调试工具:
Ollydbg
- 查壳工具:
ExeInfo
/PEID
- 脱壳工具:
LordPE
、ImportRE
OD 快捷键:
快捷键 | 功能 |
---|---|
F7 |
单步步入 |
F8 |
单步步过 |
F4 |
运行到选定位置 |
F2 |
设置断点 |
Ctrl+F2 |
重新开始 |
F9 |
运行 |
Shift+F9 |
忽略异常运行 |
Alt+F9 |
执行到用户代码 |
脱壳
LordPE
LordPE 用来将运行时的程序 dump 出来:
- 找到程序右键,
修正镜像大小
; 完整转存
。
ImportREC
ImportREC 用来修复原始程序的 IAT:
- 找到程序,输入找到的
OEP
的值; - 点击
IAT自动搜索
; 获取导入表
;显示无效的
,如果有无效的表清除即可;修正转储
。
查找 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