|
欢迎您注册加入!这里有您将更精采!
您需要 登录 才可以下载或查看,没有账号?注册
x
不知道是系统的问题 还是程序的问题,还是OD的问题,这个软件在我的OD中运行的速度巨慢无比。
在运行起来以后,查看第一个区段,也就是Code段的内容
引用
00401000 04 10 add al,10
00401002 40 inc eax
00401003 0003 add byte ptr ds:[ebx],al
00401005 07 pop es
00401006 42 inc edx
00401007 6F outs dx,dword ptr es:[edi]
00401008 6F outs dx,dword ptr es:[edi]
00401009 6C ins byte ptr es:[edi],dx
0040100A 65:61 popad
0040100C 6E outs dx,byte ptr es:[edi]
0040100D 0100 add dword ptr ds:[eax],eax
0040100F 0000 add byte ptr ds:[eax],al
00401011 0001 add byte ptr ds:[ecx],al
00401013 0000 add byte ptr ds:[eax],al
00401015 0000 add byte ptr ds:[eax],al
00401017 1040 00 adc byte ptr ds:[eax],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:[eax]
00401028 2C 10 sub al,10
0040102A 40 inc eax
0040102B 0002 add byte ptr ds:[edx],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:[5600C4],eax
- 0040737E 6A 00 push 0
- 00407380 E8 2BFFFFFF call 004072B0-------这里就是call GetModuleHandleA了
- 00407385 A3 68B65700 mov dword ptr ds:[57B668],eax
- 0040738A A1 68B65700 mov eax,dword ptr ds:[57B668]
- 0040738F A3 D0005600 mov dword ptr ds:[5600D0],eax
- 00407394 33C0 xor eax,eax
- 00407396 A3 D4005600 mov dword ptr ds:[5600D4],eax
- 0040739B 33C0 xor eax,eax
- 0040739D A3 D8005600 mov dword ptr ds:[5600D8],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:[57A0DC]
- 0055F101 8B00 mov eax,dword ptr ds:[eax]
- 0055F103 E8 D03DF2FF call 00482ED8
- 0055F108 A1 DCA05700 mov eax,dword ptr ds:[57A0DC]
- 0055F10D 8B00 mov eax,dword ptr ds:[eax]
- 0055F10F C640 5B 00 mov byte ptr ds:[eax+5B],0
- 0055F113 8B0D 44A15700 mov ecx,dword ptr ds:[57A144] ; 1.0057D1DC
复制代码 OEP找到了~ 我们下面看看IAT- 004072B0 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:[105EEFF] ; 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:[844594],eax
- 007BB51C E8 47000000 call 007BB568
- 007BB521 31C0 xor eax,eax
- 007BB523 A0 B0458400 mov al,byte ptr ds:[8445B0]
- 007BB528 83F8 00 cmp eax,0
- 007BB52B 75 34 jnz short 007BB561
- 007BB52D 8B4424 0C mov eax,dword ptr ss:[esp+C]---------注意这里
- 007BB531 89C3 mov ebx,eax
- 007BB533 83C0 02 add eax,2
- 007BB536 8B00 mov eax,dword ptr ds:[eax]
- 007BB538 8B00 mov eax,dword ptr ds:[eax]
- 007BB53A 31D8 xor eax,ebx
- 007BB53C 894424 0C mov dword ptr ss:[esp+C],eax
- 007BB540 8B00 mov eax,dword ptr ds:[eax]
- 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:[eax],al
- 007BB560 015B 58 add dword ptr ds:[ebx+58],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:[eax]
007BB538 8B00 mov eax,dword ptr ds:[eax]
这三条指令的作用就是获取下面这个7D8559B8的
0105EEF9 - FF25 FFEE0501 jmp dword ptr ds:[105EEFF] ; 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 [tmp0],tmp5,4
- mov [tmp3],#FF25#,2---------修复IAT调用为Jmp dword ptr ds:[]
- add tmp3,2
- mov [tmp3],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,资源的处理不要只修改一个索引。 |
|