Armadillo脫殼知識與方法大全
發(fā)表時間:2023-05-31 來源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]近日對Armadillo殼很感興趣, 緣于它的多種組合的變化, 但仔細(xì)看來, 其保護(hù)的解決方法又有相對固定。 方法無外乎那么幾種脫殼方法(當(dāng)然排除有key和cc), 本人在本論 壇已對標(biāo)準(zhǔn)殼...
近日對Armadillo殼很感興趣, 緣于它的多種組合的變化, 但仔細(xì)看來, 其保護(hù)的解決方法又有相對固定。 方法無外乎那么幾種脫殼方法(當(dāng)然排除有key和cc), 本人在本論
壇已對標(biāo)準(zhǔn)殼的脫殼方法發(fā)貼, 但后來有所更新, 干脆總結(jié)在一塊吧, 以方便大家。 大家可以復(fù)制下來, 放在手邊, 脫殼時按步驟來。 我還是
一小鳥, 同大家一樣在逐漸成長中, 有不對的地方和不成熟的地方, 望大家批評指正, 共同進(jìn)步。
一、基本知識:
該殼有如下保護(hù):
(1)Debug-Blocker(阻止調(diào)試器)--解決方法就是忽略所有異常, 隱藏好OD, 如果加載時, 老出錯, 就多換幾個OD試試。
(2)CopyMem-II(雙進(jìn)程保護(hù))---解決方法是:用手動或者腳本使雙變單。
(3) Enable Import Table Elimination(IAT保護(hù)) –解決方法是用工具ArmaDetach再次載入加殼程序, 記下子進(jìn)程ID, 用另一OD載入, 利用斷
點(diǎn)GetModuleHandleA, 找到Magic Jump, 修改Magic Jump, 得到正確的IAT。
(4)Enable Strategic Code Splicing(遠(yuǎn)地址跳) , 解決方法就是用Arminline工具。
(5) Enable Nanomites Processing(簡稱CC), 就是把一些retn代碼變成CC(INT型), 解決方法:用Arminline工具或Enjoy工具。
(6)Enable Memory-Patching Protections(內(nèi)存保護(hù))
二、脫此類殼常用的斷點(diǎn):
1、WaitForDebugEvent(用于尋找非標(biāo)準(zhǔn)OEP和做補(bǔ)丁用)
2、WriteProcessMemory(用于尋找非標(biāo)準(zhǔn)OEP)
3、DebugActiveProcess(找子程)
4、OpenMutexA(雙進(jìn)程轉(zhuǎn)單進(jìn)程)
5、GetSystemTime(補(bǔ)丁KEY)
6、VirtualProtect(用于5.x)
7、CreateFileMappingA(用于5.x)
8、GetModuleHandleA/LoadLibraryA (用于找Magic Jump)
9、CreateThread(尋找OEP)
三、種類及脫殼方法
說明:對于此殼一般要隱藏OD。 如果按以下方法下斷OD斷不下來, 出錯, 就多換幾個OD試試, 在我脫殼中, 就有個情況, 下斷點(diǎn)后, 老斷不下
來, 多換了幾個OD就成功了。
(一)單線程標(biāo)準(zhǔn)方式
具體方法:2次斷點(diǎn)法加修改Magic Jump。
1、找Magic Jump
方法有二:
方法一、下斷點(diǎn)Bp GetModuleHandleA/he GetModuleHandleA/bp GetModuleHandleA+5/he GetModuleHandleA+5, 按shift+f9運(yùn)行, 當(dāng)經(jīng)過一個
call緩沖有點(diǎn)大時, 一般是在堆棧窗口出現(xiàn)ASCII "kernel32.dll"和ASCII "VirtualFree“后, 再運(yùn)行一次, 出現(xiàn)"kernel32.dll", 就是返回
時機(jī), 取消斷點(diǎn), 按alt+f9執(zhí)行到返回。
方法二、也可以下bp LoadLibraryA斷點(diǎn), 當(dāng)在堆棧窗口出現(xiàn)MSVBVM60.Dll函數(shù)時, 返回時機(jī), 在kernel32.LoadLibraryA下面有一個跳轉(zhuǎn), 一
般情況下, 這個跳轉(zhuǎn)比較大的話, 就改為jmp, 而跳轉(zhuǎn)比較小的話, 就改nop)。 [注:下此斷點(diǎn)的目的是找到Magic Jump, 修改Magic Jump目的
是避開的IAT的加密。 ]
2、找OEP
下斷點(diǎn)bp GetCurrentThreadId/bp CreateThread, shift+f9運(yùn)行, 中斷后, 取消斷點(diǎn), Alt+F9返回, 單步執(zhí)行, 看到一個call edi之類的。 F7
進(jìn)入, 即到oep。 OD不要關(guān)!打開import--選擇進(jìn)程--OEP輸入va--自動搜索IAT--獲取輸入表--顯示無效函數(shù)--CUT!
(二) 雙線程的標(biāo)準(zhǔn)殼
總體步驟:1、要雙變單;2、處理IAT, 修改Magic Jump;3、尋找OEP;4、修復(fù)
1、雙變單, 方法有三。
方法一:PATCH代碼法
下斷bp OpenMutexA, 斷下后, ctrl+g到00401000, 將空數(shù)據(jù)改為如下代碼:
0040100060 pushad
004010019C pushfd
00401002 68 A0FD1200 push xxxx(注:此處的xxxx為斷下后mutex name前的數(shù)值。 )
0040100733C0 xor eax,eax
0040100950 push eax
0040100A50 push eax
0040100BE8 E694A677call KERNEL32.CreateMutexA
004010109D popfd
0040101161 popad
00401012- E9 8F9FA777jmp KERNEL32.OpenMutexA
點(diǎn)右鍵選擇重建eip,f9運(yùn)行, 斷下后,取消斷點(diǎn), ctrl+g到00401000, 恢復(fù)修改。
方法二, 下斷點(diǎn):bp OpenMutexA, SHIFT+F9, 斷下后, ALT+F9返回, 返回后, 將返回代碼下面的第一個跳轉(zhuǎn)改為相反跳轉(zhuǎn), 再次SHIFT+F9,
斷下后, ALT+F9返回, 再次將返回代碼下面的第一個跳轉(zhuǎn)改為相反跳轉(zhuǎn)。 然后再一次SHIFT+F9,取消斷點(diǎn), 至此,同樣,雙進(jìn)程轉(zhuǎn)單進(jìn)程完畢!
方法三、除了用雙變單的腳本外, 還可以用一個工具ARMADETACH, 將帶殼的程序拖入, 記下子進(jìn)程的ID。
2、處理IAT, 修改Magic Jump。
用OD附加該子進(jìn)程, 加載后, ALT+F9返回, 修改前兩個字節(jié)為加殼程序載入時的前兩個字節(jié)。
下斷點(diǎn)bpGetModuleHandleA, Shift+F9運(yùn)行, 一般是在堆棧窗口出現(xiàn)ASCII "kernel32.dll"和ASCII "VirtualFree“后, 再運(yùn)行一次, 出現(xiàn)
"kernel32.dll", 就是返回時機(jī), 中斷后alt+f9返回,在KERNEL32.LoadLibraryA下面找到Magic Jump!修改為jmp。 再下斷點(diǎn)bp
GetCurrentThreadId/bp CreateThread(或往下拉找到兩個salc, 在其上面的jmp上下斷, Shift+F9, 斷下!如果文件有校驗(yàn), 則要撤消Magic
Jump處的修改!打開內(nèi)存鏡像, 在00401000段下斷。 運(yùn)行, 中斷后, 刪除斷點(diǎn), alt+f9返回), F8單步走, 到第一個CALL ECX之類的東西時,
F7進(jìn)入。 到oep。
注:(對于有些OD有一個字符串溢出漏洞, 盡量用一些修正些錯誤的OD, 有些程序需要處理Anti, 方法如下:下斷點(diǎn)he OutputDebugStringA
斷下后, 選中%s%之類的字符, 在數(shù)據(jù)窗口跟隨, 點(diǎn)右鍵->二進(jìn)制->使用00填充, 中斷2次!都如上修改, 刪除此斷點(diǎn)。
3、修復(fù)。
(三)CopyMem-ll +Debug-Blocke保護(hù)方式
1、先找OEP, 兩個斷點(diǎn)。 (1)斷點(diǎn)bp WaitForDebugEvent,運(yùn)行, 中斷后看堆棧, 在一行有“pDebugEvent”字樣的那一行右鍵點(diǎn)擊“數(shù)據(jù)窗口
跟隨”, 取消斷點(diǎn)。 (2)bp WriteProcessMemory,運(yùn)行, 中斷后, 在數(shù)據(jù)窗口(要地址顯示)發(fā)現(xiàn)oep。
2、patch代碼, 解碼。 方法:重新載入, bp WaitForDebugEvent,運(yùn)行, 中斷, 取消斷點(diǎn), alt+f9返回, CTRL+F搜索命令:or eax, 0FFFFFFF8
, 找到后, 先往上看, 可以看到兩個CMP, 一個是“cmp dword ptr ss:[XXXX],0”在這里下硬件執(zhí)行斷點(diǎn), Shift+F9運(yùn)行, 中斷后取消斷點(diǎn)。
這時看信息窗口:SS[XXXXX]=00000000, 如果這個值不為0的話, 需要將其清0, 如果為0就不用了。 第二個CMP, cmp ecx,dword ptr ds:[XXXX]
, 下面開始解碼。 在這里要記下幾個地址:(1)cmp dword ptr ss:[XXXX],0前的地址和[]內(nèi)的值。 (2)第二個CMP中[]中的值。 接著or eax
, 0FFFFFFF8處往下, 可以找到一處為and eax, 0FF的代碼, 從這里開始Patch, 代碼如下:
inc dword ptr ds:[] //第一個CMP內(nèi)的值
mov dword ptr ds:[XXXX+4],1//XXXX為第二個CMP[]內(nèi)的值
jmp XXXX//第一個CMP前的地址
修改好后, 去掉所有斷點(diǎn), 向下找到第一個CMP下面的跳轉(zhuǎn)所跳到的地址, 來到這個地址, 下硬件執(zhí)行斷點(diǎn), Shift+F9運(yùn)行, 此時代碼解壓完畢
, 可以脫殼。
3、脫殼。 運(yùn)行LordPE,將子進(jìn)程dump出來, 這里的子進(jìn)程就是LordPE第2個進(jìn)程(有2個同名進(jìn)程)。 Dump后用LordPE修改入口點(diǎn)為在第一步中查
到的OEP。
4、修復(fù)輸入表、IAT的尋找
脫殼后不要急著去修復(fù)輸入表, 得先把RVA數(shù)據(jù)獲取, 用OD載入Dump出來的程序, 右鍵搜索二進(jìn)制字符串, 輸入FF25, 找到一個函數(shù), 在數(shù)據(jù)窗
口跟隨, 在數(shù)據(jù)窗口向上找到全是0的地方, 記下地址, 再向下找到全是0的地方, 記下地址。
5、加載子程序。
(1)找子程序pid的方法有二:
方法一:用OD載入原程序(脫殼前的程序), 下斷點(diǎn):bp DebugActiveProcess, 中斷后看堆棧, 記下Processid后面的值(這個值不是每次都
相同的)。 OD不要關(guān)。
第二種方法就是用工具ArmaDetach, 將加殼程序拖入。 記下子程序的pid和前兩個字節(jié)。
(2)另開一個OD, 附加Processid后面的值進(jìn)程或用工具ArmaDetach所記下的進(jìn)程id, 附加后, ALT+F9返回程序, 將前兩個字節(jié)改為原程序載
入時的前兩個字節(jié)。
6、下面的做法就和標(biāo)準(zhǔn)殼的一樣了, 在附加的OD中:
雙變單:方法有二。 其一:patch法。 其二修改跳轉(zhuǎn)法。
方法一:下斷點(diǎn)BP OpenMutexA(雙變單), F9運(yùn)行, 斷下后, ctrl+g到00401000, 將空數(shù)據(jù)改為如下代碼:
0040100060 pushad
004010019C pushfd
00401002 68 A0FD1200 push xxxx(注:此處的xxxx為斷下后name前的數(shù)值。 )
0040100733C0 xor eax,eax
0040100950 push eax
0040100A50 push eax
0040100BE8 E694A677call KERNEL32.CreateMutexA
004010109D popfd
0040101161 popad
00401012- E9 8F9FA777jmp KERNEL32.OpenMutexA
點(diǎn)右鍵選擇重建eip,f9運(yùn)行, 斷下后,取消斷點(diǎn), ctrl+g到00401000, 恢復(fù)修改。
方法二:下斷點(diǎn)BP OpenMutexA, SHIFT+F9運(yùn)行, 斷下后, ALT+F9返回, 返回后, 將返回代碼下面的第一個跳轉(zhuǎn)改為相反跳轉(zhuǎn), 再次SHIFT+F9
, 斷下后, ALT+F9返回, 再次將返回代碼下面的第一個跳轉(zhuǎn)改為相反跳轉(zhuǎn)。 然后再一次SHIFT+F9,取消斷點(diǎn), 至此,同樣,雙進(jìn)程轉(zhuǎn)單進(jìn)程完畢!
此法相對簡單, 另外適用于00401000空數(shù)據(jù)不能修改的程序。
(2)修改Magic Jump 。
下斷BP GetModuleHandleA+5, 運(yùn)行, 一般是在堆棧窗口出現(xiàn)ASCII "kernel32.dll"和ASCII "VirtualFree后, 再運(yùn)行一次, 就是返回時機(jī), 中
斷后alt+f9返回,在KERNEL32.LoadLibraryA下面找到Magic Jump!修改為jmp。 清除所有斷點(diǎn), 再直接按F9運(yùn)行, 出現(xiàn)暫停。 這時大功告成。
(3)用Imprec1.6f選擇進(jìn)程附加的那個進(jìn)程, 填入OEP地址, 填第4步所記下的RAV, SIZE=1000, 不要按自動搜索IAT, 直接按獲取輸入表, 再
按顯示無效地址, 剪掉修復(fù)抓取文件就OK了。
(四)全保護(hù)脫殼脫殼方法
1、雙變單可以用以下方法, 也可以用腳本, 目的是雙變單。 記下程序加載時的前兩個字節(jié)。 運(yùn)行腳本后, 記下OEP的前兩個字節(jié), OEP地址和子
進(jìn)程ID。
2、用OD附加子進(jìn)程, 加載后, ALT+F9返回, 修改前兩個字節(jié)為腳本記載的OEP的前兩個字節(jié)。
3、處理IATL輸入表
方法:(1)用工具ARMADETACH, 將帶殼的程序拖入, 記下子進(jìn)程的ID。 (2)另開一OD, 附加該子進(jìn)程, 加載后, ALT+F9返回, 修改前兩個字
節(jié)為加殼程序載入時的前兩個字節(jié)。 (3)修改Magic Jump , CTRL+G, 輸入GetModuleHandleA, 在其下面的第一個跳轉(zhuǎn)下硬件執(zhí)行斷點(diǎn),
Shift+F9運(yùn)行, 一般是在堆棧窗口出現(xiàn)ASCII "kernel32.dll"和ASCII "VirtualFree后, 再運(yùn)行一次, 就是返回時機(jī), 中斷后alt+f9返回,在
KERNEL32.LoadLibraryA下面找到Magic Jump!修改為jmp。 往下拉找到兩個salc, 在其上面的jmp上下斷, Shift+F9, 斷下!撤消Magic Jump處
的修改!CTRL+G, 輸入GetCurrentThreadId/ CreateThread, 下斷, 運(yùn)行, 中斷后, 刪除斷點(diǎn), alt+f9返回, F8單步走, 到第一個CALL ECX之
類的東西時, F7進(jìn)入。 (此時的OEP是偽OEP, 但此時的IAT是正確的。 先開的OEP是對的, 但I(xiàn)AT是錯誤的)。 (4)打開先前的OD, CTRL+B, 搜
索FF25, 在數(shù)據(jù)窗口跟隨, 找到函數(shù)的起始位置, 選定1-3個, 二進(jìn)制復(fù)制, 打開后面所開的OD, 打開內(nèi)存鏡像, 在此界面中點(diǎn)一下, 二進(jìn)制搜
索, 將剛才復(fù)制的粘貼, 找到后, 在轉(zhuǎn)存窗口, 找到函數(shù)的起始地址, 選定到末尾, 將選定的函數(shù)復(fù)制到先前開的OD的數(shù)據(jù)窗口, 要對整齊(
起點(diǎn)要一樣), 這時, 后開的OD的任務(wù)完成(目的就是將未加密的IAT找到)。
4、用AMINLINE工具修復(fù), 選擇第一個OD所用的子進(jìn)程, 在Code Splicing中開始Code的地址自動給填好了, 但長度需要設(shè)置一下, 大一些,
20000左右就可以了, 修復(fù)。 在IAT的長度要根據(jù)實(shí)際情況, 一般選1000即可, 依次進(jìn)行修復(fù), 修復(fù)后, 在OD中修復(fù)的地方都變成紅色。
5、用Imprec修復(fù), 無效指針CUT。
6、如果有類似自校驗(yàn)的, 則用AMINLINE工具中的nanomites選項(xiàng)修復(fù)。
上面是電腦上網(wǎng)安全的一些基礎(chǔ)常識,學(xué)習(xí)了安全知識,幾乎可以讓你免費(fèi)電腦中毒的煩擾。