好友
阅读权限150
听众
最后登录1970-1-1
|
ximo
发表于 2008-10-2 13:17
telock是个简单的加密壳,在CUG的招人中,也仅仅定位为初级的加密壳。这个脱壳不难,还可以说是相当简单,但是,看了大家交的情况来看,真正能够完美脱的人,还真是不多。因此,我就做个简单的分析。说来惭愧,这个壳早在4年前就被forgot等人玩的团团转了,还出了修改版的telock,呵呵,感叹一下,技术竟落后别人有4年之多。
一、寻找OEP
其实寻找OEP是相当的简单,只要学过脱壳的人,我相信,基本上每个人都能顺利到达OEP。最后一次异常法,二次内存镜象等等,都可以顺利到达OEP!本文的重点不是在于如果到达OEP,因此,就用最方便的方法去OEP吧。
ALT+M,在.data段,下内存写入断点,SHIFT+F9
0046914EAA stos byte ptr es:[edi]//中断在这
0046914F69D2 A5B0CD4Bimul edx,edx,4BCDB0A5
00469155F9 stc
0046915672 02jb short UnPackMe.0046915A
00469158CD20 D1C269DBvxdjump DB69C2D1
0046915E70 1Fjo short UnPackMe.0046917F
00469160EE out dx,al
004691616A 03push 3
00469163DA49 0Ffimul dword ptr ds:[ecx+F]
取消内存断点,再次ALT+M,在.code(00401000)段,F2下断,SHIFT+F9
0045159C55 push ebp //顺利到达OEP
0045159D8BEC mov ebp,esp
0045159F83C4 F0add esp,-10
004515A2B8 BC134500mov eax,UnPackMe.004513BC
004515A7E8 8846FBFFcall UnPackMe.00405C34
004515ACA1 E02F4500mov eax,dword ptr ds:[452FE0]
004515B18B00 mov eax,dword ptr ds:[eax]
004515B3E8 F8E5FFFFcall UnPackMe.0044FBB0
004515B8A1 E02F4500mov eax,dword ptr ds:[452FE0]
004515BD8B00 mov eax,dword ptr ds:[eax]
就这样,很容易的就到了OEP!
但是,可别高兴的太早,脱壳多的人都知道,脱壳的难点不在于寻找OEP,而是难在修复!现在的保护手段也是层出不穷,什么IAT加密,什么代码变形,什么VM保护,什么CC保护,等等。不过,由于初级的加密壳,因此修复的难度也相对来说小的多。
打开Import-REC,填上OEP后,你会发现,有好多指针都是无效的,但是,把他剪掉后,是无法正常运行的。很明显,IAT被加密了。不过,有个简单的处理方法,只要用REC的等级3来跟踪,就能找回所有的被加密的指针!
下面的重点就是讲述如何完美处理这个壳的IAT加密。别着急关闭REC,记下被被加密的指针的地址:
FThunk: 0005512CNbFunc: 00000022
00005512C?000000980000
000055130?000000980036
000055134?00000098006E
000055138?000000980090
00005513C?0000009800C6
000055140?0000009800FE
000055144?000000980120
000055148?000000980156
00005514C?00000098018E
000055150?0000009801B0
000055154?0000009801E6
000055158?00000098021E
00005515C?000000980240
000055160?000000980276
000055164?0000009802AE
000055168?0000009802D0
00005516C?000000980306
000055170?00000098033E
000055174?000000980360
000055178?000000980396
00005517C?0000009803CE
000055180?0000009803F0
000055184?000000980426
000055188?00000098045E
00005518C?000000980480
000055190?0000009804B6
000055194?0000009804EE
000055198?000000980510
00005519C?000000980546
0000551A0?00000098057E
0000551A4?0000009805A0
0000551A8?0000009805D6
0000551AC?00000098060E
0000551B0?000000980630
FThunk: 000551B8NbFunc: 00000004
0000551B8?000000990000
0000551BC?000000990036
0000551C0?00000099006E
0000551C4?000000990090
FThunk: 000551CCNbFunc: 00000003
1000551CCadvapi32.dll01EERegQueryValueExA
1000551D0advapi32.dll01E4RegOpenKeyExA
1000551D4advapi32.dll01CBRegCloseKey
很明显,前面的一些指针都被加密了!我就随便找个,以第一个指针
00005512C?000000980000
为例,其地址为00400000+0005512C=0045512C
二、处理CRC校验
很奇怪吧,明明是处理IAT加密的,为什么要讲处理CRC校验。呵呵,这当然也是有原因的。看下面吧。
跟踪IAT加密指针的一般方法就是,在这个指针处下硬件断点,然后看寄存器窗口,寻找可用的信息。
于是,重新载入,然后dd 0045512C,接着,就下硬件访问断点吧,SHIFT+F9运行,就会出现下面的提示框:
很明显了吧,提示CRC校验错误了。因此,在处理IAT加密前,必须要处理掉这个。跟这个CRC的方法很多,有兴趣的可以试试F12法,我就用一种常规的方法来进行跟踪吧。
删除所有的断点,包括硬件断点和内存断点。接着,ALT+M,在.data段下内存写入断点。
0046914EAA stos byte ptr es:[edi]//中断在这
0046914F69D2 A5B0CD4Bimul edx,edx,4BCDB0A5
00469155F9 stc
0046915672 02jb short UnPackMe.0046915A
00469158CD20 D1C269DBvxdjump DB69C2D1
0046915E70 1Fjo short UnPackMe.0046917F
00469160EE out dx,al
004691616A 03push 3
00469163DA49 0Ffimul dword ptr ds:[ecx+F]
下面就单步F8跟下去,会发现代码很乱,不用怕,接着往下走,当然向上的跳必须打断。
004695EB8985 53384000mov dword ptr ss:[ebp+403853],eax//从这开始,代码开始清晰
004695F18746 0Cxchg dword ptr ds:[esi+C],eax
004695F40BC0 or eax,eax
004695F60F84 1A040000je UnPackMe.00469A16
004695FC35 78563412xor eax,12345678
00469601E8 CD000000call UnPackMe.004696D3
0046960603C2 add eax,edx
004696088BD8 mov ebx,eax
0046960A50 push eax
0046960BFF95 D1364000call dword ptr ss:[ebp+4036D1]
0046961185C0 test eax,eax
004696130F85 D7000000jnz UnPackMe.004696F0
0046961953 push ebx
0046961AFF95 721C4000call dword ptr ss:[ebp+401C72]
0046962085C0 test eax,eax
004696220F85 C8000000jnz UnPackMe.004696F0//改jmp!跳过CRC校验
004696288B95 63374000mov edx,dword ptr ss:[ebp+403763]
0046962E0195 2B374000add dword ptr ss:[ebp+40372B],edx
004696340195 37374000add dword ptr ss:[ebp+403737],edx
0046963A6A 30push 30
0046963C53 push ebx
0046963DFFB5 37374000push dword ptr ss:[ebp+403737]
00469643EB 53jmp short UnPackMe.00469698
004696458B95 63374000mov edx,dword ptr ss:[ebp+403763]
0046964B0195 2B374000add dword ptr ss:[ebp+40372B],edx
004696510195 2F374000add dword ptr ss:[ebp+40372F],edx
004696570195 3F374000add dword ptr ss:[ebp+40373F],edx
0046965D0195 43374000add dword ptr ss:[ebp+403743],edx
004696630195 47374000add dword ptr ss:[ebp+403747],edx
004696696A 30push 30
0046966BFFB5 2B374000push dword ptr ss:[ebp+40372B]
0046967148 dec eax //★★注意一下从这里开始的代码!
0046967275 08jnz short UnPackMe.0046967C
00469674FFB5 47374000push dword ptr ss:[ebp+403747]
0046967AEB 1Cjmp short UnPackMe.00469698
0046967C40 inc eax
0046967D75 08jnz short UnPackMe.00469687
0046967FFFB5 2F374000push dword ptr ss:[ebp+40372F]
00469685EB 11jmp short UnPackMe.00469698
0046968740 inc eax
0046968875 08jnz short UnPackMe.00469692//★★到这里的为止的一系列跳!
0046968AFFB5 3F374000push dword ptr ss:[ebp+40373F]
00469690EB 06jmp short UnPackMe.00469698
00469692FFB5 43374000push dword ptr ss:[ebp+403743]
004696986A 00push 0
0046969AFF95 D9364000call dword ptr ss:[ebp+4036D9]
004696A08B85 761C4000mov eax,dword ptr ss:[ebp+401C76]
注意一下我用★标注的地方。你会发现,这些跳无论实现与否,OD都会提示错误!(这个自己改跳跟踪一下,应该很快就能发现,虽然各个提示都不相同,但有一点是相同的,就是OD提示错误信息,然后,你无法继续调试下去!)
既然,这里的一系列跳无论实现与否,都会出现错误提示,那么,现在的关键就是如何才能跳过这个地方!
那就向上找吧!
发现了吧!
004696220F85 C8000000jnz UnPackMe.004696F0//改jmp!跳过CRC校验
这个跳,就能跳过这些检测!因此,只要把这个跳改为jmp,就能kill掉CRC校验了!
三、处理IAT的加密
既然找到了这个CRC校验的地址,下面,就可以正常跟踪加密的IAT了。
再次ctrl+F2,重新载入,然后在.data段内存写入断点,断下后取消内存断点,然后CTRL+G,定位到00469622这个地址,改jmp,kill掉CRC校验后,然后再次在0045512C处下硬件断点,SHIFT+F9运行吧,下面就可以正常跟踪了!
多次SHIFT+F9后,观看寄存器信息
004698E78B85 53384000mov eax,dword ptr ss:[ebp+403853] //来到这后,看寄存器
004698ED40 inc eax
004698EE0F84 A8000000je UnPackMe.0046999C
004698F480A5 FC2F4000 FF and byte ptr ss:[ebp+402FFC],0FF
004698FB0F84 9B000000je UnPackMe.0046999C
0046990180A5 FD2F4000 FF and byte ptr ss:[ebp+402FFD],0FF
004699080F84 8E000000je UnPackMe.0046999C
0046990E8B85 57384000mov eax,dword ptr ss:[ebp+403857]
004699148907 mov dword ptr ds:[edi],eax
004699168BF8 mov edi,eax
0046991883E0 0Fand eax,0F
0046991B50 push eax
0046991CB0 B8mov al,0B8
------------------------------------------------------------------------------------------------------------
看寄存器
EAX 7C93188A ntdll.RtlDeleteCriticalSection
ECX 7C939AEB ntdll.7C939AEB
EDX 7C99C0D8 ntdll.7C99C0D8
EBX 00455736 ASCII "DeleteCriticalSection"
ESP 0012FF80
EBP 00066A24
ESI 00455000 UnPackMe.00455000
EDI 0045512C UnPackMe.0045512C
EIP 004698E7 UnPackMe.004698E7
你会发现,这个被加密的指针出来了吧!
因此0045512C处的指针就是ntdll.RtlDeleteCriticalSection
不过,由于被加密的指针太多,一个个都这么找实在太过费力(当然,如果其他的壳被机密的指针只有个位数,那完全可以用这种方法加以寻找)
那么,我们就寻找,是否有跳能跳过这个加密!
接着F8单步走下去
004699C5^\E9 1FFCFFFFjmp UnPackMe.004695E9//循环处理输入表
004699CA61 popad
004699CBC3 retn
004699CC8B9D 761C4000mov ebx,dword ptr ss:[ebp+401C76]
004699D233C0 xor eax,eax
004699D4B9 44000000mov ecx,44
004699D98DBD A82F4000lea edi,dword ptr ss:[ebp+402FA8]
004699DFF685 74364000 FF test byte ptr ss:[ebp+403674],0FF
这个jmp,就让他跳吧,从刚开始处理的地方寻找突破口!
可以发现,在这个时刻,在内存中的IAT是完整的!
0046970B0AD2 or dl,dl//跟到这里
0046970D74 1Eje short UnPackMe.0046972D
0046970F43 inc ebx
00469710FEC6 inc dh
0046971241 inc ecx
004697133A5408 FFcmp dl,byte ptr ds:[eax+ecx-1]
00469717^ 74 E8je short UnPackMe.00469701
004697193A5408 08cmp dl,byte ptr ds:[eax+ecx+8]
0046971D^ 74 E2je short UnPackMe.00469701
0046971F3A5408 12cmp dl,byte ptr ds:[eax+ecx+12]
00469723^ 74 DCje short UnPackMe.00469701
004697253A5408 1Dcmp dl,byte ptr ds:[eax+ecx+1D]
00469729^ 74 D6je short UnPackMe.00469701
0046972B^ EB D0jmp short UnPackMe.004696FD
0046972D0AF6 or dh,dh
0046972F895424 1Cmov dword ptr ss:[esp+1C],edx
0046973361 popad
00469734C685 FD2F4000 00 mov byte ptr ss:[ebp+402FFD],0
0046973B74 24je short UnPackMe.00469761//magic jmp!
0046973D80EC 08sub ah,8
00469740B0 01mov al,1
00469742FECC dec ah
0046974474 04je short UnPackMe.0046974A
00469746D0E0 shl al,1
00469748^ EB F8jmp short UnPackMe.00469742
0046974A8AA5 BE2E4000mov ah,byte ptr ss:[ebp+402EBE]
004697500885 BE2E4000or byte ptr ss:[ebp+402EBE],al
跟到这后,你就很明显的发现了,下面的的IAT处理都是完整的,而只有这段代码,不段的在向那些IAT的地址里输入垃圾信息!因此必须跳过这段!
至此,magic jump就这么出现在我们眼前了!
0046973B74 24je short UnPackMe.00469761//magic jmp!
把这个跳改jmp,得到的IAT就是完整和正确的!
下面就是完美的脱壳过程:
在.data段内存写入断点,断下后,取消断点,然后CTRL+B,0A F6(这就是上面总结出的特征码),把下面的跳改jmp,然后在00401000处F2,SHIFT+F9后就可以到达OEP,这时候,用REC看,IAT都是有效的!
下面的工作应该很清楚了!
感谢大家认真看完,希望对你有所帮助! |
|