一款自制壳的脱壳

1.进行查壳操作

因其是自制的壳,所以用工具是查不到壳的特征码,也就查不出壳;

2.确定重定位已分离

如果不进行重定位分离的话,会产生随机基址,从而导致脱壳失败

3.查找OEP

①使用ESP定理
②寻找OEP位置(OEP:47148B
记得“右键”点击“分析”选择“删除分析”

4.查看导入地址表IAT

由于已经找到了OEP,而导入地址表IAT的加载在OEP后的不远处,通过单步步过,可以发现004714B1 FF15 80504700 call dword ptr ds:[0x475080]是导入地址表IAT的加载,在此处右键单击“数据窗口中跟随”选择“内存地址”
我们可以看到其地址所存的内存地址数值在 0027XXXX的位置,是一块堆空间,而正常的IAT的地址应当在 7XXXXXXXX的地方,所以,判定IAT被加密。

5.进入IAT被加密位置

①在IAT修改处下硬件断点
在图中的 00275039的位置下硬件写入断点,就能跳转到IAT被加密的位置
②重新开始,运行找修改处
第一次运行,命中的是ntdll模块
再继续运行,找到 001E0895 ,此处就是在填充IAT
此处的地址为001E0897,这是一个VA地址,是申请在堆内存中的一个地址,所以我们只需要记录其的RVA地址0897,而01E0000就是程序动态申请的地址,在写脚本的时候需要动态获取这个地址。
001E0895 8902 mov dword ptr ds:[edx],eax
001E0897 E8 39000000 call 001E08D5
③如何确定其申请的动态基址
从新加载程序,进行单步步入跟踪,我们知道,程序比如会先加载壳代码,也就必然会开辟堆空间,,而开辟堆空间会用到VirtualAlloc,这样我们可以通过函数名快速的找到申请堆空间位置。
由图可以看到,在0047A37D处会显示字符串“ VirtualAlloc”,由此,我们确定申请的堆空间地址会直接存入eax中,再单步一下,就能看到eax寄存器中出现堆空间地址 001E0000

6.脱壳思路

此壳的加密行为为,申请一块堆空间,将原本的IAT数据写人到堆空间中,再用堆空间内存地址覆盖IAT,相当于做了一次中间转换,如果能其加密结束处将正确的IAT原始数据重新写入IAT中进行覆盖操作,就能顶掉壳的中间跳转操作,达到脱壳效果。

7.找到关键地址

①找回原始函数地址思路
我们知道了填充加密IAT的代码位置,就能找到存放原始函数API地址的堆空间,就能找回原始函数,就在执行用堆空间地址覆盖IAT代码的前不远处。
②Run追踪
我们需要使用Run跟踪来帮助我们快速找到,获得存放原始函数地址的位置。首先在填充IAT的位置,删除之前的硬件断点,再在这个位置下软件断点,点击导航栏的调试,单击“打开RUN追踪”,再选择跟踪步入
打开RUN追踪窗口,在导航栏点击“查看“,再点击“RUN追踪”即可
等待片刻
③找到关键位置
查看RUN跟踪记录的指令信息,重点关注这次循环过程中,寄存器发生的变化,从最后一条记录向前找,找寄存器中的值像真实函数地址的指令
为了确认,双击此条信息,反汇编窗口跟随,设置软件短句,运行到此处,右键单击,数据窗口跟随,点击“隐含堆栈地址”,再在数值处,右键选择“反汇编窗口中跟随”
④确认关键点
我们需要在获取函数地址指令的下一行,获取EXD的值,用来引向正确的IAT,记录其偏移 10F7
001710F6 5A pop edx ; kernel32.HeapFree
001710F7 E8 02F4FFFF call 001704FE

8.编写OD脚本恢复IAT

①准备阶段
0047148B  ==  OEP
0047A37F  ==  申请的堆空间,里面有壳代码,返回值EAX
0x0897      ==  填充IAT的下一行指令位置,我们需要用真实地址覆盖填充过的加密IAT
0x10F7      ==  获取真实函数地址的下一行,真实地址保存在EDX中

MOV ddEDX,0
MOV dwAddress,0
MOV ddGetVirtualAlloc,0047A37F
MOV dwGetFunctionRVA,10F7
MOV dwWriteIATRVA,0897
MOV ddOEPAddr,0047148B
BC
BPHWCALL
BPHWS ddGetVirtualAlloc,"x"
BPHWS ddOEPAddr,"x"
LOOP1:
RUN
GetVir:
CMP eip,ddGetVirtualAlloc
JNE CASE1
MOV dwAddress,eax
ADD dwGetFunctionRVA,dwAddress
MSG dwGetFunctionRVA
ADD dwWriteIATRVA,dwAddress
MSG dwWriteIATRVA
BPHWS dwGetFunctionRVA,"x"
BPHWS dwWriteIATRVA,"x"
JMP LOOP1
CASE1:
CMP eip,dwGetFunctionRVA
JNE CASE2
MOV ddEDX,edx
JMP LOOP1
CASE2:
CMP eip,dwWriteIATRVA
JNE CASE3
MOV [edx],ddEDX
JMP LOOP1
CASE3:
CMP eip,ddOEPAddr
JNE LOOP1
MSG "到达OEP,可以dump了!!!"
x
 
1
MOV ddEDX,0
2
MOV dwAddress,0
3
MOV ddGetVirtualAlloc,0047A37F
4
MOV dwGetFunctionRVA,10F7
5
MOV dwWriteIATRVA,0897
6
MOV ddOEPAddr,0047148B
7
BC
8
BPHWCALL
9
BPHWS ddGetVirtualAlloc,"x"
10
BPHWS ddOEPAddr,"x"
11
LOOP1:
12
RUN
13
GetVir:
14
CMP eip,ddGetVirtualAlloc
15
JNE CASE1
16
MOV dwAddress,eax
17
ADD dwGetFunctionRVA,dwAddress
18
MSG dwGetFunctionRVA
19
ADD dwWriteIATRVA,dwAddress
20
MSG dwWriteIATRVA
21
BPHWS dwGetFunctionRVA,"x"
22
BPHWS dwWriteIATRVA,"x"
23
JMP LOOP1
24
CASE1:
25
CMP eip,dwGetFunctionRVA
26
JNE CASE2
27
MOV ddEDX,edx
28
JMP LOOP1
29
CASE2:
30
CMP eip,dwWriteIATRVA
31
JNE CASE3
32
MOV [edx],ddEDX
33
JMP LOOP1
34
CASE3:
35
CMP eip,ddOEPAddr
36
JNE LOOP1
37
MSG "到达OEP,可以dump了!!!"















猜你喜欢

转载自www.cnblogs.com/HOPEAMOR/p/12017292.html