1. 程式人生 > >有關脫殼以及脫殼例項講解

有關脫殼以及脫殼例項講解

當前流行的查殼工具主要以peid和fileinfo這兩個軟體為代表。

PEiD的原理是利用查特徵串搜尋來完成識別工作的。各種開發語言都有固定的啟動程式碼部分,利用這點就可識別出何種語言編譯的。同樣,不同的殼也有其特徵碼,利用這點就可以識別是被何種殼所加密。PEiD提供了一個擴充套件介面檔案userdb.txt ,使用者可以自定義一些特徵碼,這樣就可識別出新的檔案型別。

一般的壓縮殼,如Aspack等都有專用的脫殼機。而加密殼(如ASProtect,Armadillo) 一般很少有脫殼機,必須手工脫殼。手工脫殼一般情況是分三步:一是查詢程式的真正入口點(OEP);二是抓取記憶體映像檔案;三是輸入表重建。(當然現在的加密殼複雜些,要考慮更多的東西)OEP是Original Entry Point縮寫,即程式加殼前的真正的入口點。

如何尋找oep

外殼初始化的現場環境(各暫存器值)與原程式的現場環境是相同的。加殼程式初始化時儲存各暫存器的值,外殼執行完畢,會恢復各暫存器內容。其程式碼形式一般如下:

PUSHFD         ; 將標誌暫存器入棧儲存
PUSHAD         ; push eax, ecx, edx, ebx, esp, ebp, esi, edi
……           ; 外殼程式碼部分
POPAD          ; pop edi, esi, ebp, esp, ebx, edx, ecx, eax
POPFD          ; 恢復標誌暫存器
JMP OEP        ;
OEP: ……          ; 解壓後的程式原始碼

方法一:利用UPX 通用脫殼機自動脫殼

脫殼後的程式,利用PEid進行分析,PEid給出如下的資訊:
Borland Delphi 6.0-7.0

方法二:跨段指令尋找OEP

用Ollydbg來除錯脫殼 ,執行Ollydbg,點選選單“Options/Debugging options”,選擇Events項,將第一次暫停設在WinMain函式上。 Ollydbg開啟例項Bandook v1.35.exe.

相關程式碼:
006E0440 $ 60       pushad     //一開始Ollydbg就會中斷這行,這個就是外殼的入口點,注意這個pushad指令 .

如下圖所示

絕大多數加殼程式在被加密的程式中加上一個或多個段,所以依據跨段的轉移指令(JMP)就可找到真正的入口點,此時就會有POPAD/POPFD 指令出現。UPX 用了一次跨段的轉移指令(JMP),在跳到OEP處會看到虛擬地址的值有一個突變,此時就能確定OEP了。

UPX殼比較簡單,中斷WinMain後,只需要在Ollydbg裡往下翻屏,就會發現這個跨段轉移指令:

上圖相關程式碼如下:
006E05A2  >  61    popad            //注意這裡的popad指令,和開始的pushad對應            
006E05A3  - E9 444EE7FF     jmp     005553EC  //這裡跳到OEP,將游標移到這,按F4執行到這行

這句006E05A3    jmp   005553EC就是跳到OEP的指令,執行到這,UPX外殼己將程式解壓完畢,並模擬Windows載入器將原始程式載入到記憶體, 005553EC 就是對映到記憶體目標程式的入口點,此時就可抓取記憶體映像檔案了。

相關程式碼:
005553EC 55  push ebp
005553ED 8BEC mov ebp,esp
選擇Plugins->OllyDump->Dump debugged process項,Dump儲存成新的檔案。

方法三:編譯語言特點找OEP

各類語言編譯的檔案入口點都有一些規律,可以這利用這點來尋找入口點。

1)Delphi程式
執行程式,用LordPE(或Prodump)選dump(full)脫殼,存為dump.exe。接著用Hex Workshop開啟 dump.exe,搜尋文字“runtime”,搜到後,向前查詢離“runtime”最近的十六進位制數字“55 8B EC”,數字所在的地址就是程式的OEP。

2)Visual C程式
可以利用Visual C啟動部分幾個函式GetCommandLineA(W)、GetVersion、GetModuleHandleA(W)、GetStartupInfoA(W) 等來定位程式的OEP。

常見的各類編譯語言的入口彙編程式碼都要熟悉,因為一些加密強殼會偷OEP處的程式碼到殼裡,一般情況各編譯語言入口程式碼都相同,到時只需要直接引用相關程式的入口程式碼,這給我們恢復程式碼帶來方便。

其它技術:

通過堆疊平衡尋找OEP,通過記憶體斷點尋找OEP

補充講解一下windowsapi函式,這可是脫殼的時候離不開的,如果熟悉了它可以更快的找到程式的入口及程式領空

Win32 API是基於C語言的介面,但是Win32 API中的函式可以由用不同語言編寫的程式呼叫。

Windows的主要部分有三個主要子系統,分別是Kernel/User/GDI。
Kernel:作業系統核心功能服務,包括進行與執行緒控制、記憶體管理、檔案訪問等;
User:負責處理使用者介面,包括鍵盤和滑鼠輸入、視窗和選單管理等;
GDI:圖形裝置介面,允許程式在螢幕和印表機上顯示文字和圖形。

常用Win32 API函式
GetWindowText函式,作用是取得一個窗體的標題文字,或文字控制元件的內容。
GetDlgItemText函式,作用是獲取對話方塊文字。
GetModuleFileName函式
InternetOpen函式
InternetOpenURL函式
SetWindowsHookEx函式
AdjustTokenPrivileges函式
LookupPrivilegeValue函式
OpenProcessToken函式
GetCurrentProcessId函式
GetCurrentProcess函式
GetWindowThreadProcessId函式
GetComputerName函式