2011年7月30日星期六

新手補給之脫殼+破解—— HwndSpy v1.9(Armadillo)


作 者: rocktx
時 間: 2010-06-03,22:06:42 
鏈接: http://bbs.pediy.com/showthread.php?t=114458 
【文章標題】: 新手補給之脫殼+破解—— HwndSpy v1.9(Armadillo) 
【文章作者】: rocktx 
【軟件名稱】: HwndSpy 
【軟件大小】: 920KB 
【下載地址】: http://www.highplains.net/public/HPSHwndSpy.exe 
【加殼方式】: Armadillo 
【保護方式】: Armadillo 
【編寫語言】: VC6 
【操作平台】: WinXP SP3 
【軟件介紹】: 簡直就是 SpyXX 加強版 
【作者聲明】: 拙作一篇,獻給像我一樣的精品菜鳥,好好學習,天天向上! -------------------------------------------------- ------------------------------
【詳細過程】 
  
  
  
  
一、脫殼
  
  
保護方式:
  
!- Protected Armadillo
  
Protection system (Professional)
  
!- <Protection Options>
  
Debug-Blocker
  
CopyMem-II
  
Enable Import Table Elimination
  
Enable Memory-Patching Protections
  
!- <Backup Key Options>
  
Variable Backup Keys
  
!- <Compression Options>
  
Better/Slower Compression
  
!- <Other Options>
  
!- 版本號: 4.10 08Apr2005
  
!- Elapsed Time 00h 00m 12s 734ms
  
  
重點是前三項保護方式:
  
Debug-Blocker
  
CopyMem-II
  
Enable Import Table Elimination
  
  
準備工具:
  
OD (with HideOD 插件) ——— 插件用於AntiAntiDebug
  
ArmaDetach 1.3 —————— 主要功臣,大大加快脫殼進度,有時候在處理Debug-Blocker 時,1.1 版會比較穩定
  
LordPE —————————— 處理PE 模塊
  
ImportRec 1.6 or 1.7 —— 處理IAT
  
ArmInline 0.96 —————— 處理IAT 亂序
  
FixRes —————————— 處理資源
  
ODbgScript plugin v1.47 —— OD腳本插件,一般使用1.47 或以上的版本
  
CFF Explorer —————— 又一款PE 編輯器,可以不用,純粹個人喜好
  
  
準備腳本(將下面的文本保存為.osc 或者.txt 文件):
  
////////////////////////////////////////////////// //////////////////////////////////////////////////
  
//轉單進程腳本
  
msg "請忽略所有異常,並添加忽略C000001E異常,然後運行本腳本!"
  
gpa "OpenMutexA","kernel32.dll"
  
bp $RESULT
  
esto
  
exec
  
pushad
  
pushfd
  
push edx
  
xor eax,eax
  
push eax
  
push eax
  
call kernel32.CreateMutexA
  
popfd
  
popad
  
jmp kernel32.OpenMutexA
  
ende
  
bc eip
  
msg "現已轉換成單進程!"
  
ret
  
////////////////////////////////////////////////// //////////////////////////////////////////////////
  
  
首先用HideOD 隱藏好OD,然後忽略所有異常,如果實在搞不定,可以用看雪的OllyICE;
  
  
下面開始流水作業(考慮到篇幅和精力,本人未啟用完全手脫功能);
  
  
  
1、尋找OEP
  
  
打開ArmaDetach v1.3,選擇CopyMem-II 模式,拖入HwndSpy.exe 文件,顯示信息
  
-------------------------------------
  
Filename: HwndSpy.exe
  
Parent process iD: [000004BC]
  
Processing...
  
[PROTECTiON S​​YSTEM]
  
Professional Edition
  
[PROTECTiON OPTiONS]
  
Debug-Blocker protection detected
  
CopyMem-II protection detected
  
Memory-Patching Protections enabled
  
Import Table Elimination enabled
  
[CHiLD iNFO]
  
Crypto call found: [0049BA76]
  
Child process iD: [00000D9C] // 進程ID
  
Entry point: [0042A2C6] // OEP
  
Original bytes: [558BEC6A] // OEP 處4個字節值
  
Detached successfully :)
  
-------------------------------------
  
打開OD,附加進程00000D9C 後Alt+F9,會停在OEP,還原上面的4個字節值後:
  
0042A2C6 55 push ebp
  
0042A2C7 8BEC mov ebp,esp
  
0042A2C9 6A FF push -1
  
0042A2CB 68 F8424500 push HwndSpy.004542F8
  
0042A2D0 68 B8914200 push HwndSpy.004291B8
  
0042A2D5 64:A1 00000000 mov eax,dword ptr fs:[0]
  
0042A2DB 50 push eax
  
  
  
2、處理IAT
  
  
為避免功虧一簣,這裡推薦使用ArmaDetach v1.1,拖入HwndSpy.exe 文件後顯示信息
  
-------------------------------------
  
DONE!
  
Child process ID: 0000092C // 進程ID
  
Entry point: 004BD000 // 殼的入口
  
Original bytes: 60E8 // 殼的入口處頭2個字節值
  
-------------------------------------
  
再打開一個OD,附加進程00000B54,Alt+F9返回並還原上面的2個字節到入口:
  
004BD000 > 60 pushad
  
004BD001 E8 00000000 call HwndSpy.004BD006
  
004BD006 5D pop ebp
  
004BD007 50 push eax
  
004BD008 51 push ecx
  
004BD009 0FCA bswap edx
  
004BD00B F7D2 not edx
  
004BD00D 9C pushfd
  
  
用ODbgScript v1.47 載入上面保存的腳本文件,程序會自動執行,將進程由雙變單;
  
然後he GetModuleHandleA,Shift + F9一直運行,注意觀察堆棧窗口,直到依次出現:
  
00127A6C 00D752BA /CALL 到GetModuleHandleA 來自00D752B4
  
00127A70 00D88BAC \pModule = "kernel32.dll"
  
00127A74 00D89CC4 ASCII "VirtualAlloc"
  
...
  
00127A6C 00D752D7 /CALL 到GetModuleHandleA 來自00D752D1
  
00127A70 00D88BAC \pModule = "kernel32.dll"
  
00127A74 00D89CB8 ASCII "VirtualFree"
  
...
  
001277D0 00D64F0D /CALL 到GetModuleHandleA 來自00D64F07
  
001277D4 00127920 \pModule = "kernel32.dll"
  
001277D8 00000000
  
  
取消斷點,Alt+F9返回到
  
00D64F0D 8B0D AC0DD900 mov ecx,dword ptr ds:[D90DAC]
  
00D64F13 89040E mov dword ptr ds:[esi+ecx],eax
  
00D64F16 A1 AC0DD900 mov eax,dword ptr ds:[D90DAC]
  
00D64F1B 391C06 cmp dword ptr ds:[esi+eax],ebx
  
00D64F1E 75 16 jnz short 00D64F36
  
00D64F20 8D85 B4FEFFFF lea eax,dword ptr ss:[ebp-14C]
  
00D64F26 50 push eax
  
00D64F27 FF15 B432D800 call dword ptr ds:[D832B4] ; kernel32.LoadLibraryA
  
00D64F2D 8B0D AC0DD900 mov ecx,dword ptr ds:[D90DAC]
  
00D64F33 89040E mov dword ptr ds:[esi+ecx],eax
  
00D64F36 A1 AC0DD900 mov eax,dword ptr ds:[D90DAC]
  
00D64F3B 391C06 cmp dword ptr ds:[esi+eax],ebx
  
00D64F3E 0F84 2F010000 je 00D65073 ; Magic jump,改成jmp 後,Enter 跟隨
  
  
來到
  
00D65073 83C7 0C add edi,0C
  
00D65076 89BD 78FDFFFF mov dword ptr ss:[ebp-288],edi
  
00D6507C 83C6 04 add esi,4
  
00D6507F 395F FC cmp dword ptr ds:[edi-4],ebx
  
00D65082 ^ 0F85 49FEFFFF jnz 00D64ED1
  
00D65088 EB 03 jmp short 00D6508D ; 這裡F4
  
00D6508A D6 salc
  
00D6508B D6 salc
  
00D6508C 8F ??? ; 未知命令
  
  
恢復上面的修改,在內存鏡像的.text 段F2下斷,Shift+F9運行後斷下,IAT解碼完畢;
  
  
現在回到前一個OD,右鍵查找模塊調用(Search for all intermodular calls),在結果中隨便點一個已解碼函數調用,回車後跟隨IAT地址,比如到
  
00F21748 7C80E87C kernel32.FileTimeToSystemTime
  
00F2174C 7C80E8F6 kernel32.FileTimeToLocalFileTime
  
00F21750 773D7E70 COMCTL32.CreatePropertySheetPageA
  
  
隨便複製幾個字節的二進制碼,到後一個OD 的內存鏡像中查找該值,會找到
  
00F312CC 020C0119
  
00F312D0 77F18BEE GDI32.SaveDC
  
00F312D4 7E41945D USER32.GetWindowLongA
  
00F312D8 00D6623E
  
00F312DC 7E42D312 USER32.DestroyIcon
  
00F312E0 7E42D312 USER32.DestroyIcon
  
...
  
00F31BF0 77F1E9BE GDI32.Rectangle
  
00F31BF4 7E4186C7 USER32.GetDC
  
00F31BF8 77F1DCFF GDI32.GetTextExtentPointA
  
00F31BFC 00000000
  
  
將這些已完全解碼的IAT 指針值,用二進制方式複制並粘貼到前一個OD的IAT中,注意不要錯位;
  
  
然後打開ArmInline,載入前一個OD,在輸入表亂序選項卡中填寫:
  
New base va of IAT = 0046D000
  
Length of existing IAT = 1000 (AmrInline 提供的值通常會偏小)
  
  
最後點Rebase IAT,輸入表就移動到0046D000 處了;
  
當然,如果不想用ArmInline,可以試試ImportRec的重建IAT功能;
  
  
3、dump 內存鏡像,用ImportRec 恢復一下IAT,脫殼完畢;
  
  
  
  
二、破解:
  
Armadillo 殼的破解起來比較簡單,主要用到兩個函數:LoadLibrary、GetEnvironmentVariable,對於某些版本可以
  
直接修改驗證段的返回值,但是如果程序在多處有檢測,逐一修改不僅麻煩,還有可能會錯過暗樁的處理;
  
  
  
1、bp LoadLibraryA
  
  
Armadillo 在驗證時,一般會先LoadLibrary("Armaccess.dll"),憑該函數斷點,很容易找到關鍵代碼:
  
004145A6 8D85 30FFFFFF lea eax,dword ptr ss:[ebp-D0]
  
004145AC 50 push eax
  
004145AD FF15 14D24600 call dword ptr ds:[<&kernel32.LoadLibraryA>] ; kernel32.LoadLibraryA
  
004145B3 8BF8 mov edi,eax
  
004145B5 3BFB cmp edi,ebx
  
004145B7 897D F8 mov dword ptr ss:[ebp-8],edi
  
004145BA 75 09 jnz short 004145C5 ; 成功載入就會跳走
  
004145BC 5F pop edi
  
004145BD 5E pop esi
  
004145BE 33C0 xor eax,eax ; 否則返回0,所以要讓它返回1
  
004145C0 5B pop ebx
  
004145C1 8BE5 mov esp,ebp
  
004145C3 5D pop ebp
  
004145C4 C3 retn
  
  
往上到段首
  
00414550 55 push ebp
  
00414551 8BEC mov ebp,esp
  
00414553 81EC 98010000 sub esp,198
  
00414559 53 push ebx
  
0041455A 56 push esi
  
0041455B 57 push edi
  
  
改為
  
00414550 33C0 xor eax,eax
  
00414552 40 inc eax
  
00414553 C3 retn
  
  
  
2、bp GetEnvironmentVariableA
  
  
Armadillo 會使用該函數獲取一些環境變量,也就是註冊信息,對於本程序,要檢測的變量為:
  
  
HPSKEYTYPE、USESLEFT、HPSMAXDAYS、DAYSINSTALLED、USERKEY、USERNAME、HPSVERSION、HPSPRODUCTID
  
  
當然前面還有個FIRSTRUN,這些變量名是用GetEnvironmentVariableA 斷點跟踪獲得的,本程序的調用方式如下:
  
-------------------------------------------------- ---------
  
typedef DWORD (WINAPI * PGENV)(LPCTSTR, LPTSTR, DWORD);
  
HMODULE hDLL = LoadLibrary("kernel32.dll");
  
// hDLL = GetModuleHandle("kernel32.dll");
  
if (hDLL)
  
{
    
PGENV getenv = (PGENV)GetProcAddress(hDLL, "GetEnvironmentVariableA");
    
if (getenv)
    
{
      
getenv("USERKEY", szKey, sizeof(szKey) / sizeof(TCHAR));
      
// 檢查 szKey 值
    
}
  
}
  
-------------------------------------------------- ---------
  
下面是找到的驗證過程函數之一:
  
00401A50 64:A1 00000000 mov eax,dword ptr fs:[0]
  
00401A56 6A FF push -1
  
00401A58 68 2DA04400 push 0044A02D
  
00401A5D 50 push eax
  
00401A5E 64:8925 00000000 mov dword ptr fs:[0],esp
  
00401A65 81EC E0030000 sub esp,3E0
  
00401A6B 8D4424 18 lea eax,dword ptr ss:[esp+18]
  
00401A6F 50 push eax
  
00401A70 E8 4BEB0000 call 004105C0 ; 這裡開始Patch,改成jmp 0044D150
  
00401A75 83C4 04 add esp,4
  
00401A78 85C0 test eax,eax
  
00401A7A 0F84 47090000 je 004023C7
  
  
Patch代碼:
  
0044D150 60 pushad
  
0044D151 E8 00000000 call 0044D156
  
0044D156 5F pop edi
  
0044D157 83EF 06 sub edi,6
  
0044D15A 83C7 50 add edi,50
  
0044D15D 33C0 xor eax,eax
  
0044D15F 66:8B07 mov ax,word ptr ds:[edi]
  
0044D162 66:85C0 test ax,ax
  
0044D165 74 13 je short 0044D17A
  
0044D167 03C7 add eax,edi
  
0044D169 50 push eax
  
0044D16A 66:0347 02 add ax,word ptr ds:[edi+2]
  
0044D16E 50 push eax
  
0044D16F FF15 C8D34600 call dword ptr ds:[46D3C8] ; kernel32.SetEnvironmentVariableA
  
0044D175 83C7 04 add edi,4
  
0044D178 ^ EB E3 jmp short 0044D15D
  
0044D17A 61 popad
  
0044D17B E8 4034FCFF call 004105C0
  
0044D180 ^ E9 F048FBFF jmp 00401A75
  
  
二進制:
  
60 E8 00 00 00 00 5F 83 EF 06 83 C7 50 33 C0 66 8B 07 66 85 C0 74 13 03 C7 50 66 03 47 02 50 FF
  
15 C8 D3 46 00 83 C7 04 EB E3 61 E8 40 34 FC FF E9 F0 48 FB FF
  
  
數據部分:
  
0044D1A0 00040060
  
0044D1A4 0004006C
  
0044D1A8 00040078
  
0044D1AC 00040084
  
0044D1B0 00380094
  
0044D1B4 000800D4
  
0044D1B8 000400E8
  
0044D1BC 000800F4
  
  
二進制:
  
60 00 04 00 6C 00 04 00 78 00 04 00 84 00 04 00 94 00 38 00 D4 00 08 00 E8 00 04 00 F4 00 08 00
  
  
...
  
0044D200 00000034 4...
  
0044D204 4B535048 HPSK
  
0044D208 59545945 EYTY
  
0044D20C 00004550 PE..
  
0044D210 00000031 1...
  
0044D214 53455355 USES
  
0044D218 5446454C LEFT
  
0044D21C 00000000 ....
  
0044D220 00000032 2...
  
0044D224 4D535048 HPSM
  
0044D228 41445841 AXDA
  
0044D22C 00005359 YS..
  
0044D230 00000030 0...
  
0044D234 53594144 DAYS
  
0044D238 54534E49 INST
  
0044D23C 454C4C41 ALLE
  
0044D240 00000044 D...
  
0044D244 31313131 1111
  
0044D248 31313131 1111
  
0044D24C 3232322D -222
  
0044D250 32323232 2222
  
0044D254 33332D32 2-33
  
0044D258 33333333 3333
  
0044D25C 342D3333 33-4
  
0044D260 34343434 4444
  
0044D264 2D343434 444-
  
0044D268 35353535 5555
  
0044D26C 35353535 5555
  
0044D270 3636362D -666
  
0044D274 36363636 6666
  
0044D278 00000036 6...
  
0044D27C 52455355 USER
  
0044D280 0059454B KEY.
  
0044D284 00000000 ....
  
0044D288 6B636F72 rock
  
0044D28C 00007874 tx..
  
0044D290 52455355 USER
  
0044D294 454D414E NAME
  
0044D298 00000000 ....
  
0044D29C 00000000 ....
  
0044D2A0 00000031 1...
  
0044D2A4 56535048 HPSV
  
0044D2A8 49535245 ERSI
  
0044D2AC 00004E4F ON..
  
0044D2B0 31303546 F501
  
0044D2B4 00000000 ....
  
0044D2B8 50535048 HPSP
  
0044D2BC 55444F52 RODU
  
0044D2C0 44495443 CTID
  
  
二進制:
  
34 00 00 00 48 50 53 4B 45 59 54 59 50 45 00 00 31 00 00 00 55 53 45 53 4C 45 46 54 00 00 00 00
  
32 00 00 00 48 50 53 4D 41 58 44 41 59 53 00 00 30 00 00 00 44 41 59 53 49 4E 53 54 41 4C 4C 45
  
44 00 00 00 31 31 31 31 31 31 31 31 2D 32 32 32 32 32 32 32 32 2D 33 33 33 33 33 33 33 33 2D 34
  
34 34 34 34 34 34 34 2D 35 35 35 35 35 35 35 35 2D 36 36 36 36 36 36 36 36 00 00 00 55 53 45 52
  
4B 45 59 00 00 00 00 00 72 6F 63 6B 74 78 00 00 55 53 45 52 4E 41 4D 45 00 00 00 00 00 00 00 00
  
31 00 00 00 48 50 53 56 45 52 53 49 4F 4E 00 00 46 35 30 31 00 00 00 00 48 50 53 50 52 4F 44 55
  
43 54 49 44
  
  
原理是調用SetEnvironmentVariableA 設置環境變量:
  
-------------------------------------------------- ------
  
HPSKEYTYPE = "4" (註冊碼類型,必須為4)
  
USESLEFT = "1"
  
HPSMAXDAYS = "2" (日期限制)
  
DAYSINSTALLED = "0"
  
USERKEY = "11111111-22222222-33333333-44444444-55555555-66666666" (註冊碼任意,長度區間[41, 100])
  
USERNAME = "rocktx" (用戶名任意,但不能是"DEFAULT",長度不大於100)
  
HPSVERSION = "1" (版本ID,即:1.9版,是程序之前用GetFileVersion 獲得的)
  
HPSPRODUCTID = "F501"
  
-------------------------------------------------- ------
  
  
最後要導入註冊表(要和環境變量相匹配):
  
-------------------------------------------------- ------
  
Windows Registry Editor Version 5.00
  
  
[HKEY_CURRENT_USER\Software\High Plains Software\HPS HwndSpy\User]
  
"UserName"="rocktx"
  
"User"="rocktx"
  
"RegistrationKey"="11111111-22222222-33333333-44444444-55555555-66666666"
  
-------------------------------------------------- ------
  
  
  
  
三、優化
  
  
1、挪動IAT (這一步可以合併到脫殼階段)
  
  
對於一般的VC 程序,IAT是在.rdata 區段,以Notepad98.exe 為例,用L​​ordPE 查看輸入表在00406000 處,在OD中:
  
00406000 000061B4
  
00406004 FFFFFFFF
  
00406008 FFFFFFFF
  
0040600C 00006592 // 這裡就是第一個模塊shell32.dll 的偏移,查看00406592 就會看到
  
00406010 000063F8
  
  
現在回到HwndSpy 的.rdata段,右鍵查找字符串:kernel32.dll,找到
  
0045D1BE 4E52454B KERN
  
0045D1C2 32334C45 EL32
  
0045D1C6 6C6C642E .dll
  
  
顯然,該模塊的偏移值為0005D1BE,繼續查找這個常量,來到
  
0045BFA8 00000000 // 這裡就是IAT的原始位置,RVA = 0005BFA8
  
0045BFAC 00000000
  
0045BFB0 00000000
  
0045BFB4 0005D1BE // 這裡指向kernel32.dll
  
0045BFB8 00000000
  
  
當然,kernel32.dll 不一定是第一個模塊,數據窗口中上下翻翻,自己確定一下。
  
  
從0045BFA8 到.rdata 段尾用00 清空(如果程序有導出表,注意不要一併清空了),將程序保存為一個副本0001.exe,以後的操作
  
都針對這個副本進行,打開ImportRec,選項中只勾選Create New IAT (重建IAT) ,獲取IAT 後還原到RVA 0005BFA8 處即可;
  
  
  
2、挪動資源
  
  
LordPE 查看.text1 區段的偏移為0006D000,下面的步驟就是將資源放到這裡:
  
a、用FixRes 打開0001.exe,NewRVA = 0006D000,FileAlignment = 1000,選擇導出路徑後,點Dump Resource;
  
b、用CFF Explorer 打開0001.exe,除了前三個區段,將後面的垃圾區段全部刪除(Delete Section (Header and Data))後保存;
  
c、用LordPE 打開0001.exe,查看區段表,右鍵Load section from disk...(從磁盤中載入區段),載入剛才Dump 的資源文件;
  
如果想要完美,可以將區段名改為.rsrc,區段屬性改為40000040;
  
d、修正資源的RVA 為0006D000,重建一下PE;
  
e、最後修正可選頭中的編譯器鏈接版本為0600,以免Peid 認不出來,將Base of Code 改成00001000,以免OD 分析不了代碼結構;
  
  
3、去掉多餘的菜單項( 這些菜單項的功能純粹是增加右鍵菜單長度):
  
00405CB4 8B55 04 mov edx,dword ptr ss:[ebp+4] ; 改成jmp 00405D05
  
00405CB7 6A 00 push 0
  
00405CB9 6A 00 push 0
  
00405CBB 68 00080000 push 800
  
00405CC0 52 push edx
  
00405CC1 FFD7 call edi
  00405CC3 8B45 04 mov eax,dword ptr ss:[ebp+4]
  
00405CC6 68 B8FF4500 push 0045FFB8 ; ASCII "Re&gister..."
  
  
至此,程序處理完畢,大小568 kb,可以用UPX壓縮;
  
  
  
  
-------------------------------------------------- ------------------------------ 【經驗總結】
  
全在上面了,好累,以後注意勞逸結合,Armageddon處理一下就可以了。
  
-------------------------------------------------- ------------------------------ 【版權聲明】: 本文原創於看雪技術論壇, 轉載請註明作者並保持文章的完整, 謝謝!

                                                       
2010年06月03日 22:05:12

没有评论:

发表评论