greet to whynotbar for his modified Olly
unpack Execryptor with this Olly will be much easy.
试练品:"total uninstall"
先膜拜一下shoooo
step0.设置OD和advencedolly,hidecap插件。
很简单,让OD忽略所有异常,advencedolly的anti anti-debug全开。break on TLS CAllBACK也打开.
注意:系统会不稳定,因为用了anti_rdtsc.sys
step1.OD载入tu.exe
OD停在TLS CALLBACK上:
005D7BBE 55 PUSH EBP //载入后停在这里
005D7BBF E8 28D40400 CALL Tu.00624FEC
005D7BC4 E8 095EF8FF CALL Tu.0055D9D2
005D7BC9 92 XCHG EAX,EDX
005D7BCA BD E2B6BB05 MOV EBP,5BBB6E2
005D7BCF 1056 E9 ADC BYTE PTR DS:[ESI-17],DL
005D7BD2 18B1 0100E818 SBB BYTE PTR DS:[ECX+18E80001],DH
step2.去EP下内存访问断点,并且删除原来EP处的CC断点:
00616474 >- E9 811EF4FF JMP Tu.005582FA //这行下内存访问断点,并且删除原来的CC
00616479 A4 MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
0061647A 29B0 5675C6AF SUB DWORD PTR DS:[EAX+AFC67556],ESI
00616480 95 XCHG EAX,EBP
step3.F9(RUN)
因为用了内存访问断点,所以可能运行比较慢.
停在EP后,可以看见CODE已经解码.so
step4.在CODE段下内存访问断点,然后RUN
之后我们会在CODE段的某个地方断下:
00500727 .- E9 3E871000 JMP Tu.00608E6A //断在这里了,显然这不是OEP附近,至少我没看出来
0050072C . E9 D1050000 JMP Tu.00500D02
00500731 04 DB 04
00500732 C4 DB C4
00500733 9E DB 9E
00500734 4D DB 4D ; CHAR 'M'
00500735 BF DB BF
00500736 35 DB 35 ; CHAR '5'
00500737 BC DB BC
00500738 27 DB 27 ; CHAR '''
00500739 69 DB 69 ; CHAR 'i'
0050073A 8E DB 8E
0050073B E5 DB E5
0050073C 37 DB 37 ; CHAR '7'
0050073D A7 DB A7
0050073E 18 DB 18
0050073F 54 DB 54 ; CHAR 'T'
00500740 17 DB 17
00500741 . 33C0 XOR EAX,EAX
00500743 . 5A POP EDX
00500744 . 59 POP ECX
00500745 . 59 POP ECX
step5.根据编译器特征找OEP.(根据区段名判断这个程序是delphi编译的)
delphi的程序都有个初始化例程(函数).
一般delphi的oep都是这个样子的:
push ebp
mov ebp,esp
sub esp,imm32
mov eax,imm32
call xxxxxxxx //这个就是初始化例程
而这个初始化函数都是
push ebx
mov ebx,eax
XOR EAX,EAX
MOV [imm32],EAX
call GetModuleHandleA //What do you think about it?
对了,我们只要He GetModuleHandleA就可以停在OEP的附近,并根据堆栈的值来找到原始的OEP.
但是Exec肯定会偷代码,所以用run跟踪,把所有的指令记下来,方便分析被偷代码.
step6.He GetModuleHandleA,F9,Alt+F9:
00407110 . 53 PUSH EBX
00407111 . 8BD8 MOV EBX,EAX
00407113 . 33C0 XOR EAX,EAX
00407115 . A3 10375400 MOV DWORD PTR DS:[543710],EAX
0040711A . 6A 00 PUSH 0 ; /pModule = NULL
0040711C . E8 2BFFFFFF CALL <JMP.&kernel32.GetModuleHandleA> ; \GetModuleHandleA
00407121 . A3 18375400 MOV DWORD PTR DS:[543718],EAX ; Tu.00400000 //我们到了这里.
看堆栈:
0013FF48 7FFD6000
0013FF4C 0053F755 RETURN to Tu.0053F755 from Tu.00407110
0013FF50 7C930738 ntdll.7C930738
返回0053F755:
0053F736 53 PUSH EBX
0053F737 00E9 ADD CL,CH
0053F739 37 AAA
0053F73A 6D INS DWORD PTR ES:[EDI],DX ; I/O command
0053F73B 0D 007B1A26 OR EAX,261A7B00
0053F740 6A 00 PUSH 0
0053F742 6A 00 PUSH 0
0053F744 49 DEC ECX
0053F745 ^ 75 F9 JNZ SHORT Tu.0053F740
0053F747 51 PUSH ECX
0053F748 53 PUSH EBX
0053F749 56 PUSH ESI
0053F74A 57 PUSH EDI
0053F74B B8 58F25300 MOV EAX,Tu.0053F258
0053F750 E8 BB79ECFF CALL Tu.00407110
0053F755 33C0 XOR EAX,EAX //回到了这里,上面就是OEP了,很明显被偷了代码.
0053F757 55 PUSH EBP
0053F758 68 9BFC5300 PUSH Tu.0053FC9B
0053F75D 64:FF30 PUSH DWORD PTR FS:[EAX]
可喜的是,初始化类表没有被偷.:-)
现在看run跟踪的纪录(其实不看纪录也能恢复,因为delphi的框架很死----这个是我事后从shoooo那里学的)
唯一值得注意的就是一个小循环
类似这个样子
loop:
push 0
push 0
dec ecx
jnz loop
push ecx
通过纪录知道第一次进入循环前ecx=0xc
其实上面的这个循环的作用就是sub esp,imm32,换了一种形式而已.
直到这个就是可以修复stolen code了
修复后:
0053F738 55 PUSH EBP
0053F739 8BEC MOV EBP,ESP
0053F73B B9 0C000000 MOV ECX,0C
0053F740 6A 00 PUSH 0
0053F742 6A 00 PUSH 0
0053F744 49 DEC ECX
0053F745 ^ 75 F9 JNZ SHORT Tu.0053F740
0053F747 51 PUSH ECX
0053F748 53 PUSH EBX
0053F749 56 PUSH ESI
0053F74A 57 PUSH EDI
0053F74B B8 58F25300 MOV EAX,Tu.0053F258
0053F750 E8 BB79ECFF CALL Tu.00407110
0053F755 33C0 XOR EAX,EAX
然后现在就可以用loadPE dump了,砍掉最后一个壳的区段.
step7.修复IAT
这个软件的IAT又是完好
这步就不讲了.重建导入表后得到dump_.exe
别急,还没完!
用lordPE把 TLS里面的CallBackTableVA置0(其他的别动,应为Delphi需要TLS)
step8.最后的修复
运行一下.
软件出现了主界面,但是立马又出现了file corrupted的错误框.看来还是有壳在搞鬼.
跟踪dump_.exe,发现F8不能过初始化例程,而且一瞬间多了4个线程.肯定里面被动了手脚(不知道是Exec太强,还是作者用了SDK,竟然能在这里面动手脚)
就这样慢慢跟踪,发现哪个函数不能F8过,就肯定是里面的问题.
最后确定是这一段代码的问题:
00404628 > /8B04DF mov eax, dword ptr ds:[edi+ebx*8]
0040462B . |43 inc ebx
0040462C . |891D 40365400 mov dword ptr ds:[543640], ebx
00404632 . |85C0 test eax, eax
00404634 . |74 02 je short 00404638
00404636 . |FFD0 call eax
00404638 > |3BF3 cmp esi, ebx
0040463A .^\7F EC jg short 00404628
这段代码就是依次调用初始化类表中的的函数.
肯定是EXEC加了自己的函数,或者作者用了SDK.
这个表里面的函数数量相当多,于是我们使用条件断点.
在call eax上设置条件纪录断点(永远记录eax的值)
然后我们把log窗口清理干净,F9运行
一瞬间过后,OD遇到异常(这个是壳的反跟踪线程,会不停的异常).
看记录:
找到这里:
00404636 COND: addr = 004FE814
00404636 COND: addr = 004FEC64
00404636 COND: addr = 004FF3F0
7C810659 New thread with ID 00000DAC created
7C810659 New thread with ID 00000E08 created
7C810659 New thread with ID 000006BC created
可见当call 004FF3F0后马上出现了3个新线程.
重新载入dump_.exe 去004FF3F0看看:
004FF3F0 . 832D 28435400>SUB DWORD PTR DS:[544328],1
004FF3F7 . 73 1A JNB SHORT dumped_.004FF413
004FF3F9 .- E9 40FC0B00 JMP dumped_.005BF03E
004FF3FE . E8 2E380E00 CALL dumped_.005E2C31
004FF403 . C3 RETN
004FF404 E8 DB E8
004FF405 1F DB 1F
004FF406 A9 DB A9
004FF407 E9 DB E9
004FF408 81 DB 81
004FF409 02 DB 02
004FF40A 00 DB 00
004FF40B 00 DB 00
004FF40C D5 DB D5
004FF40D 30 DB 30 ; CHAR '0'
004FF40E 69 DB 69 ; CHAR 'i'
004FF40F F5 DB F5
004FF410 F4 DB F4
004FF411 9F DB 9F
004FF412 B8 DB B8
004FF413 > C3 RETN
可见如果[544328]中的数比1小,那么就要JMP dumped_.005BF03E.那么就要启动壳的检查和监视线程.
好了,用LordPE把[544328]改成1.运行一下,没有问题了.
但是退出的时候还是会非法操作,这个修复很容易,自行解决吧~.
总结:
这个又是个没加密IAT的程序,所以不难.和UPX差不多.