0x00 前言windows
對於加殼程序第一件事就是要找到OEP(oringinal Entry point),因爲加殼的緣故,當PE文件載入OD或者其餘調試軟件時進入的的每每是殼程序的入口地址。因此要進行逆向分析第一步就必須找到PE程序的原始入口點。函數
0x01 殼的加載過程工具
殼和病毒在某些方面比較相似,都須要比原程序更早得到控制權。殼修改了原程序的的執行文件的組織結構,從而比原程序更早得到控制權,而且並不會影響原程序的正常運行。瞭解的殼的加載過程對於脫殼加殼異常重要。殼的加載過程以下:加密
1)保存入口參數spa
加殼程序初始化時保存各個寄存器的值,外殼執行完畢,再恢復各個寄存器內容,最後再跳到源程序的入口處執行。一般,用pushad/popad,pushfd/popfd指令來保存的和恢復現場環境。線程
2)獲取殼本身所需的API函數3d
通常的殼輸入表只有GetProAddress,GetMoudleHanle,LoadLibrary這幾個API函數,甚至只有Kernel32.DLL以及GetProAddress。若是須要其餘的API函數,能夠經過LoadLibraryA(W)或者LoadLibraryExa(W)將DLL文件映像映射到調用進程的地址空間,函數返回的HINSTANCE值用於標識文件映像到虛擬內存地址。指針
LoadLibrary函數的原型以下:調試
HINSTANCE LoadLibrary{code
LPCTSTR lpLibFileName //DLL文件名地址
}
返回值:成功時返回模塊句柄,失敗返回NULL。
當DLL文件已經被映射到調用進程的地址空間裏,能夠調用GetModuleHanleA(W)函數得到DLL模塊的句柄,函數的地址原型以下:
HMODULE GetModuleHandle{
LPCTSTR lpModuleName //DLL文件地址
}
一旦模塊被加載,線程就能夠調用GetProcAddress函數獲取輸入函數地址。函數的原型以下:
FARPROC GetProcAddress{
HMODULE hModlue //DLL模塊句柄
LPCSTR lpProName //函數名
}
這三個函數異常重要,對於程序加殼幫助很大。後面幾篇將會詳細介紹用法,這裏暫且羅列出來。
3)解密原程序的各個區塊的數據
殼出於保護原程序代碼和數據的目的,通常都會加密原程序文件的各個區塊,在程序時外殼將會對這些數據解密,以讓程序可以正常運行。殼通常都是按區塊加密的,那麼在解密時也是按區塊解密的,而且把解密的區塊數據按照區塊的定義放在合適的內存位置。
4)ITA的初始化
ITA填寫,原本應該由PE加載器實現。可是因爲加殼時,本身構造了一個輸入表,而且讓PE文件頭輸入表指針指向了自建的輸入表。因此PE裝載器就對自建的輸入表進行填寫。那麼原來PE輸入表只能由外殼程序來填寫了。外殼所要作的就是將這個新輸入表結構從頭至尾掃描一遍,對每個DLL引入的全部函數從新獲取地址,並填寫在ITA表中。
5)重定位處理
文件執行時將被映像到指定的內存地址中,這個初始地址稱爲基址。對於EXE文件,windows系統會盡可能使用EXE問價所指定的內存地址,好比某EXE問價的基址爲40000h,而運行時Windows系統提供給程序使用的基地址也是40000h。這種狀況就不須要重定位了。對於DLL文件,windows沒辦法每一次提供DLL運行時提供相同的基址。對於這種狀況,重定位是必須的。此時殼程序也須要提供PE文件的重定位功能。因此加殼DLL文件比加殼EXE文件多一個重定位表。
6)HOOK-API
程序文件中輸入表的做用是讓windows系統在程序運行時提供API的實際地址給程序使用。在程序的第一行代碼執行前,windows系統就完成了這項工做。
殼程序通常都修改了原程序的輸入表,而後本身模仿windows系統的工做來填充輸入表的中相關數據。在填充過程當中,外殼程序可填充HOOK-API的代碼地址,這樣就可間接的獲取程序的控制權。
7)跳轉到程序入口點(OEP)
經歷過以上步驟後,外殼程序的功能就完成了,隨後他會把控制權交給原程序,通常的殼這裏會有一個明顯的「分界線」。固然如今愈來愈多的加密殼將OEP一段代碼搬到外殼的地址空間裏,而後將這段代碼清除掉。這種方式稱爲StolenBytes。這樣,OEP與外殼就沒有明顯的分界線了,這增長了脫殼的難度。
0x02 利用兩次內存斷點法手動找到OEP
兩次內存法的原理就是利用了殼加載過程第三步時須要對各個區段進行解密並將解密後的區段寫入各個區段,完畢以後會跳轉至原程序的OEP處。固然,若是咱們能判斷出殼什麼時候跳轉至OEP處最好,可是通常這並不容易。可是咱們能夠先對.data區塊下斷後再運行程序(由於區段.code比.data先解壓,運行到這個斷點時.code以及解密完成),隨後再對.code(有的編譯器是.text)段下斷在運行,這樣程序就會停在OEP處(由於解密完成後殼程序必定再次返回到OEP處,將控制權交給原程序)。這個方法就是兩次內存法。
0x03 實例介紹兩次斷點法找OEP過程
1)將文件拖入od,alt+m進入內存模板,隨後對.data區塊按F2下斷,以下圖:
2)點擊F9運行,此時程序停在了下來,以下圖:
這裏其實立刻就要對.data區塊進行解密讀寫操做了,此時再alt+m進入內存模塊,對.text(這個就是.code區塊,因爲編譯器不一樣,有的顯示.text區塊)區塊下斷。
3)點擊F9運行,此時程序中止,以下圖:
其實這裏就是原程序的OEP地址了,因爲od對PE文件進行了分析,因此顯示如上圖,咱們能夠右鍵,刪除模塊分析便可獲得下圖:
標紅框的地方就是OEP地址了。
0x04 總結
兩次內存斷點法雖然簡單,可是咱們仍是要弄清楚其中的原理。它其實就是利用殼加載過程須要對區段進行解密而後返回原程序OEP這一特性。(PS:這種方法對於那種去區段信息改的面目全非的基本無效,我昨天就碰到一個加殼程序,區段信息只留下幾個本身寫,連code,data這些經常使用區段都沒有,因此使用以前請用lordPE等工具查看一下區段信息)