[原創]尋找Asp1.2X的Stolen code的另一種方法

看雪資料發表於2004-07-11

Advanced WMA Workshop 2.04b簡單脫殼破解

程式用asp1.24rc4加殼,並用殼的時間保護


作者:lordor
QQ:88378557
Mail:lordor#163.com
來自:www.digitalnuke.com
說明:asp1.24RC4的Stolen code的尋找方法,這個方法對於1.3以上的是否管用,還在研究中。
自由轉載請保




一、尋找偽OEP
用od載入程式,設定記憶體不打鉤,其它都 打鉤,隱藏od,到如下:
AWMAWork.>PUSH AWMAWork.00632001  ==>先停在這裡,看一下暫存器的值
--------------
ECX 0012FFB0
EDX 7FFE0304
EBX 7FFDF000
ESP 0012FFC4  ==>注意這個
EBP 0012FFF0  ==>
ESI 00000024
EDI 00000000
EIP 00401000 AWMAWork.<ModuleEntryPoint>
--------------

經過26個seh後,到這裡的特徵程式碼:
00CB39EC  XOR DWORD PTR DS:[EAX],EAX  ==>停在這裡
00CB39EE  POP DWORD PTR FS:[0]
00CB39F5  POP EAX
00CB39F6  CMP DWORD PTR DS:[CB7EB0],0
00CB39FD  JE SHORT 00CB3A13
00CB39FF  PUSH 0C
00CB3A01  MOV ECX,0CB7EB0
00CB3A06  LEA EAX,DWORD PTR SS:[EBP-8]
00CB3A09  MOV EDX,4
00CB3A0E  CALL 00CB0B40
00CB3A13  PUSH DWORD PTR SS:[EBP-4]
00CB3A16  PUSH DWORD PTR SS:[EBP-8]
00CB3A19  MOV EAX,DWORD PTR SS:[EBP-C]
00CB3A1C  CMP DWORD PTR DS:[EAX],0
00CB3A1F  JE SHORT 00CB3A23
00CB3A21  PUSH DWORD PTR DS:[EAX]
00CB3A23  PUSH DWORD PTR SS:[EBP-10]
00CB3A26  PUSH DWORD PTR SS:[EBP-14]
00CB3A29  RETN      ==>這裡下斷,shift+F9執行到這裡



開啟"Memory Map"視窗
在AWMAWorkshop的"code"段下“Set break-on access”(即按F2),這樣當執行完殼的程式碼後,再執行解壓後程式碼段的內容就會停下來。
置完後,按F9,會到這裡
0047DB94  PUSH AWMAWork.0047DCEC                   ; JMP to MSVCR70._except_handler3
0047DB99  MOV EAX,DWORD PTR FS:[0]
0047DB9F  PUSH EAX
0047DBA0  MOV EAX,DWORD PTR SS:[ESP+10]
0047DBA4  MOV DWORD PTR SS:[ESP+10],EBP
0047DBA8  LEA EBP,DWORD PTR SS:[ESP+10]
0047DBAC  SUB ESP,EAX    ==>這裡為stack分配區域性地址,eax為壓入的立即數
0047DBAE  PUSH EBX    ***
0047DBAF  PUSH ESI    ***  
0047DBB0  PUSH EDI    ***
0047DBB1  MOV EAX,DWORD PTR SS:[EBP-8]
0047DBB4  MOV DWORD PTR SS:[EBP-18],ESP
0047DBB7  PUSH EAX    ***
0047DBB8  MOV EAX,DWORD PTR SS:[EBP-4]
0047DBBB  MOV DWORD PTR SS:[EBP-4],-1
0047DBC2  MOV DWORD PTR SS:[EBP-8],EAX
0047DBC5  LEA EAX,DWORD PTR SS:[EBP-10]
0047DBC8  MOV DWORD PTR FS:[0],EAX
0047DBCE  RETN      ==>停在這裡
0047DBCF  MOV ECX,DWORD PTR SS:[EBP-10]
0047DBD2  MOV DWORD PTR FS:[0],ECX
0047DBD9  POP ECX
0047DBDA  POP EDI
0047DBDB  POP ESI
0047DBDC  POP EBX
0047DBDD  LEAVE
0047DBDE  PUSH ECX

可以看到這個是VC7的第一個call的程式碼,看一下暫存器的值,並注意***上面壓入了幾句(這裡只有四句),後面會用到:
------------
ECX 0012FFB0
EDX 7FFE0304
EBX 7FFDF000
ESP 0012FF30  ==>注意這裡
EBP 0012FFC0  
ESI 00000000
EDI 00000000
EIP 0047DBCE AWMAWork.0047DBCE

------------
F8一步,到這裡
0047D8C5  RETN 10
0047D8C8  ADD BYTE PTR DS:[EAX],AL
0047D8CA  ADD BYTE PTR DS:[EAX],AL
0047D8CC  ADD BYTE PTR DS:[EAX],AL
0047D8CE  NOP        ==>花指令,nop掉
0047D8CF  CALL AWMAWork.0047DB94
0047D8D4  XOR EBX,EBX      ===>到這裡,偽OEP,可以看到上一個call(0047DB94)已經在殼中執行了
0047D8D6  PUSH EBX
0047D8D7  MOV EDI,DWORD PTR DS:[4820FC]
0047D8DD  CALL EDI
0047D8DF  CMP WORD PTR DS:[EAX],5A4D
0047D8E4  JNZ SHORT AWMAWork.0047D905
0047D8E6  MOV ECX,DWORD PTR DS:[EAX+3C]
0047D8E9  ADD ECX,EAX

二、尋找STOLEN CODE,並DUMP程式

可以看到0047D8C8  ADD BYTE PTR DS:[EAX],AL處就是真正的OEP了,那裡已經抽掉兩句程式碼了,
可能你會問,我是怎麼知道的?
找回抽掉的程式碼的方法一般有:
1、TC跟蹤得到
2、tDasm老兄介紹的還原stolen code的分析法
3、FLY老兄介紹的cdi猜測法,這個我還是未明白
4、blowfish老兄介紹的建立stack法,這個方法非常好。

我的方法是在blowfish方法的基礎上再加上:參照同類編譯器生成的入口程式碼。


好,那麼我們開啟一個VC7的程式,看一下入口的程式碼
Service.<>PUSH 74    
0040270F  PUSH Service.00403BF8
00402714  CALL Service.0040290C
00402719  XOR EBX,EBX      ==>這裡以下都是相同的語句
0040271B  MOV DWORD PTR SS:[EBP-20],EBX
0040271E  PUSH EBX                                 ; /pModule => NULL
0040271F  MOV EDI,DWORD PTR DS:[<&KERNEL32.GetModu>; |kernel32.GetModuleHandleA
00402725  CALL EDI                                 ; \GetModuleHandleA
00402727  CMP WORD PTR DS:[EAX],5A4D
0040272C  JNZ SHORT Service.0040274D
0040272E  MOV ECX,DWORD PTR DS:[EAX+3C]
00402731  ADD ECX,EAX
00402733  CMP DWORD PTR DS:[ECX],4550
00402739  JNZ SHORT Service.0040274D

所以關鍵就是想方法補上抽掉的兩句程式碼。首先可以推測一下這兩句的形式:
push 立即數
push 地址

那麼如何那個立即數及地址呢?

這裡就要檢視STACK的內容來確定了。

先看一載入程式時的ESP==0012FFC4,EBP=0012FFF0,
再看一下到偽OEP後的STACK的內容:
0012FF34   00000000  ==>現在的esp
0012FF38   00000000
0012FF3C   7FFDF000
0012FF40   00CA0000
0012FF44   00C80000
0012FF48   0000000C
0012FF4C   00CD1F70
0012FF50   0012FF60
0012FF54   00CCDD95  RETURN to 00CCDD95 from 00CCDDA0
0012FF58   00CCDDF3  RETURN to 00CCDDF3 from 00CCDDFD
0012FF5C   00CCDDD6  RETURN to 00CCDDD6 from 00CCDDE8
0012FF60   00400000  AWMAWork.00400000
0012FF64   C0F1DD1F
0012FF68   0012FFA4
0012FF6C   00CA0000
0012FF70   00C80000
0012FF74   00CB4138
0012FF78   00CD1DA0
0012FF7C   00CCDD50
0012FF80   00400000  AWMAWork.00400000
0012FF84   00632880  AWMAWork.00632880
0012FF88   00CCDE87  RETURN to 00CCDE87 from 00CCDE93
0012FF8C   5FCEDFF7
0012FF90   00000369
0012FF94   0080FD60
0012FF98   FDC7616E
0012FF9C   0012FFF0
0012FFA0   0012FFB0
0012FFA4   00000000
0012FFA8   0012FF34
0012FFAC   0012FFE0
0012FFB0   0012FFE0  Pointer to next SEH record
0012FFB4   0047DCEC  SE handler
0012FFB8   0049E9C0  AWMAWork.0049E9C0
0012FFBC   FFFFFFFF
0012FFC0   0012FFF0  ==>注意這裡
0012FFC4   77E5EB69  RETURN to kernel32.77E5EB69



其中(0012FFB8   0049E9C0  AWMAWork.0049E9C0)的0049E9C0即為第二句抽掉的的push,
現在來確定那個立即數
0012FFC0-0012FF34=8c,這個是我們要找的立即數嗎?不是,還要減掉4*4個位元組(注意上面所說的),即
8c-4*4=7C,這個就是立即數。

所以總結抽掉的程式碼如下:
push 7C
push 0049E9C0
注:這可不是常見的push ebp什麼的啊

這兩句補完後,長度剛好相等
0047D8C8  PUSH 7C
0047D8CA  PUSH AWMAWork.0049E9C0
0047D8CF  CALL AWMAWork.0047DB94
0047D8D4  XOR EBX,EBX
0047D8D6  PUSH EBX

把入口修正為47D8C8後dump這個程式。


三、修復輸入表

執行AsprDbgr_build_106程式,一路確定,在提示偽OEP後,執行ImportREC1.6修復輸入表,在OEP中輸入7d8c8,會找到全部的api,Fixdump即可
脫完殼後,程式的nag提示都沒有了


lordor總結:
尋找OEP及修復輸入表,都是極簡單,可以用秒殺,但在修復Stolen code時我花了不少時間,參考很多文章,對blowfish老兄的方法覺得更有

價值,但操作很煩,後來我想到根據入口程式碼的情況,對照相應編譯器未加殼的程式來尋找Stolen code,這個方法更簡單實用。



By lordor 04.7.11

相關文章