天天看點

脫殼簡單總結

title: 脫殼

date: 2021-07-05 14:37:06

tags: RE

脫殼

1.概述:

1.殼:

一:加殼的目的:為了隐藏程式真正的OEP(入口點),防止被破解。

二:加殼軟體是一種在編譯好可執行檔案之後,為了一些特定的需求,而做的一些事情,常見需求有:

​ 有一些版權資訊需要保護起來,不想讓别人随便改動

​ 為了讓程式小一點,進而友善使用(把可執行檔案進行壓縮使用)

​ 給木馬等軟體加殼以避免防毒軟體

三:殼的加載過程:

​ 一般殼的裝載過程:

​ (1)擷取殼所需要使用的API位址

加殼後的檔案,比未加殼的檔案的輸入表所引入的API少(甚至隻有Kernel32.dll以及GetProcAddress這個API函數);殼實際上還需要其他API函數來完成一些事情,它為了隐藏這些API,一般隻在殼的代碼中用顯式連結的方式來動态加載這些API

​ (2)解密原程式的各個區塊(Section)的資料

殼一般是按區塊加密的,那麼解密的時候也是按區塊解密,并且把解密的區塊資料按照區塊的定義放在合适的記憶體位置;如果加殼時用到了壓縮技術,那麼在解密之前,需要用對應的解壓縮技術。

​ (3)重定位

​ (4)HOOK-API

程式檔案中的輸入表的作用:讓Windows系統在程式運作時提供API的實際位址給程式使用,這個是在程式的第一行代碼執行之前,由Windows系統完成的操作。

而殼一般是修改了原程式檔案的輸入表,然後仿照Windows系統的工作來填充輸入表中的相關資料,在填充過程中,外殼就可填充HOOK-API的代碼位址,進而可以間接獲得程式的控制權。

​ (5)跳轉到程式原入口點

這個時候,殼把控制權交還給原程式

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-LrESqGdT-1625549563239)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\image-20210204180643199.png)]

2.什麼是脫殼

找到程式真正的入口點(OEP)

3.分類:

簡單分為兩類 壓縮殼 加密殼

壓縮殼隻是減少程式體積對資源進行壓縮,加密殼是程式輸入表等等進行加密保護

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-Fjfs4YOc-1625549563243)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\image-20210204172527304.png)]

4.脫殼工具

OD 找OEP 利用插件dump也可脫殼

PEID/Exeinfope… 查殼

脫殼簡單總結

ImportREC 修複的

LordPE 脫殼的 win10 用不了

無法找到程序

脫殼簡單總結

方法:右擊相應的程序, 修複鏡像大小, 完整轉存.

脫殼簡單總結

脫殼機也行

5.預備知識:

1.PUSHAD (壓棧) 代表程式的入口點,

●把從EAX到EDI寄存器壓入堆棧,儲存現場(原來的值)

2.POPAD (出棧) 代表程式的出口點,與PUSHAD想對應,一般找到這個OEP就在附近

3.OEP:程式的入口點,軟體加殼就是隐藏了OEP(或者用了假的OEP/FOEP),隻要我們找到程式真正的OEP,就可以立刻脫殼。

6.步驟

1.識别殼

1.查殼工具

脫殼簡單總結
脫殼簡單總結

目的:知道殼的版本和編譯程式的語言和編譯器

2.通過入口特征和區段特征來識别

連接配接器版本

區段

殼的版本

結合OD看入口點特征 ,需要積累 多看

常見入口點特征:

https://blog.csdn.net/w_g3366/article/details/94595881

脫殼簡單總結

判斷是什麼語言寫的 可以檢視區段和入口特征:

(1)VC6特點:入口點代碼是固定的代碼,入口調用的API也是相同的,其中有的push位址不同程式可能不同;區段有四個也是固定的.text、.rdata、.data和.rsrc。

(2)VS特點:入口點隻有兩行代碼,一個CALL後直接JMP,第一個CALL進去後調用的API也是相同的;區段相對于VC6多了一個.reloc。

(3)易語言獨立編譯是調用VC的連結程式編譯的,是以從區段和入口代碼特征和VC相同

(4)非獨立編譯比較容易識别,入口特征和子產品特征都有krnln.fnr

入口特征可以通過OllyDBG載入獲得,載入後可以按一下“Ctrl+A”,讓OD分析一下代碼,就可以把入口點一些特征字元串分析出來,對于Shielden、Safengine、VProtect這類加殼程式都可以使用這種方法判斷出來。

2.尋找oep
3.dump
4.修複檔案
5.其他

importREC自動修複失敗 手動修複IAT

7.方法相關知識:

(1)ESP定律法:

堆棧平衡

殼代碼就像一個函數,進入時會開辟堆棧,儲存寄存器環境,退出時會恢複堆棧,恢複寄存器。是以是堆棧平衡

是以 在殼代碼操作了堆棧後對堆棧設定硬體通路斷點,然後運作程式,當斷點命中的時候,就是退出殼代碼的時候

在其附近單步幾次。就可以到達程式原始的OEP

❤ 第一次回到初始空棧狀态就可以找到我們的OEP

●斷點:運作到這個地方就zanting

●通路斷點再次通路這個地方 就停

!!注意!!

普通軟體斷點用于代碼段,硬體斷點可以用于記憶體,堆棧上

(2)記憶體鏡像法:

記憶體鏡像法下的記憶體通路斷點

記憶體斷點一般分為 記憶體通路斷點 記憶體寫入斷點

記憶體通路斷點:當代碼讀取記憶體的資料的時候程式暫停

記憶體寫入斷點:當代碼向記憶體中寫入資料的時候程式暫停

❤總結:

第一次記憶體通路斷點:為了讓前面的部分先解碼

第二次記憶體通路斷點:為了讓後面部分也解碼完成,同時在通路代碼段的時候,很可能會直接斷在OEP處

8.脫殼方法:

方法一:單步跟蹤法

1.用OD載入,點“不分析代碼!”

2.單步向下跟蹤F8,實作向下的跳。也就是說向上的跳不讓其實作!(通過F4)

3.遇到程式往回跳的(包括循環),我們在下一句代碼處按F4(或者右健單擊代碼,選擇斷點——>運作到所選)

4.綠色線條表示跳轉沒實作,不用理會,紅色線條表示跳轉已經實作!

●如果讓程式向上跳轉,則可能程式往反方向跳轉,無休無止,也就找不到OEP)

5.如果剛載入程式,在附近就有一個CALL的,我們就F7跟進去,不然程式很容易跑飛,這樣很快就能到程式的OEP

6.在跟蹤的時候,如果運作到某個CALL程式就運作的,就在這個CALL中F7進入

7.一般有很大的跳轉(大跨段),比如 jmp XXXXXX 或者 JE XXXXXX 或者有RETN的一般很快就會到程式的OEP。

 PS:在有些殼無法向下跟蹤的時候,我們可以在附近找到沒有實作的大跳轉,右鍵–>“跟随”,然後F2下斷,Shift+F9運作停在“跟随”的位置,再取消斷點,繼續F8單步跟蹤。一般情況下可以輕松到達OEP!

❤ OD 不能在nop處下斷點

方法二:ESP定律法

ESP定理脫殼(ESP在OD的寄存器中,我們隻要在指令行下ESP的硬體通路斷點,就會一下來到程式的OEP了!)

1.開始就點F8,注意觀察OD右上角的寄存器中ESP有沒突現(變成紅色)。

(這隻是一般情況下,更确切的說我們選擇的ESP值是關鍵句之後的第一個ESP值)

2.在指令行下:dd XXXXXXXX(指在目前代碼中的ESP位址,或者是hr XXXXXXXX),按回車!

3.選中下斷的位址,斷點—>硬體通路斷點>WORD斷點。

4.按一下F9運作程式,直接來到了跳轉處,按下F8,到達程式OEP。

方法三:記憶體鏡像法

1:用OD打開軟體!

2:點選選項——調試選項——異常,把裡面的忽略全部√上!CTRL+F2重載下程式!

3:按ALT+M,打開記憶體鏡象,找到程式的第一個.rsrc.按F2下斷點,然後按SHIFT+F9運作到斷點,接着再按ALT+M,打開記憶體鏡象,找到程式的第一個.rsrc.上面的.CODE(也就是00401000處),按F2下斷點!然後按SHIFT+F9(或者是在沒異常情況下按F9),直接到達程式OEP!

方法四:一步到達OEP

1.開始按Ctrl+F,輸入:popad(隻适合少數殼,包括UPX,ASPACK殼),然後按下F2,F9運作到此處

2.來到大跳轉處,點下F8,到達OEP!

方法五:最後一次異常法

1:用OD打開軟體

2:點選選項——調試選項——異常,把裡面的√全部去掉!CTRL+F2重載下程式

3:一開始程式就是一個跳轉,在這裡我們按SHIFT+F9,直到程式運作,記下從開始按SHIFT+F9到程式運作的次數m!

4:CTRL+F2重載程式,按SHIFT+F9(這次按的次數為程式運作的次數m-1次)

5:在OD的右下角我們看見有一個”SE 句柄”,這時我們按CTRL+G,輸入SE 句柄前的位址!

6:按F2下斷點!然後按SHIFT+F9來到斷點處!

7:去掉斷點,按F8慢慢向下走!

8:到達程式的OEP!

❤ 這是總結出來的一種捷徑.

原理就是. 最後一次異常之後就正常運作了. 這個正常運作必須是真正的OEP. 是以最後一次異常是最靠近的

方法六:模拟跟蹤法

1:先試運作,跟蹤一下程式,看有沒有SEH暗樁之類

2:ALT+M打開記憶體鏡像,找到(包含=SFX,imports,relocations)

記憶體鏡像,項目 30

位址=0054B000

大小=00002000 (8192.)

Owner=check 00400000

區段=.aspack

包含=SFX,imports,relocations

類型=Imag 01001002

通路=R

初始通路=RWE

3:位址為0054B000,如是我們在指令行輸入tc eip<0054B000,回車,正在跟蹤ing。。

PS:大家在使用這個方法的時候,要了解他是要在怎麼樣的情況下才可以使用

方法七:“SFX”法

1:設定OD,忽略所有異常,也就是說異常頁籤裡面都打上勾

2:切換到SFX頁籤,選擇“位元組模式跟蹤實際入口(速度非常慢)”,确定。

3:重載程式(如果跳出是否“壓縮代碼?”選擇“否”,OD直接到達OEP)

ps:這種方法不要濫用得好,鍛煉能力為妙。

這裡最常用的ESP定律法(堆棧平衡原理),為什麼說是ESP呢,當所有的寄存器都壓入棧時(pushad),esp位址的是指向棧頂的位址的,當殼将執行權交給源程式時,esp位址要回到pushad之前的狀态,這時就可以看到esp變化了,這就是源程式的入口點。(彙編,彙編,彙編!)

SFX:od程式自帶的調試功能,用來尋找相應的OEP

使用注意:SFX使用的範圍是當程式載入OD之後,入口點必須是代碼段之外才可以使用

總結:

9.例子

upx殼

upx的工作原理其實是這樣的:首先将程式壓縮。

所謂的壓縮包括兩方面:

一方面在程式的開頭或者其他合适的地方 插入一段代碼。

另一方面是将程式的其他地方做壓縮(也就是上面講到的壓縮)。壓縮也可以叫做加密,因為壓縮後的程式比較難看懂,原來的代碼有很大的不同。

當程式執行時:實時的對程式解壓縮。解壓縮功能是在第一步時插入的代碼完成的功能。

聯起來就是:upx可以完成代碼的壓縮和實時解壓執行。且不會影響程式的執行效率。

用upx壓縮之後形式為:1–>2–>3–>4–>5–>6

最初代碼的形式就應該是:7–>8–>9–>5–>6

執行時的形式變為:1–>7–>8–>9–>5–>6

● 1是upx插入的代碼

●記憶體鏡像法:

○需要讀取2 3 4記憶體空間的代碼,這個就會存在記憶體通路,然後把2 3 4 解壓出來,就會有記憶體寫入

○把2 看作代碼段 3 看做資料段 4 看做資源段

○假設解碼的順序是按照2 3 4進行

,第一個記憶體通路斷點,下在4 資源段處

當程式斷下來的時候,說明代碼段2和資料段3都解碼完成了

1 7 8 4 5 6

○第二個記憶體通路斷點 ,下在解壓完成的代碼段

為啥:第二次斷下來的時候,4肯定解碼完成了,這時候就完成了所有解碼,

1 7 8 9 5 6

接下來就是找OEP了,OEP在代碼段7中的代碼中,是以我們下的是代碼段的通路斷點,達到OEP就會通路代碼段,是以就可以找到OEP進而完成脫殼

手脫upx方法:

1.單步跟蹤

2.一步到達(利用popad)

3.esp定律

4.記憶體鏡像法

10.dump

利用od自帶的插件ollydump完成脫殼

11.修複檔案

用importREC修複導入表

前提(已經找到OEP)

1、脫殼在目前程序,如脫殼出來的程式不能運作,提示無法定位程式輸入點,需要使用

importREC修複導入表。

2、打開importREC,選正ollydbg正在調試的程序,填入正确的OEP,點ITA AutoSearch,

如oep正确将得到正确提示,點GetImport,得到正确的導入表。點Fix Dump,選擇脫殼

出來的儲存檔案,Done!(修正後的程式為原程式名後加一下劃線,原程式不會被修改。)

12.emmm

如果直接Dump檔案,修複導入表會發現程式仍然不能正常運作,那麼他就不是一個單純的壓縮殼,殼中加密技術一般有IAT加密,混淆花指令,偷取OEP,反調試,代碼虛拟化

importREC自動修複失敗 手動修複IAT:

https://www.cnblogs.com/5315hejialei/p/7060315.html

原理:

程式的IAT是連續的排列的,是以我們隻需要找到IAT的起始位置和末位置,就可以确定IAT的位址和大小。在壓縮殼中,我們隻要找一個調用系統的API的Call的位址,然後在資料視窗中查找,确定IAT起始和結束位址。然後在OD中手動修複

總結:

脫殼簡單總結

手脫各種殼:

手脫 UPX 殼的捷徑

1、直接ESP定律

2、用我們已開始提到的”關鍵提示“。

具體操作:OD載入程式後,直接Ctrl+F,輸入 POPAD ;

點确定後 來到這個指令所在的位置。按F2,在這個地方下斷;

再按F9(運作);

停止後,按F2取消剛才下的斷點。再F8單步!

手脫 ASPCK 的殼

脫這個殼用ESP定律,還是相對快捷的。

可以用載入程式後,第二行(是一個CALL)那裡面的ESP。 //多數程式這個殼的第二行都是一個CALL 在左OD左下角的指令行中,輸入指令:hr ESP位址(如 hr 0012FFA4);

F9 運作。

然後從OD”調試菜單“中的”硬體斷點“這一項将剛才下的斷點删除,這點很重要!最後F8單步!

用記憶體鏡像法手脫FSG 1.33 和 PCshrink 的殼

1、忽略所有異常

2、Alt+M 打開記憶體鏡像,找到第一個 ”.rsrc“

3、F2(下斷),F9(運作)

4、Alt+M 打開記憶體鏡像,找到”Code“段;

5、F2(下斷),Shift+F9【這點一定要記住,切記是 Shift+F9】運作;

6、先按F8,再按下F4,直接到達OEP

PEpack 1.0 和 WinUpack 0.37-0.39 和 RLPack v.1.14-16

用esp定律

手脫 JDpack 殼

脫這個殼推薦使用記憶體鏡像法 。

手脫 PEDiminisher ;Dxpack 0.86 ;

32lite 0.03a ;PEtite 2.2 這幾種殼的簡單方法

脫PEDiminisher ;Dxpack 0.86 ;

這兩種殼的時候,直接用之前講到的ESP定律,即可完美脫殼。指令:【hr ESP位址】

**用ESP脫 32lite 0.03a 後 要注意的是,需要用 ImportREC 這個工具進行修複。**如:00410D50 在輸入框中輸入 10D50 就可以了【004舍去】

在用ESP定律脫 PEtite 2.2 的時候,推薦選擇 Pushad 下面那行位址中的 ESP

手脫 Exestealth 2.72 的殼

看到這或許會沉迷與ESP定律當中,在這裡提醒大家:Exestealth 2.72 的殼 用我們一開始提到的”懶方法脫殼“是最簡單的;

手脫nspack(北鬥)1.3 的殼

1、ESP定律,指令:hr ESP位址 【脫殼後程式不能正常運作】

2、用 ImportREC 這個工具進行修複,修複後程式正常運作。

另類方法脫 ASPack 2.12R 殼的技巧

Ctrl+S 搜尋:retn 0C【retn和零C 中間有個空格】 找到後向下看,如下:

retn 0C push 0 //在 retn 0C 的下面 retn //在這個地方按 F2(下斷) ;

F9(運作)

停止後按 一下 F8(單步);

再按一下 F7(跟進) 觀看這看不懂?沒關系,要是我,我也看不懂,是以我早有準備;

詳細步驟,如下(這是某程式的一部分):

程式中斷後來到這裡: 0046B3B8 C2 oc00 retn 0C //開始F8(單步)

0046B3B9 68 64584500 push registra.00455864 //這裡調用來自 00455864 (OEP) 0046B3C0 C3 retn //F7(跟進) 步入到OEP

注意:這種殼ESP不能直接脫。

脫FSG v2.0技巧

用od打開之後找到一個三跳轉的地方,就是一個判斷跳轉語句跳過了一個jmp,用F4走到jmp的位置,單步就可以找到oep的位置,用lordpe轉存之後在修複的時候還有個坑,fsg會在輸入表的地方加一些無用的幹擾,是以要手工定位,找到一個API,用d 位址的指令找到輸入表開始的地方減去基址為rva,在判斷一下大小,最後把無效函數去掉,在修複轉存檔案就可以了。

手脫PECompact 2.x

這個殼一般先給eax指派然後壓棧,那麼一定會通路eax,是以我們運作到push eax下面,然後給eax裡的位址下一個通路斷點,接着不斷地f9,會有一個jmp大跳轉,單步跟過去就是oep

手脫KBys Packer

od載入,先走幾步F8,發現了PUSHAD,這就可以用ESP了,再ESP下斷點,F9一步,走到oep附近,F8,發現一個jmp大跳轉,跟過去就是熟悉的入口指令,這就是oep了

re

繼續閱讀