PE_Admin[20090719]-免费全功能版脱壳[by hyperchem]
不知道是系统的问题 还是程序的问题,还是OD的问题,这个软件在我的OD中运行的速度巨慢无比。在运行起来以后,查看第一个区段,也就是Code段的内容
引用
00401000 04 10 add al,10
00401002 40 inc eax
00401003 0003 add byte ptr ds:,al
00401005 07 pop es
00401006 42 inc edx
00401007 6F outs dx,dword ptr es:
00401008 6F outs dx,dword ptr es:
00401009 6C ins byte ptr es:,dx
0040100A 65:61 popad
0040100C 6E outs dx,byte ptr es:
0040100D 0100 add dword ptr ds:,eax
0040100F 0000 add byte ptr ds:,al
00401011 0001 add byte ptr ds:,al
00401013 0000 add byte ptr ds:,al
00401015 0000 add byte ptr ds:,al
00401017 1040 00 adc byte ptr ds:,al
0040101A 05 46616C73 add eax,736C6146
0040101F 65:04 54 add al,54
00401022 72 75 jb short 00401099
00401024 65:8D40 00 lea eax,dword ptr gs:
00401028 2C 10 sub al,10
0040102A 40 inc eax
0040102B 0002 add byte ptr ds:,al
0040102D 04 43 add al,43
发现这是个典型的Delphi程序。
下面我们来找OEP。
Delphi的程序的OEP很好找。依据以下几点:
引用
1,OEP的上面是初始化函数表
2,OEP的下面是Code段结束的00
3,OEP附近的第一个API调用时GetModuleHandleA
这个程序把原始程序的所有区段都合并到第一个区段去了,所以通过前两种方法中OEP的话,对于大多数人来说都是个体力活。
我们用第三种方法,因为程序N慢,所以对于我来说也是种煎熬~
重新载入,然后bp GetModuleHandleA 运行,然后就等到程序中断下来 看返回的地址是不是在第一个区段的范围内。
最后我们中断并返回到这里:00407374 53 push ebx
00407375 8BD8 mov ebx,eax
00407377 33C0 xor eax,eax
00407379 A3 C4005600 mov dword ptr ds:,eax
0040737E 6A 00 push 0
00407380 E8 2BFFFFFF call 004072B0-------这里就是call GetModuleHandleA了
00407385 A3 68B65700 mov dword ptr ds:,eax
0040738A A1 68B65700 mov eax,dword ptr ds:
0040738F A3 D0005600 mov dword ptr ds:,eax
00407394 33C0 xor eax,eax
00407396 A3 D4005600 mov dword ptr ds:,eax
0040739B 33C0 xor eax,eax
0040739D A3 D8005600 mov dword ptr ds:,eax
004073A2 E8 C1FFFFFF call 00407368
004073A7 BA CC005600 mov edx,005600CC
004073AC 8BC3 mov eax,ebx
004073AE E8 1DD7FFFF call 00404AD0
004073B3 5B pop ebx
004073B4 C3 retn熟悉Delphi朋友肯定知道这就是OEP处的第一个call了。 继续返回到上层0055F0EC >55 push ebp----------这就是OEP了
0055F0ED 8BEC mov ebp,esp
0055F0EF 83C4 F0 add esp,-10
0055F0F2 B8 7CED5500 mov eax,0055ED7C
0055F0F7 E8 7882EAFF call 00407374
0055F0FC A1 DCA05700 mov eax,dword ptr ds:
0055F101 8B00 mov eax,dword ptr ds:
0055F103 E8 D03DF2FF call 00482ED8
0055F108 A1 DCA05700 mov eax,dword ptr ds:
0055F10D 8B00 mov eax,dword ptr ds:
0055F10F C640 5B 00 mov byte ptr ds:,0
0055F113 8B0D 44A15700 mov ecx,dword ptr ds: ; 1.0057D1DCOEP找到了~ 我们下面看看IAT004072B0 90 nop
004072B1 - E9 3E7CC500 jmp 0105EEF4----这里应该是Jmp GetModudleHandleA
004072B6 8BC0 mov eax,eax
004072B8 90 nop
004072B9 - E9 027CC500 jmp 0105EEC0
004072BE 8BC0 mov eax,eax
004072C0 90 nop
004072C1 - E9 CE7BC500 jmp 0105EE94
004072C6 8BC0 mov eax,eax
004072C8 90 nop
004072C9 - E9 9A7BC500 jmp 0105EE68发现IAT已经被处理了。我们要修复。
好了,先说句题外话吧。在跟踪的过程,我发现程序的注册框是壳代码里面显示的,而且这个时候原程序的代码段和数据段都已经解码了,
也就是说这个时候还没有执行到OEP,数据没有初始化。这个是我们修复的最好时机。
直接运行程序,弹出注册框以后,用OD附加这个程序。然后开始我们的修复IAT的过程。
跟入上面的Jmp,看到下面的代码。0105EEF4 E8 03C675FF call PE_Adm_1.007BB4FC
0105EEF9 - FF25 FFEE0501 jmp dword ptr ds: ; SHELL32.7D8559B8跟进上面的call,清理下代码,得到下面的代码007BB502 9C pushfd
007BB503 50 push eax
007BB504 53 push ebx
007BB50A E8 DDB6F8FF call 00746BEC ; jmp to kernel32.GetCurrentThread
007BB50F 9C pushfd
007BB510 58 pop eax
007BB511 A3 94458400 mov dword ptr ds:,eax
007BB51C E8 47000000 call 007BB568
007BB521 31C0 xor eax,eax
007BB523 A0 B0458400 mov al,byte ptr ds:
007BB528 83F8 00 cmp eax,0
007BB52B 75 34 jnz short 007BB561
007BB52D 8B4424 0C mov eax,dword ptr ss:---------注意这里
007BB531 89C3 mov ebx,eax
007BB533 83C0 02 add eax,2
007BB536 8B00 mov eax,dword ptr ds:
007BB538 8B00 mov eax,dword ptr ds:
007BB53A 31D8 xor eax,ebx
007BB53C 894424 0C mov dword ptr ss:,eax
007BB540 8B00 mov eax,dword ptr ds:
007BB542 3C CC cmp al,0CC
007BB544 74 14 je short 007BB55A
007BB546 80FC CC cmp ah,0CC
007BB549 74 0F je short 007BB55A
007BB54B C1E8 10 shr eax,10
007BB54E 3C CC cmp al,0CC
007BB550 74 08 je short 007BB55A
007BB552 80FC CC cmp ah,0CC
007BB555 74 03 je short 007BB55A
007BB557 EB 08 jmp short 007BB561
007BB559 - E9 C605B045 jmp 462BBB24
007BB55E 8400 test byte ptr ds:,al
007BB560 015B 58 add dword ptr ds:,ebx
007BB563 9D popfd
007BB564 C3 retn这里面ESP+C里面放的是
0105EEF4 E8 03C675FF call PE_Adm_1.007BB4FC
这个call的返回地址,也就是0105EEF9
007BB533 83C0 02 add eax,2
007BB536 8B00 mov eax,dword ptr ds:
007BB538 8B00 mov eax,dword ptr ds:
这三条指令的作用就是获取下面这个7D8559B8的
0105EEF9 - FF25 FFEE0501 jmp dword ptr ds: ; SHELL32.7D8559B8
007BB53A 31D8 xor eax,ebx----这个就是用上面的地址跟返回地址异或,就得到真正API地址了。
可以分析下,所有的IAT都是这样处理的,所以写个脚本修复下就OK了!mov eip,00401000-----------代码开始
mov tmp0,01750000----------这个是我用StrongOD分配的内存,用来存放IAT的
Loop:
mov tmp1,eip
find tmp1,#90E9#-----------查找nop Jmp
cmp $RESULT,0
je Finish
mov tmp2,$RESULT
mov tmp3,$RESULT
add tmp2,1
GCI tmp2,DESTINATION
cmp $RESULT,01040000--------
jb continue
cmp $RESULT,01910000--------因为jmp的地址不在一个内存段上,所以这两个值就是内存段的上限和下限值
jg continue
mov tmp4,$RESULT
add tmp4,5
GCI tmp4,DESTINATION--------因为是哪里用的是FF25这样的jmp型,所以直接用GCI就可以获取异或后的API地址了
cmp $RESULT,0
je continue
mov tmp5,$RESULT
xor tmp5,tmp4---------------异或解开
mov ,tmp5,4
mov ,#FF25#,2---------修复IAT调用为Jmp dword ptr ds:[]
add tmp3,2
mov ,tmp0,4
add tmp0,4
jmp continue
continue:
mov eip,tmp2
jmp Loop
Finish:
ret跑完脚本以后,IAT就差不多全部修复了~
还剩三处没有修复,因为处理的方法不同的说004078C0 90 nop
004078C1- E9 7AA17C77 jmp version.GetFileVersionInfoA
004078C6 8BC0 mov eax,eax
004078C8 90 nop
004078C9- E9 21A17C77 jmp version.GetFileVersionInfoSizeA
004078CE 8BC0 mov eax,eax
004078D0 90 nop
004078D1- E9 D49F7C77 jmp version.VerQueryValueA使用的是直接Jmp的~ 这三个手动修复下就可以了!
然后用UIF把IAT移动回程序内,DUmp进程,ImportREC重建输入表(还记得OEP是什么吧?)。
至此脱壳完成!
建议:
1,不要向System32下释放dll文件,否则很容易被主动掉!
2,不要给dll加WinUPack这样的壳,因为这个壳是病毒常用的,很容易被误杀。
3,IAT加密还需加强的说~
4,资源的处理不要只修改一个索引。
页:
[1]