Armadillo 2.52加殼原理分析和改進的脫殼方法 (12千字)
目標軟體:The Armadillo Software Protection System Version2.52 build 1164
目標檔案:Armadillo.exe
加殼方式:Armadillo 2.52
使用工具:WinDbg或trw2000, peditor, WinHex 10.2 SR-2,m$的win32
sdk文件,<winnt.h>
URL:
http://www.siliconrealms.com/
本文作者:leo_cyl
Armadillo
的保護方式主要有以下特點:修改pe頭,使WinDbg等偵錯程式無法“attach”,使procdump無法dump;anti-debug程式碼(我以前的貼子有討論);利用偵錯程式捕獲頁面保護異常,分段解碼。
(一)捕獲頁面保護異常、找OEP
和以前版本一樣,Armadillo 外殼產生另外一個程式(被加殼的程式)。所以下斷點“bpx
createprocessa”
004C39E4
call ds:CreateProcessA
004C39EA
test eax, eax
004C39EC
jnz 4C39F5
……
……
0187:004C3A0F 51
PUSH ECX
0187:004C3A10 68E6314C00 PUSH
DWORD 004C31E6
0187:004C3A15 6A00
PUSH BYTE +00
0187:004C3A17 6A00
PUSH BYTE +00
0187:004C3A19 FF1554A04C00
CALL `KERNEL32!CreateThread`
0187:004C3A1F 6A00
PUSH BYTE +00
0187:004C3A21
FF1530A14C00 CALL `KERNEL32!GetModuleHandleA`
……
……
……
0187:004C3A42 6A00
PUSH BYTE +00
0187:004C3A44 FF1530A14C00 CALL
`KERNEL32!GetModuleHandleA`
……
……
0187:004C3A68 E80C0C0000
CALL 004C4679
0187:004C3A6D 83C40C
ADD ESP,BYTE +0C
0187:004C3A70 8B8D68FEFFFF
MOV ECX,[EBP+FFFFFE68]
0187:004C3A76 51
PUSH ECX
0187:004C3A77
8B157CE54C00 MOV EDX,[004CE57C]
0187:004C3A7D
52 PUSH EDX
0187:004C3A7E E8BA0C0000 CALL 004C473D
以上程式碼在被加殼的程式第一條指令處寫入“eb fe”程式碼,即“jmp eip” 使被加殼程式“掛起”
0187:004C3A83
83C408 ADD ESP,BYTE +08
0187:004C3A86 A17CE54C00 MOV EAX,[004CE57C]
0187:004C3A8B 8B4804 MOV
ECX,[EAX+04]
0187:004C3A8E 51
PUSH ECX
0187:004C3A8F FF158CA04C00 CALL
`KERNEL32!ResumeThread`
0187:004C3A95 8B157CE54C00 MOV
EDX,[004CE57C]
0187:004C3A9B 8B4208
MOV EAX,[EDX+08]
0187:004C3A9E 50
PUSH EAX
0187:004C3A9F FF1588A04C00
CALL `KERNEL32!DebugActiveProcess`
0187:004C3AA5 8B0D7CE54C00
MOV ECX,[004CE57C]
0187:004C3AAB 8B5104
MOV EDX,[ECX+04]
0187:004C3AAE
52 PUSH EDX
0187:004C3AAF FF1584A04C00 CALL `KERNEL32!SuspendThread`
以上程式碼通過呼叫“DebugActiveProcess”開始除錯被加殼的程式。
……
……
……
0187:004C3AFA 68E8030000 PUSH DWORD 03E8
《===== dwMilliseconds
0187:004C3AFF 8B9574FEFFFF MOV
EDX,[EBP+FFFFFE74]
0187:004C3B05 52
PUSH EDX 〈====
lpDebugEvent
0187:004C3B06 FF1580A04C00 CALL `KERNEL32!WaitForDebugEvent`
0187:004C3B0C 85C0 TEST
EAX,EAX
0187:004C3B0E 0F8414060000 JZ NEAR
004C4128
0187:004C3B14 C78570FDFFFF68B4+MOV DWORD [EBP+FFFFFD70],004CB468
0187:004C3B1E 33C0 XOR
EAX,EAX
0187:004C3B20 A06EE54C00 MOV
AL,[004CE56E]
0187:004C3B25 85C0
TEST EAX,EAX
0187:004C3B27 7565
JNZ 004C3B8E
0187:004C3B29 8B4DE4
MOV ECX,[EBP-1C]
0187:004C3B2C
81E1FF000000 AND ECX,FF
0187:004C3B32 85C9
TEST ECX,ECX
0187:004C3B34
7458 JZ 004C3B8E
〈==跳轉
0187:004C3B36 C645E400 MOV
BYTE [EBP-1C],00
0187:004C3B3A C745FC00000000 MOV
DWORD [EBP-04],00
0187:004C3B41 669C
PUSHFW +
0187:004C3B43
6658 POP AX
|
0187:004C3B45 66056200
ADD AX,62 |設定單步除錯標誌
0187:004C3B49 66059E00
ADD AX,9E |anti-debug???
0187:004C3B4D 6650 PUSH
AX |
0187:004C3B4F 669D
POPFW +
0187:004C3B51
66050100 ADD AX,01
0187:004C3B55
C745FCFFFFFFFF MOV DWORD [EBP-04],FFFFFFFF
0187:004C3B5C
EB30 JMP SHORT 004C3B8E
以上進入除錯迴圈,根據DebugEvent結構中的debugging event code 做相應處理。其中最重要的是EXCEPTION_DEBUG_EVENT(0x00000001)。請參考MSDN中WaitForDebugEvent的描述。
……
……
0187:004C3BA5 MOV DWORD [EBP+FFFFFB60],80010001
0187:004C3BAF MOV EDX,[EBP+FFFFFE74] 〈====注意!edx
= lpDebugEvent
0187:004C3BB5 CMP DWORD [EDX],BYTE +01
//EXCEPTION_DEBUG_EVENT
0187:004C3BB8 JNZ
NEAR 004C3ED7
0187:004C3BBE MOV DWORD [EBP+FFFFFD70],004CB470
0187:004C3BC8 XOR EAX,EAX
0187:004C3BCA MOV
AL,[004CE56F]
0187:004C3BCF TEST EAX,EAX
0187:004C3BD1 JZ NEAR 004C3CB7
0187:004C3BD7 MOV
ECX,[EBP+FFFFFE74]
0187:004C3BDD CMP DWORD
[ECX+0C],80000001 //STATUS_GUARD_PAGE_VIOLATION
0187:004C3BE4
JNZ NEAR 004C3CB7
0187:004C3BEA MOV
DWORD [EBP+FFFFFD70],004CB488
0187:004C3BF4 MOV EDX,[EBP+FFFFFE74]
〈====注意!edx = lpDebugEvent
0187:004C3BFA MOV EAX,[EDX+24]
……
……
0187:004C3BB5 處比較是否是EXCEPTION_DEBUG_EVENT。(包括頁面異常)
注意在NT下,頁面異常的程式碼是0x80000001(STATUS_GUARD_PAGE_VIOLATION)而9x下是0xc0000005(STATUS_ACCESS_VIOLATION)所以在9x下會來到這裡:
0187:004C3CBD CMP DWORD [ECX+0C],C0000005
//STATUS_ACCESS_VIOLATION
0187:004C3CC4 JNZ NEAR
004C3E89
0187:004C3CCA MOV EDX,[EBP+FFFFFE74] 〈====注意!edx
= lpDebugEvent
0187:004C3CD0 CMP DWORD [EDX+5C],BYTE
+00
0187:004C3CD4 JZ 004C3CE2
0187:004C3CD6 MOV
DWORD [EBP+FFFFFD70],004CB4E8
0187:004C3CE0 JMP
SHORT 004C3CEC
當被加殼的程式需要解碼時,會觸發頁面異常,來到上述程式碼,如果你參考MSDN中有關DebugEvent結構的描述,很容易找到產生頁面異常的地址,是在lpDebugEvent+0x18處。(即edx+18)。
這有什麼用呢?呵呵……這是找OEP的關鍵!!!假如在0187:004C3CD0下斷點,當程式第一次在這裡中斷時,檢視edx+18h的內容“dd edx+18”即可看到OEP。(41EF80H)
繼續跟蹤……
0187:004C3D52 8B8D50FBFFFF MOV
ECX,[EBP+FFFFFB50]
0187:004C3D58 83E901
SUB ECX,BYTE +01
0187:004C3D5B 85C9
TEST ECX,ECX
0187:004C3D5D 7C14
JL 004C3D73
0187:004C3D5F
6A01 PUSH BYTE +01
0187:004C3D61 8B9550FBFFFF MOV EDX,[EBP+FFFFFB50]
0187:004C3D67 83EA01 SUB
EDX,BYTE +01
0187:004C3D6A 52
PUSH EDX
0187:004C3D6B E8D0030000 CALL
004C4140 //關鍵,進入
0187:004C3D70
83C408 ADD ESP,BYTE +08
0187:004C3D73 8B8550FBFFFF MOV EAX,[EBP+FFFFFB50]
0187:004C3D79 83C001 ADD
EAX,BYTE +01
0187:004C3D7C 3B0588E54C00 CMP
EAX,[004CE588]
0187:004C3D82 7D14
JNL 004C3D98
以上程式碼將產生頁面異常的地址進行頁對齊,並CALL 004C4140解碼。
進入函式004C4140後,來到這裡:
0187:004C4271 PUSH BYTE +00
0187:004C4273 MOV ECX,[EBP+08]
0187:004C4276 PUSH
ECX
0187:004C4277 CALL 004C432A 〈==這裡對異常頁解碼
0187:004C427C ADD ESP,BYTE +08
0187:004C427F AND
EAX,FF
0187:004C4284 TEST EAX,EAX
0187:004C4286
JNZ 004C428F〈===解碼成功?
0187:004C4288 XOR
AL,AL
0187:004C428A JMP 004C4326
0187:004C428F
MOV EDX,[004CE58C] 〈==注意!!!
0187:004C4295 ADD
EDX,BYTE +01
0187:004C4298 MOV [004CE58C],EDX
0187:004C429E MOV EAX,[004CE588]
0187:004C42A3 LEA
ECX,[EAX*4+FFFFFFFC]
注意0187:004C428F處,[004CE58C]是一個記數器,解碼成功後加一,有什麼用呢?看後面……
……
……
0187:004C42D1 25FF000000 AND
EAX,FF
0187:004C42D6 85C0
TEST EAX,EAX
0187:004C42D8 754A
JNZ 004C4324
0187:004C42DA 8B0D8CE54C00
MOV ECX,[004CE58C]
0187:004C42E0 3B0D2CB44C00
CMP ECX,[004CB42C]
0187:004C42E6 7E3C
JNG 004C4324
0187:004C42E8
6A01 PUSH BYTE +01
0187:004C42EA 8B158CE54C00 MOV EDX,[004CE58C]
當解碼一定數量的頁面後,將以前解碼的頁面重新加密!在這裡的數量是0x13頁。為了以後脫殼方便。
我用peditor計算出0187:004C428F的實際偏移,然後用WinHex,將ADD
EDX,BYTE +01改為ADD EDX,BYTE +00;只改了一個byte。
簡要分析0187:004C4277處的解碼函式“ CALL
004C432A”。以下是它的流程:
1。呼叫VirtualProtectEx將異常頁面屬性改為PAGE_READWRITE
2。呼叫ReadProcessMemory,將異常頁面讀入
3。解碼。
4。呼叫WriteProcessMemory,寫入正確程式碼。
5。呼叫VirtualProtectEx將頁面屬性改為PAGE_EXECUTE_READ
(二)修改PE頭
被加殼的程式執行後,用procdump沒法dump出,會非法操作。用ring3的偵錯程式沒法“attach”,用peditor
dump出的檔案是無效的exe。為什麼呢?通過比較dump出的PE頭,發現偏移0x3c處被修改。重新裝入Armadillo,下斷點“bpm 400003c
w”,執行……
0187:00A8EF54 MOV EAX,[EBP-0C] 〈==
EAX=400000H
0187:00A8EF57 LEA ECX,[EBP-04]
0187:00A8EF5A SUB EBX,EDI 〈=== EBX = 4E7119
0187:00A8EF5C PUSH ECX
0187:00A8EF5D ADD
[EAX+3C],EBX 〈== 修改PE頭,[EAX+3C] = 40003C
0187:00A8EF60 PUSH
DWORD [EBP-04]
0187:00A8EF63 PUSH BYTE +40
……
……
……
0187:00A8EF89 AND EAX,BYTE +03
0187:00A8EF8C
LEA ECX,[EBP-08]
0187:00A8EF8F INC
EAX
0187:00A8EF90 ADD [EDI+06],AX 〈==修改PE頭,[EDI+06]
= 4000FE
0187:00A8EF94 CALL 00A88597
0187:00A8EF99 MOV
EBX,EAX
共修改3C和FE兩處,參考有關PE頭的資料,可知偏移3C的DWORD是PE表頭的偏移(原值是F8)。偏移FE的WORD是sections
的個數(原值是8)。Armadillo故意將PE頭改錯,難怪沒法dump出。
(三)dump出加殼的程式
好了,原理分析清楚了。要dump出加殼程式就很容易了。
事先用peditor檢視,得知size of image 是104000;
首先找到OEP是41EF80,另外修改004C428F,將ADD
EDX,BYTE +01改為ADD EDX,BYTE +00。
在41EF80下斷點。中斷後,將PE頭改回,40003C處是000000F8,4000FE處是0008,注意高位在前!!!
在程式中找一個沒用到的地址。不要選程式碼段,因為解碼後會覆蓋掉我們寫的程式碼。我選.Data1段的最後256個byte即4CF000處,將eip改為4CF000,輸入以下程式碼:
push esi
push ecx
push eax
mov esi,401000
mov ecx,103000
//size of image 減 1000h
rep lodsb
pop eax
pop ecx
pop esi
int3
注意我沒有使用hying的程式碼,因為要申請記憶體和查詢api地址,而且記憶體不夠的話也麻煩,其實只要掃描一遍記憶體就足以觸發偵錯程式了,修改004C428F的原因就是防止外殼把解碼過的頁面從新加密。
f5執行,在int3處停下(注意開啟 i3here on),將eip改回41EF80,可看到已經解碼了,掛起程式,回到window桌面,這時用什麼工具都可以dump出了!(任我魚肉了!!)。
另外,還有一個地方要注意,最好在OEP處掛起程式再dump,因為這時程式的初始化變數還沒有被修改。
大家可對比一下,當程式執行後,用procdump
dump出的檔案和在OEP處dump出的有何不同。(會非法操作!!因為初始化變數[438110]已經不同了。)
(四)修復IAT
沒什麼方便的方法!:(
我的方法是用peditor檢視,得知IAT在426000處,下斷點“bpm 426000 w” 在這停下:
0187:00A8E4BB 8A06 MOV
AL,[ESI]
0187:00A8E4BD 3AC3
CMP AL,BL
0187:00A8E4BF 7468
JZ 00A8E529
0187:00A8E4C1 3CFF
CMP AL,FF
0187:00A8E4C3 7537
JNZ 00A8E4FC
0187:00A8E4C5
668B7E01 MOV DI,[ESI+01]
0187:00A8E4C9
46 INC ESI
0187:00A8E4CA 0FB7C7 MOVZX
EAX,DI
0187:00A8E4CD 50 PUSH
EAX
0187:00A8E4CE 46
INC ESI
0187:00A8E4CF FF75F4
PUSH DWORD [EBP-0C]
0187:00A8E4D2 46
INC ESI
0187:00A8E4D3 E84075FFFF
CALL 00A85A18
然後把[ESI]前後的內容儲存下來,以後手工修復IAT時參考。
(五)小結
無論用什麼方法脫殼,原理和hying的是一樣的。
但為什麼用procdump 不會觸發偵錯程式呢?我的解釋是這樣:無論procdump
或 WinHex 在讀取其他程式的內容時,是通過WriteProcessMemory來完成的,而WriteProcessMemory最終呼叫VMM完成讀取,VMM是在ring0上,所以不會觸發ring3上的偵錯程式。我能想到的方法是:在ring3下、在自身程式空間內掃描整個記憶體,以觸發偵錯程式。
附錄:
附上部分DEBUG_EVENT結構的宣告:(註釋是我加的)
typedef struct _DEBUG_EVENT
{
DWORD dwDebugEventCode; //偏移0x0
DWORD dwProcessId;
//偏移0x4
DWORD dwThreadId;
//偏移0x8
union {
EXCEPTION_DEBUG_INFO Exception;
//偏移0xC
CREATE_THREAD_DEBUG_INFO CreateThread;
CREATE_PROCESS_DEBUG_INFO CreateProcessInfo;
EXIT_THREAD_DEBUG_INFO ExitThread;
EXIT_PROCESS_DEBUG_INFO
ExitProcess;
LOAD_DLL_DEBUG_INFO LoadDll;
UNLOAD_DLL_DEBUG_INFO UnloadDll;
OUTPUT_DEBUG_STRING_INFO
DebugString;
RIP_INFO RipInfo;
} u;
} DEBUG_EVENT, *LPDEBUG_EVENT;
typedef struct _EXCEPTION_DEBUG_INFO
{ //即異常程式碼是0x00000001時的結構
EXCEPTION_RECORD ExceptionRecord;
//偏移0xC;0x80000001為STATUS_GUARD_PAGE_VIOLATION(NT)
//0xC0000005為STATUS_ACCESS_VIOLATION(WIN (win
9x)
DWORD dwFirstChance;
} EXCEPTION_DEBUG_INFO, *LPEXCEPTION_DEBUG_INFO;
typedef struct _EXCEPTION_RECORD {
DWORD ExceptionCode;
//偏移0xc
DWORD ExceptionFlags;
//偏移0x10
struct _EXCEPTION_RECORD
*ExceptionRecord; //偏移0x14
PVOID ExceptionAddress;
//偏移0x18
DWORD NumberParameters;
ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
} EXCEPTION_RECORD, *PEXCEPTION_RECORD;
相關文章
- 關於Armadillo 1.8x-2.x的anti-debug&加殼原理初步探討和脫殼方法
(12千字)2002-04-11
- 脫殼----對用pecompact加殼的程式進行手動脫殼
(1千字)2000-07-30
- 脫殼----對用Petite2.2加殼的程式進行手動脫殼的一點分析
(5千字)2000-07-27
- 用Armadillo標準加殼的程式的脫殼和引入表修復方案---OLLYDBG (8千字)2015-11-15
- Armadillo3.60
加殼的EXE檔案脫殼全過程2004-09-08
- 壹次脫殼法――Armadillo 雙程式標準殼 快速脫殼2015-11-15
- 對PECompact加殼的DLL脫殼的一點分析 (7千字)2000-08-17
- 殼的工作原理脫殼2013-04-10
- Armadillo 3.6主程式脫殼2015-11-15
- ASPROtect 1.22加殼的ahaview2.0脫殼 (5千字)2002-03-24View
- 實戰Armadillo V3.60標準加殼方式的脫殼――WinXP的Notepad2015-11-15
- 股市風暴4.0的外殼分析與脫殼方法(一) (7千字)2001-06-10
- telock脫殼總結 (12千字)2001-09-27
- Armadillo V3.01標準加殼方式的脫殼(第一篇)--SoundEdit
Pro2015-11-15
- Armadillo V2.xx標準加殼方式的脫殼(第二篇)--Virtual
Personality 4.02015-11-15
- 手動脫殼的教程(由petite v2.2加殼) (4千字)2001-11-26
- Armadillo V3.6雙程式標準殼 ------神速脫殼大法2015-11-15
- 談談如何使用加殼保護自己的軟體不被常用方法脫殼(2千字)2000-10-10
- 關於用ASProtect v1.3加殼軟體的脫殼方法體會 (5千字)2001-11-21
- iOS逆向學習之五(加殼?脫殼?)2019-10-10iOS
- Asprotect 1.2x 加殼的 Advanced Direct
Remailer 2.17 脫殼 (3千字)2002-06-20REMAI
- 脫ASPack2.12加殼的DLL檔案簡便方法2004-12-18
- 以殼解殼--SourceRescuer脫殼手記破解分析2004-11-16
- 用OD對Aspr加殼程式的手動脫殼及修復 (7千字)2015-11-15
- 先分析,再脫殼(二) (13千字)2003-09-04
- 關於雙程式Armadillo標準殼的脫法2015-11-15
- Armadillo殼時間問題的解決And脫殼――Mr.Captor
V2.82015-11-15APT
- 怎樣脫pklite32, Shrinker 3.4 和 NeoLite加的殼(3千字)2000-07-31
- ASPRTECT1.2X加殼的Delphi
Application Peeper Pro 2.3.1.9 脫殼(簡單) (3千字)2002-04-06APP
- EmbedPE
1.13 詳細分析和脫殼2005-01-03
- ExeStealth 常用脫殼方法 + ExeStealth V2.72主程式脫殼2015-11-15
- FTPrint的脫殼(asprotect) (2千字)2001-02-05FTP
- Thebat!139脫殼詳情及對Asprotect加殼保護的一點小結
(4千字)2000-03-27BAT
- 對Crunch v1.1加殼程式的手動脫殼及反跟蹤程式碼的一點分析
(15千字)2000-10-02
- C32Asm外殼脫殼分析筆記2015-11-15ASM筆記
- 先分析,再脫殼(一)2003-09-04
- Krypton
0.5加殼程式脫殼及輸入表修復記2004-10-06
- 脫Crunch/PE -> BitArts的殼。 (3千字)2002-05-03