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