用Ollydbg手脫ArmadilloV3.60加殼的DLL
作者:fly
【作者聲明】:只是感興趣,沒有其他目的。失誤之處敬請諸位大俠賜教!
【調試環境】:WinXP、Ollydbg1.10C、PEiD、LordPE、ImportREC
—————————————————————————————————
【脫殼過程】:
Armadillo加殼DLL的脫殼筆記到現在還沒兄弟整理放上來,《加密與解密》中也沒有提及。這些天相當鬱悶,為了轉移一下心境,用了半天時間寫下這點東西,其實標準殼的DLL關鍵是重定位表的問題啦。
借用《加密與解密》第2版光碟片中附帶的EdrLib.dll為例子來示範吧,況且看雪老師還寫了EdrTest.exe,脫殼後測試很方便啦。
用Armadillo V3.60的Standard Protection Plus Debug-Blocker方式來給EdrLib.dll加殼,如果選擇CopyMem-II方式給DLL加殼,則Armadillo會警告的。看來forgot是看不到雙進程的DLL啦,呵呵。
—————————————————————————————————
一、Magic Jump + DUMP
先用LordPE看看加殼後的DLL資訊:基址=00400000,進入點=00029A93
Ollydbg1.10C調試DLL確實方便,我們不需要在入口插入CC(SoftIce調試DLL),也不需要藉助DLL_Loader.exe,所要做的就是在DLL上點右鍵,選擇“Open With Ollydbg”;當然,你要先設定菜單關聯,把Ollydbg添加進系統資源管理員裡啦。或者你願意用Ollydbg直接載入DLL也行啦。
設定Ollydbg忽略所有的異常選項。老規矩:用IsDebug 1.4外掛程式去掉Ollydbg的調試器標誌。
代碼:--------------------------------------------------------------------------------
00899A93 55 push ebp//進入OD後停在這
00899A94 8BEC mov ebp,esp
00899A96 53 push ebx
00899A97 8B5D 08 mov ebx,dword ptr ss:[ebp+8]
00899A9A 56 push esi
00899A9B 8B75 0C mov esi,dword ptr ss:[ebp+C]
00899A9E 57 push edi
00899A9F 8B7D 10 mov edi,dword ptr ss:[ebp+10]
00899AA2 85F6 test esi,esi
00899AA4 75 09 jnz short EdrLib.00899AAF
--------------------------------------------------------------------------------
偶們下斷:BP GetModuleHandleA+5,Shift+F9運行,注意看堆棧:
代碼:--------------------------------------------------------------------------------
☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
注意看BP GetModuleHandleA+5 時的堆棧變化:
0006BFA0 00A2C807 返回到 00A2C807 來自 kernel32.GetModuleHandleA
0006BFA4 00A3D6C8 ASCII "kernel32.dll"
0006BFA8 00A3E67C ASCII "VirtualAlloc"
0006BFA0 00A2C824 返回到 00A2C824 來自 kernel32.GetModuleHandleA
0006BFA4 00A3D6C8 ASCII "kernel32.dll"
0006BFA8 00A3E670 ASCII "VirtualFree"
0006BD18 00A1799B 返回到 00A1799B 來自 kernel32.GetModuleHandleA
0006BD1C 0006BE54 ASCII "kernel32.dll"//可以返回了 ★
☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
--------------------------------------------------------------------------------
看到上面的樣子就可以取消斷點,Alt+F9返回程式,修改Magic Jump了
代碼:--------------------------------------------------------------------------------
00A17995 FF15 C480A300 call dword ptr ds:[A380C4] ; kernel32.GetModuleHandleA
00A1799B 8B0D E011A400 mov ecx,dword ptr ds:[A411E0]//返回這裡
00A179A1 89040E mov dword ptr ds:[esi+ecx],eax
00A179A4 A1 E011A400 mov eax,dword ptr ds:[A411E0]
00A179A9 393C06 cmp dword ptr ds:[esi+eax],edi
00A179AC 75 16 jnz short 00A179C4
00A179AE 8D85 B4FEFFFF lea eax,dword ptr ss:[ebp-14C]
00A179B4 50 push eax
00A179B5 FF15 CC80A300 call dword ptr ds:[A380CC] ; kernel32.LoadLibraryA
00A179BB 8B0D E011A400 mov ecx,dword ptr ds:[A411E0]
00A179C1 89040E mov dword ptr ds:[esi+ecx],eax
00A179C4 A1 E011A400 mov eax,dword ptr ds:[A411E0]
00A179C9 393C06 cmp dword ptr ds:[esi+eax],edi
00A179CC 0F84 AD000000 je 00A17A7F//Magic Jump ★ 改為JMP!
00A179D2 33C9 xor ecx,ecx
00A179D4 8B03 mov eax,dword ptr ds:[ebx]
00A179D6 3938 cmp dword ptr ds:[eax],edi
00A179D8 74 06 je short 00A179E0
--------------------------------------------------------------------------------
現在我們Alt+M開啟記憶體查看視窗,看到這個DLL的給個區段
代碼:--------------------------------------------------------------------------------
00870000 00001000 EdrLib 00870000 (itself) PE header
00871000 00003000 EdrLib 00870000 .text //★ 這裡下 記憶體訪問 斷點
00874000 00001000 EdrLib 00870000 .rdata exports
00875000 00001000 EdrLib 00870000 .data data
--------------------------------------------------------------------------------
在第2個00871000的.text段上設定 記憶體訪問 斷點,F9運行,中斷在OEP
代碼:--------------------------------------------------------------------------------
008711C9 55 push ebp//OEP啦 ★
008711CA 8BEC mov ebp,esp
008711CC 53 push ebx
008711CD 8B5D 08 mov ebx,dword ptr ss:[ebp+8]
008711D0 56 push esi
008711D1 8B75 0C mov esi,dword ptr ss:[ebp+C]
008711D4 57 push edi
008711D5 8B7D 10 mov edi,dword ptr ss:[ebp+10]
008711D8 85F6 test esi,esi
008711DA 75 09 jnz short EdrLib.008711E5
008711DC 833D 60538700 00 cmp dword ptr ds:[875360],0
008711E3 EB 26 jmp short EdrLib.0087120B
008711E5 83FE 01 cmp esi,1
008711E8 74 05 je short EdrLib.008711EF
008711EA 83FE 02 cmp esi,2
008711ED 75 22 jnz short EdrLib.00871211
--------------------------------------------------------------------------------
用LordPE選中Ollydbg的loaddll.exe的進程,在下面的列表裡選擇EdrLib.dll,然後完整脫殼,得到dumped.dll。
—————————————————————————————————
二、輸入表
因為已經修改了Magic Jump,所以現在可以得到完整的輸入表。隨便從程式找個API調用:
008710FD FF15 20408700 call dword ptr ds:[874020]; kernel32.GetVersion
在轉存中跟隨874020,上下看到許多函數地址,很明顯的可以找到IAT開始和結束的地址:
代碼:--------------------------------------------------------------------------------
☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
IAT:
00874000 1D 51 C4 77 1C 3A C4 77 3E E7 C4 77 CC D2 C4 77 .Q.w.:.w>..w...w
00874010 50 88 A1 00 F1 7E E5 77 E1 C9 E5 77 38 C9 E5 77 P....~.w...w8..w
00874020 86 C4 E5 77 B5 5C E5 77 B4 16 E4 77 90 9C E5 77 ...w.\.w...w...w
00874030 C4 7C E5 77 39 9B E5 77 B4 C5 E5 77 29 2B E5 77 .|.w9..w...w)+.w
00874040 61 8B E5 77 31 C9 E5 77 3D 9C E5 77 06 84 E5 77 a..w1..w=..w...w
00874050 7A 17 E4 77 75 32 F5 77 99 A0 E5 77 B1 C5 E7 77 z..wu2.w...w...w
00874060 72 46 E5 77 24 99 E5 77 02 77 E4 77 E1 7E E5 77 rF.w$..w.w.w.~.w
00874070 0B 6E E5 77 26 C7 E5 77 34 9E E5 77 97 15 F5 77 .n.w&..w4..w...w
00874080 8C 9D E5 77 08 99 E5 77 1F E2 F7 77 00 E3 F7 77 ...w...w...w...w
00874090 F8 16 F5 77 9F 84 E5 77 3F A1 E5 77 03 C7 E4 77 ...w...w?..w...w
008740A0 0A 98 E5 77 2F 72 F5 77 FD A5 E5 77 D8 05 E6 77 ...w/r.w...w...w
008740B0 CE 7C E5 77 05 74 E5 77 F9 81 E5 77 EB 41 E4 77 .|.w.t.w...w.A.w
008740C0 66 C8 E5 77 3E 18 F6 77 C3 88 A1 00 00 00 00 00 f..w>..w........
☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
--------------------------------------------------------------------------------
開始地址=00874000
結束位址=008740C9
但是現在直接用ImportREC選取EdrLib.dll,填入RVA=00004000、大小=C9,卻提示“不能載入當前進程相關資料資訊!”
看看ImportREC的日誌:
映像基地址:00400000 大小:00097000
->> 模組被選擇! : e:\試煉場\脫殼學習\dll脫殼\armadillo\edrlib.dll\edrlib.dll
原來ImportREC顯示EdrLib.dll的基址還是00400000,呵呵
如果填入RVA=00474000、大小=C9,可以得到輸入表,卻無法完成修複抓取檔案。為何?都是重定位惹的禍啦。
於是懶人如我就想了個移花接木的辦法:再開啟一個Ollydbg,載入Win98的NotePad.EXE,然後把00874000-008740C9的資料複製、粘貼進NotePad.EXE的00404000-004040C9,然後用ImportREC選擇NotePad.EXE進程,填入RVA=00004000、大小=C9,得到輸入表,CUT掉垃圾指標,改OEP=000011C9,就可以FixDump啦!
—————————————————————————————————
三、重定位表 修複
麻煩就在這裡!因為Armadillo加殼DLL的重定位表處理方面沒有找到資料可以參考。後來我發現Armadillo加殼DLL沒有加密重定位表!終於鬆了口氣呀,我們所要做的就是找到DLL原來的重定位表的RVA和大小就行了!
我們可以從程式中找到某處需要重定位的地方,比如OEP附近的:
008711DC 833D 60538700 00 cmp dword ptr ds:[875360],0
這裡的[875360]肯定是重定位之後的,我們重新Load後對008711E0處下硬體或者記憶體訪問/寫入斷點,然後監視程式何時把008711E0處的40變化為87就能找到重定位處理的程式碼片段了!但是這樣比較麻煩,琢磨了半天(呵呵,時間都花在這裡了),提供一個簡便尋找重定位處理程式碼片段的方法!
用Ollydbg重新載入EdrLib.dll,下斷:BP GetModuleHandleA+5,Shift+F9運行,注意看堆棧:
代碼:--------------------------------------------------------------------------------
☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
注意看BP GetModuleHandleA+5 時的堆棧變化:
0006BFA0 00A2C807 返回到 00A2C807 來自 kernel32.GetModuleHandleA
0006BFA4 00A3D6C8 ASCII "kernel32.dll"
0006BFA8 00A3E67C ASCII "VirtualAlloc"
0006BFA0 00A2C824 返回到 00A2C824 來自 kernel32.GetModuleHandleA
0006BFA4 00A3D6C8 ASCII "kernel32.dll"
0006BFA8 00A3E670 ASCII "VirtualFree"
0006BD18 00A1799B 返回到 00A1799B 來自 kernel32.GetModuleHandleA
0006BD1C 0006BE54 ASCII "kernel32.dll"//返回修改Magic Jump的地方 ★
0006BD18 00A1799B 返回到 00A1799B 來自 kernel32.GetModuleHandleA
0006BD1C 0006BE54 ASCII "user32.dll"
0006BD18 00A1799B 返回到 00A1799B 來自 kernel32.GetModuleHandleA
0006BD1C 0006BE54 ASCII "advapi32.dll"
0006BFA4 00A3134F 返回到 00A3134F 來自 kernel32.GetModuleHandleA
//★ 時機到啦
☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
--------------------------------------------------------------------------------
這裡是以前返回修改Magic Jump的地方,現在我利用這個時機來搞定重定位表!
我們Alt+M開啟記憶體查看視窗,看到這個DLL的各個區段:
代碼:--------------------------------------------------------------------------------
00870000 00001000 EdrLib 00870000 (itself) PE header//★ 這裡下 記憶體訪問 斷點
00871000 00003000 EdrLib 00870000 .text
00874000 00001000 EdrLib 00870000 .rdata exports
00875000 00001000 EdrLib 00870000 .data data
--------------------------------------------------------------------------------
這次我在第1個00870000的PE header段上設定 記憶體訪問 斷點,F9運行,程式中斷在00A32393處!
代碼:--------------------------------------------------------------------------------
00A32335 87FA xchg edx,edi
00A32337 C705 DCDBA300 E4E4A>mov dword ptr ds:[A3DBDC],0A3E4E4
00A32341 A1 9C55A400 mov eax,dword ptr ds:[A4559C]
00A32346 8B00 mov eax,dword ptr ds:[eax]
//[EAX]=[008F86D1]=00006000 ★ 這個00006000就是重定位表的RVA!
00A32348 8985 48ECFFFF mov dword ptr ss:[ebp-13B8],eax
00A3234E A1 9C55A400 mov eax,dword ptr ds:[A4559C]
00A32353 83C0 04 add eax,4
00A32356 A3 9C55A400 mov dword ptr ds:[A4559C],eax
00A3235B A1 9C55A400 mov eax,dword ptr ds:[A4559C]
00A32360 8B00 mov eax,dword ptr ds:[eax]
//[EAX]=[008F86D5]=000003B0 ★ 這個000003B0就是重定位表的大小!
00A32362 8985 7CECFFFF mov dword ptr ss:[ebp-1384],eax
00A32368 A1 9C55A400 mov eax,dword ptr ds:[A4559C]
00A3236D 83C0 04 add eax,4
00A32370 A3 9C55A400 mov dword ptr ds:[A4559C],eax
00A32375 83BD 48ECFFFF 00 cmp dword ptr ss:[ebp-13B8],0
00A3237C 74 6F je short 00A323ED
00A3237E 83BD 7CECFFFF 00 cmp dword ptr ss:[ebp-1384],0
00A32385 74 66 je short 00A323ED
00A32387 8B85 0CEBFFFF mov eax,dword ptr ss:[ebp-14F4]
00A3238D 8B8D 1CEBFFFF mov ecx,dword ptr ss:[ebp-14E4]
00A32393 3B48 34 cmp ecx,dword ptr ds:[eax+34]; LOADDLL.00400000
//中斷在這裡!
00A32396 74 55 je short 00A323ED//如與映像基址不符則重定位處理!★
00A32398 FFB5 7CECFFFF push dword ptr ss:[ebp-1384]
00A3239E 8B85 1CEBFFFF mov eax,dword ptr ss:[ebp-14E4]
00A323A4 0385 48ECFFFF add eax,dword ptr ss:[ebp-13B8]
00A323AA 50 push eax
00A323AB 8B85 0CEBFFFF mov eax,dword ptr ss:[ebp-14F4]
00A323B1 FF70 34 push dword ptr ds:[eax+34]
00A323B4 FFB5 1CEBFFFF push dword ptr ss:[ebp-14E4]
00A323BA E8 A8100000 call 00A33467//重定位處理CALL ★
00A323BF 83C4 10 add esp,10
00A323C2 0FB6C0 movzx eax,al
00A323C5 85C0 test eax,eax
00A323C7 75 24 jnz short 00A323ED
00A323C9 8B45 08 mov eax,dword ptr ss:[ebp+8]
00A323CC 8B00 mov eax,dword ptr ds:[eax]
00A323CE C700 07000000 mov dword ptr ds:[eax],7
00A323D4 68 D4E4A300 push 0A3E4D4 ; ASCII "Location CPG"
00A323D9 8B45 08 mov eax,dword ptr ss:[ebp+8]
00A323DC FF70 04 push dword ptr ds:[eax+4]
00A323DF E8 68530000 call 00A3774C ; jmp to MSVCRT.strcpy
00A323E4 59 pop ecx
00A323E5 59 pop ecx
00A323E6 33C0 xor eax,eax
00A323E8 E9 BB030000 jmp 00A327A8
--------------------------------------------------------------------------------
呵呵,00A323BA的CALL裡面就是重定位處理的核心,如果採用在重定位後的地址下記憶體斷點的方法,最終會中斷在這個CALL裡面的。其實在這個CALL的上面我們就可以得到DLL原先的重定位表的RVA和大小!
下硬體執行斷點:HE 00A32346,Ctrl+F2重新載入這個DLL,Shift+F9運行,程式中斷在00A32346處!分析見上。
—————————————————————————————————
四、修正 + 最佳化
用LordPE修正dumped_.dll的重定位表RVA=00006000、大小=000003B0,儲存之。
如果在00A32396處修改為JMP跳過重定位處理,則不需要修改DLL的基址,否則修改基址為OEP處看到的基址,如這裡為00870000用LordPE刪除dumped_.dll的text1和其下的adata、data1、reloc1、pdata共5個區段,然後去掉“脫殼修複”和“清除重定位表”選項,重建PE簡單最佳化一下脫殼後的檔案,608K->17K,暈,比加殼前的原檔案還小了。
脫殼後的DLL用PEiD看依舊顯示“Armadillo 2.51-3.xx DLL Stub -> Silicon Realms Toolworks”,呵呵。用FI看顯示“MS VC++ v6.0 {DLL} ”。如果想測試脫殼後的DLL,可以把UnPacked-EdrLib.dll重新命名為EdrLib.dll,然後運行EdrTest.exe就知道是否脫殼成功了。
其實熟悉之後完全可以一次完成脫殼,為了說的詳細點,所以分了幾次。經驗來自於不斷的實踐、總結和積累。
拙文一篇,僅供各位對DLL脫殼感興趣的兄弟參考。