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差不多.