手工實現各種脫殼后的修復


手工修復導入表結構

實現手工修復導入表結構

1.首先需要找到加殼后程序的導入表以及導入了那些函數,使用PETools工具解析導入表結構,如下。

2.發現目錄FOA地址為0x00000800的位置,長度是0x000000A8定位過去看看,程序中只保留了一個LoadLibraryA和GetProcAddress這兩個關鍵函數,通過這兩個關鍵函數即可定位到所有的函數入口,一般殼都會只加載這兩個API函數。

3.首先我們先來實現手工脫殼,使用ESP定律,開頭運行F8一次,在ESP寄存器上右鍵選擇內存窗口中轉到,選擇斷點硬件訪問四字節,脫殼環節省略,OEP位置如下。

4.找到了程序的OEP位置以后,我們可以找到以下代碼,通常是在程序的最底部,我們可以順藤摸瓜的找到內存IAT表的所在位置。

將地址轉為地址,能夠看到脫殼后的程序導入的函數,該程序導入了三個函數,分別在兩個動態鏈接庫中存儲着。

而我們編寫的PETOOLS工具並沒有那么智能,他只能識別出文件中的導入表結構,也就是在沒有裝載入內存時的狀態,很明顯,此處識別的是外殼的導入表結構

我們接着脫殼,使用內置的脫殼工具進行內存轉儲即可,如下所示。

正常我們脫殼后,程序輸入表會保留原始的帶殼狀態下的結構,如下。

使用X64DBG對其進行FixDump修復后,其結構表現如下,看樣子是完全重構了它的輸入表結構。

既然知道了解決方案,我們也來自己重構一下輸入表結構,我們可以任意選擇一處具有可讀可寫屬性的內存,這里以2E00為例

首先我們先在20E0處構建一些導入字符串,格式如下。

00002118 => 指向ExitProcess字符串
00002126 => 指向CreateFileA字符串
00000000 => 代表換行符,將兩個模塊隔開
00002134 => 指向MessageBoxA字符串

之所以中間需要隔開,是因為前兩個函數屬於Kernel32.dll最后一個函數屬於User32.dll 兩者之間使用一個DWORD來分隔開,使用PETools工具解析后可以清晰的看出來。

構建的字符串結構如下所示

接着我們繼續來構建IID結構數組,IID數組則選在2010得位置,以此類推。

000020E0 代表的是OriginFristThunk字段 -> 指向00002118 -> ExitProcess字符串
00002100 代表的是Name字段 -> 指向Kernel32.dll字符串
00002000 指向FristThunk -> 此處可指向一個空白空間,有PE裝載器自動填充。

接着我們需要找到脫殼后的程序輸入表位置,並填入。

最后的結構對應關系如下。

最后跳轉到0x130處,修正地址為0x2010大小則是0x28

手工脫殼完成了。


處理不連續的輸入表結構

有些輸入表結構在內存中是不連續的,例如下面案例,我們使用PETools解析出來,首先目錄FOA=0x0000A800其次大小是0x000005E8

將FOA轉換為VA地址,0x0040E000 長度是5E8,也就是40e000 - 40E5E8這個范圍內。

其中導入函數開始位置是 40e0ec 結束位置是 40e22C 長度是 00000140

脫殼修復時,填入對應地址,刪除無效指針,即可自動新建一個新的導入表。



手工修正重定位表

重定位表一般出現在DLL中,因為DLL都是動態加載,所以地址不固定,DLL的入口點在整個執行過程中至少要執行2次,一次是在開始時執行初始化工作,一次則是在結束時做最后的收尾工作,重定位表則是解決DLL的地址問題,默認情況下,重定位表是如下方式構建的。

1000 表示重定位RVA地址,011c則表示重定位塊的長度,后面則是每兩個字節代表一個重定位塊,1D是重定位地址,30則是重定位的類型,以此向下排列。

重定位表也是分頁排列的,每一頁大小都是1000字節,如下我們解析一下看看。

我們以第一個為例,查詢一下1000頁上的重定位結構。

重定位RVA: 0000101D是用 1000 加上 1D得到的。

重定位地址: 0040702C 則是建議裝入地址,修正RVA: 0000702C 則是程序被PE加載器修正后的RVA地址,通常與基地址相加得到,如下。

接下來以 UPX3.01為例,我們來手工脫殼,DLL的脫殼往往需要經過兩部,第一步修正導入表地址,第二部則是修正重定位表,UPX殼會破壞這兩個表結構,我們需要自己修正一下,首先看一下加殼后的Section節。

upx殼,我們可以搜索popad命令來快速到達殼尾部的位置上,然后可看到如下,jmp語句則是跳轉到解密后的地址處,由於殼沒運行起來,這里是空的。

我們讓殼單步運行一段距離,觀察尾部的jmp所指向的地址處是否解碼(不能讓殼跑到這里,我們手動定位過來觀察)發現解碼后,直接找一處可能會重定位的地址。

例如:call 0x401167 此處在載入時必然會發生重定位,我們就數據窗口跟隨。

跟隨40127B ,然后在第一個四字節出右鍵,選擇斷點,內存寫入斷點,設置好以后,運行1-4次左右,就會停到重定位地址處,如下所示。

我們來到程序OEP處,將內存轉儲,並修正鏡像。

接着我們將UPX外殼的重定位數據提取出來,依次循環拿到ebx中的地址,如下0017106E - 00171000 = 6E得到的6E就是需要修正的地址。

再次循環結果變為了0017108D - 00171000 = 8D 得到8D這條數據。

最終我們需要手動創建一個新節,然后寫入我們得到的重定位數據,自己手動重建一個重定位表,這個過程很麻煩,我就不在演示了。

最后不要忘記調整,重定位表的位置,第一處為相對RVA偏移,第二處則為重定位塊大小。



關於附加數據的修正

附加數據就是在最后一個節的后面增加的一段數據,這段數據沒有節區屬性,所以附加數據不會被動態裝入內存,附加數據一般起點是最后一個區塊的末尾,終點則是文件的末尾字節,例如下面的一個案例中,附加數據就在文件偏移 0x00003200 + 0x00000600 = 3800的位置處。

使用WinHex定位過去看看,會發現數據,這段數據由於沒有被載入內存,所以我們是不可能通過PETools工具對其進行分析的,當然專業的PE工具依然可以識別出來。

我們首先使用X64DBG,並配合ESP定律,快速脫殼並修復程序,保存后,接着就是在文件末尾創建一段空款區域。

將附加數據拷貝過來,有時附加數據並沒有在程序中引用,這種的可以不復制,有的不行,程序運行會引用這些數據塊,我們需要修正。

當我們打開程序時,程序會自動調用CreateFile打開自身,並將文件指針移動到附加數據位置,我們需要手動修正讀取偏移,下一個CreateFile斷點,運行程序會斷下,回溯一層。

向下跟進,修改0x3800這個是脫殼前默認附加數據的位置,此時我們脫殼后附加數據改到了,B400的位置此處也要修正。

修正后直接打補丁,此時即可正常讀取出附加數據了。



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM