TA的每日心情 | 开心 2024-12-9 18:45 |
---|
签到天数: 124 天 [LV.7]常住居民III
|
SHIFT+F9执行:
0040D19D A4 movs byte ptr es:[edi],byte ptr ds:[esi] //还没解完呢
0040D19E B3 02 mov bl,2
对data段下内存“写入”断点,试试看他是不是要写data段。
00372712 F3:A4 rep movs byte ptr es:[edi],byte ptr ds:[esi] //断到这里
00372714 5E pop esi
下面再对code段下内存访问断点。F9
00372855 8907 mov dword ptr ds:[edi],eax ; SHELL32.DragFinish //这里是对IAT加密
的地方了!!!
00372857 5A pop edx
00372858 0FB642 FF movzx eax,byte ptr ds:[edx-1]
0037285C 03D0 add edx,eax
0037285E 42 inc edx
0037285F 83C7 04 add edi,4
00372862 59 pop ecx
00372863 ^ E2 A9 loopd short 0037280E
00372865 ^ E9 63FFFFFF jmp 003727CD
0037286A 8BB5 93060000 mov esi,dword ptr ss:[ebp+693] //到这里下断F2
现在如果再对data下访问断点已经是没用了。这时应该格外的小心。
我们现在就想既然这一段是对code解码的,那么我们就绕过他吧!
到0037286A下断F2,然后清除内存断点!!!!
F9以后停在这里,继续对code下内存访问断点。
看看左下角还在解码,哎~真是麻烦!
003728E1 /EB 1D jmp short 00372900
003728E3 |25 FFFFFF7F and eax,7FFFFFFF
003728E8 |0385 83060000 add eax,dword ptr ss:[ebp+683]
003728EE |2B85 8F060000 sub eax,dword ptr ss:[ebp+68F]
003728F4 |8BDE mov ebx,esi
003728F6 |2BD8 sub ebx,eax
003728F8 |8958 FC mov dword ptr ds:[eax-4],ebx //停在这里
003728FB |83C7 08 add edi,8
003728FE ^|EB DB jmp short 003728DB
00372900 \64:FF35 30000000 push dword ptr fs:[30] //清除内存断点以后到这里下断,F9
又是一段解码的代码,再次使用上面的办法手动跳出去。
现在继续对code段下内存访问断点!!F9以后到达这里。
004010CC FFD7 call edi ; unpackme.004010CE //OEP哦
004010CE 58 pop eax
004010CF 83EC 44 sub esp,44
004010D2 56 push esi
004010D3 90 nop
004010D4 E8 B518F7FF call 0037298E
004010D9 8BF0 mov esi,eax
呵呵~虽然不是我们熟悉的OEP,但是地址是没错了,况且根据我们的步骤,我可以很肯定的说这是code段的第一次“执行”中断!
所以这就是OEP了。
总结一下:当我们在寻找OEP的时候,要多次对code下断“赌”一“赌”他解压完毕,如果不是就对别的段试试~如果程序跑飞了,那就没办法了,重来呗~其实说起来要赌的是:当data段,idata段,rsrc段摆在你的面前,你会好好“珍惜”那个段,不过还好上天还会给我们从来一次的机会(ctrl+F2 ^_^),那么我们会对那个不会跑飞的段说3个字----“先断你”如果非要在上面加一个次数,我希望是“一次内存断点就好了”
vi.下面来讨论一下内存断点的局限性问题。
是不是什么壳都可以用内存中断啊?
不是每个都可以的,一些像UPX和ASPACK就不行。
为什么?
呵呵~follew me!
情况1.
我们来看看UPX的壳
首先,他的壳代码在UPX1段。
这里是他要跳到OEP的地方
0040ED4F /77 11 ja short NOTEPAD_.0040ED62
0040ED51 |01C3 add ebx,eax
0040ED53 |8B03 mov eax,dword ptr ds:[ebx]
0040ED55 |86C4 xchg ah,al
0040ED57 |C1C0 10 rol eax,10 //在解码
0040ED5A |86C4 xchg ah,al
0040ED5C |01F0 add eax,esi
0040ED5E |8903 mov dword ptr ds:[ebx],eax
0040ED60 ^|EB E2 jmp short NOTEPAD_.0040ED44
0040ED62 \24 0F and al,0F
0040ED64 C1E0 10 shl eax,10
0040ED67 66:8B07 mov ax,word ptr ds:[edi]
0040ED6A 83C7 02 add edi,2
0040ED6D ^ EB E2 jmp short NOTEPAD_.0040ED51 //回跳解码
0040ED6F 61 popad
0040ED70 - E9 5723FFFF jmp NOTEPAD_.004010CC //跳到OEP
我们看到他在对code段解压完毕的时候马上就JMP到OEP去了,那么我们根本就来不及使用内存断点的办法。
你可能说,我可以在
0040ED6F 61 popad //这一句下段然后使用啊
呵呵~~当然可以,不过你把花在下内存断点的时间,多按下几次F8不更好?!
也就是说当一个壳如果他在JMP 到OEP前的一行代码仍在都在对code段解压,那么我们就不能再使用这种办法了!
或者说我们没必要使用内存断点更贴切一点!
情况2.
对于一些在OEP处有stolen code的代码
我们来看看一个OEP
0049E2F4 u> 55 push ebp //OEP
0049E2F5 8BEC mov ebp,esp
0049E2F7 83C4 F4 add esp,-0C
0049E2FA B8 BCE04900 mov eax,unpack.0049E0BC
0049E2FF E8 048CF6FF call unpack.00406F08 //这里调用子程序
0049E304 A1 B8FE4900 mov eax,dword ptr ds:[49FEB8]
0049E309 50 push eax
0049E30A 6A 00 push 0
0049E30C 68 1F000F00 push 0F001F
0049E311 E8 E68EF6FF call <jmp.&kernel32.OpenFileMappingA> //API
0049E316 A3 60194A00 mov dword ptr ds:[4A1960],eax
0049E31B 833D 60194A00 00 cmp dword ptr ds:[4A1960],0
这个软件在被PESPIN加壳了以后这些全被偷掉了!
也就是说,壳在模拟OEP代码的时候必然会执行
0049E2FF E8 048CF6FF call unpack.00406F08 //这一步
而这个地方是call向code段的。如果我们使用内存访问断点,那么就停在这个子程序的地方
00406F08 50 push eax //会停在这里
00406F09 6A 00 push 0
00406F0B E8 F8FEFFFF call <jmp.&kernel32.GetModuleHandleA>
00406F10 BA 04F14900 mov edx,unpack.0049F104
00406F15 52 push edx
这里既不是处理stolen code的地方,也不是FOEP的地方。这就会对我们的判断产生误导。
当然你可以alt+F9返回到壳处理stolen的地方,然后用内存断点,或者按几下F8到达FOEP处,但试问如果你拿到一个未知的壳的时候又怎么知道应该这么处理呢?
还有其他一些情况留给大家总结吧!
在下的砖已抛出,各位的玉不久矣。
--------------------------------------------------
3.总结
好了说了很多,大家应该对内存断点的办法有了全面的了解,如果了解了内存断点的原理就不难明白他的使用方法,不难明白为什么有写壳不能使用内存断点的办法,其实任何的一种办法都需要经验的积累。相信如果大家在回答开篇的3个问题,已经不难了。
大家可以结合原理再好好的体会一下《手动脱壳进阶第八篇Skvp1.32》这篇文章。 |
|