上節(jié)課講了許多有關(guān)殼的知識(shí),下面我們就開始講如何脫殼,以及脫殼時(shí)要用的的一些工具,首先是查殼,當(dāng)前流行的查殼工具主要以peid和fileinfo這兩個(gè)軟件為代表。
PEiD的原理是利用查特征串搜索來完成識(shí)別工作的。各種開發(fā)語言都有固定的啟動(dòng)代碼部分,利用這點(diǎn)就可識(shí)別出何種語言編譯的。同樣,不同的殼也有其特征碼,利用這點(diǎn)就可以識(shí)別是被何種殼所加密。PEiD提供了一個(gè)擴(kuò)展接口文件userdb.txt ,用戶可以自定義一些特征碼,這樣就可識(shí)別出新的文件類型。
![]() |
一般的壓縮殼,如Aspack等都有專用的脫殼機(jī)。而加密殼(如ASProtect,Armadillo) 一般很少有脫殼機(jī),必須手工脫殼。手工脫殼一般情況是分三步:一是查找程序的真正入口點(diǎn)(OEP);二是抓取內(nèi)存映像文件;三是輸入表重建。(當(dāng)然現(xiàn)在的加密殼復(fù)雜些,要考慮更多的東西)OEP是Original Entry Point縮寫,即程序加殼前的真正的入口點(diǎn)。
如何尋找oep
外殼初始化的現(xiàn)場(chǎng)環(huán)境(各寄存器值)與原程序的現(xiàn)場(chǎng)環(huán)境是相同的。加殼程序初始化時(shí)保存各寄存器的值,外殼執(zhí)行完畢,會(huì)恢復(fù)各寄存器內(nèi)容。其代碼形式一般如下:
PUSHFD ; 將標(biāo)志寄存器入棧保存
PUSHAD ; push eax, ecx, edx, ebx, esp, ebp, esi, edi
…… ; 外殼代碼部分
POPAD ; pop edi, esi, ebp, esp, ebx, edx, ecx, eax
POPFD ; 恢復(fù)標(biāo)志寄存器
JMP OEP ;
OEP: …… ; 解壓后的程序原代碼
方法一:利用UPX 通用脫殼機(jī)自動(dòng)脫殼
![]() |
脫殼后的程序,利用PEid進(jìn)行分析,PEid給出如下的信息:
Borland Delphi 6.0-7.0
方法二:跨段指令尋找OEP
用Ollydbg來調(diào)試脫殼 ,運(yùn)行Ollydbg,點(diǎn)擊菜單“Options/Debugging options”,選擇Events項(xiàng),將第一次暫停設(shè)在WinMain函數(shù)上。 Ollydbg打開實(shí)例Bandook v1.35.exe.
相關(guān)代碼:
006E0440 $ 60 pushad //一開始Ollydbg就會(huì)中斷這行,這個(gè)就是外殼的入口點(diǎn),注意這個(gè)pushad指令 .
如下圖所示
![]() |
絕大多數(shù)加殼程序在被加密的程序中加上一個(gè)或多個(gè)段,所以依據(jù)跨段的轉(zhuǎn)移指令(JMP)就可找到真正的入口點(diǎn),此時(shí)就會(huì)有POPAD/POPFD 指令出現(xiàn)。UPX 用了一次跨段的轉(zhuǎn)移指令(JMP),在跳到OEP處會(huì)看到虛擬地址的值有一個(gè)突變,此時(shí)就能確定OEP了。
UPX殼比較簡(jiǎn)單,中斷WinMain后,只需要在Ollydbg里往下翻屏,就會(huì)發(fā)現(xiàn)這個(gè)跨段轉(zhuǎn)移指令:
![]() |
上圖相關(guān)代碼如下:
006E05A2 > 61 popad //注意這里的popad指令,和開始的pushad對(duì)應(yīng)
006E05A3 - E9 444EE7FF jmp 005553EC //這里跳到OEP,將光標(biāo)移到這,按F4執(zhí)行到這行
這句006E05A3 jmp 005553EC就是跳到OEP的指令,執(zhí)行到這,UPX外殼己將程序解壓完畢,并模擬Windows加載器將原始程序加載到內(nèi)存, 005553EC 就是映射到內(nèi)存目標(biāo)程序的入口點(diǎn),此時(shí)就可抓取內(nèi)存映像文件了。
相關(guān)代碼:
005553EC 55 push ebp
005553ED 8BEC mov ebp,esp
選擇Plugins->OllyDump->Dump debugged process項(xiàng),Dump保存成新的文件。
![]() |
方法三:編譯語言特點(diǎn)找OEP
各類語言編譯的文件入口點(diǎn)都有一些規(guī)律,可以這利用這點(diǎn)來尋找入口點(diǎn)。
1)Delphi程序
執(zhí)行程序,用LordPE(或Prodump)選dump(full)脫殼,存為dump.exe。接著用Hex Workshop打開 dump.exe,搜索文本“runtime”,搜到后,向前查找離“runtime”最近的十六進(jìn)制數(shù)字“55 8B EC”,數(shù)字所在的地址就是程序的OEP。
2)Visual C程序
可以利用Visual C啟動(dòng)部分幾個(gè)函數(shù)GetCommandLineA(W)、GetVersion、GetModuleHandleA(W)、GetStartupInfoA(W) 等來定位程序的OEP。
常見的各類編譯語言的入口匯編代碼都要熟悉,因?yàn)橐恍┘用軓?qiáng)殼會(huì)偷OEP處的代碼到殼里,一般情況各編譯語言入口代碼都相同,到時(shí)只需要直接引用相關(guān)程序的入口代碼,這給我們恢復(fù)代碼帶來方便。
其它技術(shù):
通過堆棧平衡尋找OEP,通過內(nèi)存斷點(diǎn)尋找OEP
補(bǔ)充講解一下windowsapi函數(shù),這可是脫殼的時(shí)候離不開的,如果熟悉了它可以更快的找到程序的入口及程序領(lǐng)空
Win32 API是基于C語言的接口,但是Win32 API中的函數(shù)可以由用不同語言編寫的程序調(diào)用。
Windows的主要部分有三個(gè)主要子系統(tǒng),分別是Kernel/User/GDI。
Kernel:操作系統(tǒng)核心功能服務(wù),包括進(jìn)行與線程控制、內(nèi)存管理、文件訪問等;
User:負(fù)責(zé)處理用戶接口,包括鍵盤和鼠標(biāo)輸入、窗口和菜單管理等;
GDI:圖形設(shè)備接口,允許程序在屏幕和打印機(jī)上顯示文本和圖形。
![]() |
常用Win32 API函數(shù)
GetWindowText函數(shù),作用是取得一個(gè)窗體的標(biāo)題文字,或文本控件的內(nèi)容。
GetDlgItemText函數(shù),作用是獲取對(duì)話框文本。
GetModuleFileName函數(shù)
InternetOpen函數(shù)
InternetOpenURL函數(shù)
SetWindowsHookEx函數(shù)
AdjustTokenPrivileges函數(shù)
LookupPrivilegeValue函數(shù)
OpenProcessToken函數(shù)
GetCurrentProcessId函數(shù)
GetCurrentProcess函數(shù)
GetWindowThreadProcessId函數(shù)
GetComputerName函數(shù)








