常见的脱壳思路

前言

         去年暑假,学习了如何脱壳,但是没有深入的了解这一块的知识,现在花费差不多三天的时间总结一下。

UPX壳

单步法

         程序流程不断向下,然后遇到POPAX,接着一个段间跳转后,直达EOP。

  • 不断向下寻找EOP
  • 使用LoadPe转储文件
    • 1)右键修正镜像大小
    • 2)完整转储文件
  • 利用导入表修复工具去修复导入表
    • 1)修改EOP
    • 2)自动搜索
    • 3)获取输入表
    • 4)显示无效函数
    • 5)修复转储文件

ESP定律法

         程序在运行真正代码前会解密已经压缩过的代码,解压程序将一些关键代码数据压栈,解压完成后,解压程序在将这些代码出栈。在压栈出栈处下硬件断点,如果执行,程序必定断在解压完成后的代码前。这就是ESP定律法,主要利用程序运行中,栈指针保持平衡。

  • 寻找使用ESP寄存器变化的代码,寻找ESP对应的内存地址,然后在地址上下硬件断点(dd,hr)。
  • f7跑起来,到达段间跳转
  • 单步一下直达EOP
  • 利用上一步脱壳的方法脱壳。

二次内存镜像法

         第一次将断点设置在代码段reloc资源节区是为了让加壳程序执行完解压过程,第二次将断点设置在代码段是为了寻找EOP。

  • 在代码段的资源节区设置在访问上设置中断(内存访问断点)
  • 在代码段的text代码节区设置内存访问断点
  • 直达EOP
  • 脱壳

一步直达法

         这个方法适用于UPX和部分北斗的壳,这部分壳在压缩的时候,使用了POPAP和PUSHAP这两个指令。

ASPACK壳

单步法

ESP定律法

二次内存镜像法

一步直达法

模拟跟踪法

         针对ASPACK壳

  • 寻找含有SFX节区的节区,记录其地址xxxxx
  • 命令下输入tc eip< xxxxxx

SFX法

  • 设置调试器SFX选项,设置成第二项:块方式跟踪到真正入口点(也有可能是第三个选项)

NSPACK

         NSPACK又名北斗,是病毒木马经常使用的压缩壳,本身使用vc写的。跳入oep的特征是:

1
2
3
popad
popfd
jmp xxxxxxxxx

单步法

ESP定律法

二次内存镜像法

         注意,在使用这个方式的时候,由于NSPACK没有压缩资源,也就是没有资源节区,所以直接在text节区下断即可!

一步直达法

模拟跟踪法

SFX法

FSG壳

单步法

ESP定律法

适用于FSG的特殊方法

         运行完popad后,寻找堆栈窗口第四个参数,那个就是oep。

修复FSG造成的导入表丢失问题

         在完成之前的修复后,发现还是无法运行程序,可以考虑修复导入表信息。

  • 寻找一个导入函数
  • 前后都是空的,说明这是导入表信息
  • 在IAT fix中修复,修改RVA和尺寸

PECompact2.X

单步法

         这个壳用了一个巧妙的方法,把它解压代码放入异常处理例程中了,我们直接跟入处理例程,程序会自动回到用户领空。

ESP定律法

BP VirtualFree法1

         这个方法利用了是解密解压缩过程中,需要对内存进行释放。在此下断的好处是能够在程序解压缩之后断下。

  • BP VirtualFree下断点
  • shift+f9,忽略异常运行(存在异常)
  • 取消断点,返回到用户领空
  • 搜索命令:push 8000
  • F4运行到此处,单步即可

BP VirtualFree法2

         第一次做代码的恢复,第二次更想是IAT的导入。

  • BP VirtualFree下断点
  • 使用两次shift+F9
    • 第一次
    • 第二次
  • 取消断点
  • 返回用户空间
  • 单步

bp VirtualAlloc法1

         在为解压出来的代码分配内存空间,所以可以对VirtualAlloc下断。

  • bp VirtualAlloc
  • shift+F9
  • ALT+F9返回用户代码
  • 单步

PECompact使用的特殊方法(1)

  • 看程序原始入口点

    1
    5.0040A86D > B8 74DE4500 mov eax,qqspirit.0045DE74
  • bp 45DE74 下断

  • 单步

最后一次异常法

         假设程序在第m次运行跑飞,我们查看第m-1次的堆栈情况。

  • 把所有忽略异常取消
  • shift+F9运行程序
  • 取m-1次的堆栈里面的SE函数
  • 在SE函数开始处下断。
  • 单步

EZIP壳

单步法

ESP定律法

修复文件

  • 和上述一样操作
  • 重新寻找新的RVA和大小
  • 利用LoadPE进行PE合并

tElock 0.98b1壳

最后一次异常法

         加壳程序通常在程序执行的开始部分采用SEH技术进行异常的处理为了获取程序控制权,而最后一次异常是为了将程序控制权交给程序本身,这就是最后一次异常法的基本原理。需要注意一下方面:

  • 除了关闭调试器的异常选项,还有关闭插件StrongOd的异常选项
  • 如果在SE句柄函数下断后,一直断不了的话,可以使用SHIFT+F9断下。

模拟跟踪法

  • 利用最后一次异常法
  • 使用模拟跟踪法
    • 内存中找SFX段,记录段地址xxxxx
    • 输入tc eip<xxxxx

两次内存镜像法

exe32pack壳

ESP定律法

WinUpack壳

单步法

         这个壳有个特点:程序在完成代码的解压后,并不直接进入oep,而是执行完IAT的重构后,跳转到判断是否完成IAT重构的判断中,然后执行是否跳转OEP。

  • 根据跳转的条件判断:eax==0的时候跳转成功。设置条件断点即可!!

常见语言的入口点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
常见语言的入口点:
VB:
004012D4 > 68 54474000 push QQ个性网.00404754
004012D9 E8 F0FFFFFF call <jmp.&MSVBVM60.#100>
004012DE 0000 add byte ptr ds:[eax],al
004012E0 0000 add byte ptr ds:[eax],al
004012E2 0000 add byte ptr ds:[eax],al
004012E4 3000 xor byte ptr ds:[eax],al
004012E6 0000 add byte ptr ds:[eax],al
004012E8 48 dec eax
delphi:
004A5C54 > 55 push ebp
004A5C55 8BEC mov ebp,esp
004A5C57 83C4 F0 add esp,-10
004A5C5A B8 EC594A00 mov eax,openpro.004A59EC
BC++:
00401678 > /EB 10 jmp short btengine.0040168A
0040167A |66:623A bound di,dword ptr ds:[edx]
0040167D |43 inc ebx
0040167E |2B2B sub ebp,dword ptr ds:[ebx]
00401680 |48 dec eax
00401681 |4F dec edi
00401682 |4F dec edi
00401683 |4B dec ebx
00401684 |90 nop
00401685 -|E9 98005400 jmp 00941722
0040168A \A1 8B005400 mov eax,dword ptr ds:[54008B]
0040168F C1E0 02 shl eax,2
00401692 A3 8F005400 mov dword ptr ds:[54008F],eax
00401697 52 push edx
00401698 6A 00 push 0
0040169A E8 99D01300 call <jmp.&KERNEL32.GetModuleHandleA>
0040169F 8BD0 mov edx,eax
VC++:
0040A41E > 55 push ebp
0040A41F 8BEC mov ebp,esp
0040A421 6A FF push -1
0040A423 68 C8CB4000 push 跑跑排行.0040CBC8
0040A428 68 A4A54000 push <jmp.&MSVCRT._except_handler3>
0040A42D 64:A1 00000000 mov eax,dword ptr fs:[0]
0040A433 50 push eax
0040A434 64:8925 0000000>mov dword ptr fs:[0],esp
0040A43B 83EC 68 sub esp,68
0040A43E 53 push ebx
0040A43F 56 push esi
0040A440 57 push edi
MASM(汇编):
004035C9 > 6A 00 push 0
004035CB E8 A20A0000 call <jmp.&kernel32.GetModuleHandleA>
004035D0 A3 5B704000 mov dword ptr ds:[40705B],eax
004035D5 68 80000000 push 80
004035DA 68 2C754000 push 11.0040752C
004035DF FF35 5B704000 push dword ptr ds:[40705B]
004035E5 E8 820A0000 call <jmp.&kernel32.GetModuleFileNameA>
004035EA E8 87070000 call 11.00403D76
004035EF 6A 00 push 0
004035F1 68 0B364000 push 11.0040360B
004035F6 6A 00 push 0
004035F8 6A 64 push 64
004035FA FF35 5B704000 push dword ptr ds:[40705B]