逆向基礎——軟體手動脫殼技術入門
這裡整合了一下之前自己學習軟體手工脫殼的一些筆記和脫文,希望能給新學軟體逆向和脫殼的童鞋們一點幫助。
1 一些概念
1.1 加殼
加殼的全稱應該是可執行程式資源壓縮,是保護檔案的常用手段。加殼過的程式可以直接執行,但是不能檢視原始碼。要經過脫殼才可以檢視原始碼。
加殼是利用特殊的演算法,對EXE
、DLL
檔案裡的資源進行壓縮、加密。類似WINZIP
的效果,只不過這個壓縮之後的檔案,可以獨立執行,解壓過程完全隱蔽,都在記憶體中完成。它們附加在原程式上透過Windows
載入器載入記憶體後,先於原始程式執行,得到控制權,執行過程中對原始程式進行解密、還原,還原完成後再把控制權交還給原始程式,執行原來的程式碼部分。加上外殼後,原始程式程式碼在磁碟檔案中一般是以加密後的形式存在的,只在執行時在記憶體中還原,這樣就可以比較有效地防止破解者對程式檔案的非法修改,同時也可以防止程式被靜態反編譯。
殼的型別通常分為壓縮殼和加密殼兩類。壓縮殼的特點是減小軟體體積大小,加密保護不是重點。加密殼種類比較多,不同的殼側重點不同,一些殼單純保護程式,另一些殼提供額外的功能,如提供序號產生器制、使用次數、時間限制等。
1.2 OEP
OEP:(Original Entry Point
),程式的入口點。軟體加殼一般隱藏了程式真實的OEP
(或者用了假的OEP
), 我們需要尋找程式真正的OEP
,才可以完成脫殼。
一般加殼程式在使用Ollydbg
等動態除錯工具時,會停在殼的預處理塊。即處在對於程式原始程式碼塊的解壓或解密操作之前,在執行完程式自脫殼模組後,會停留在程式加殼之前的OEP
位置,此時是dump
程式的最佳時期。脫殼時在真實OEP
處下int3
斷點,就可以捕捉到程式程式碼段完全恢復的狀態。因此,尋找加殼程式的正確OEP,也成了手動脫殼時的第一要務。
1.3 IAT
IAT:(Import Address Table
),匯入地址表。由於匯入函式就是被程式呼叫但其執行程式碼又不在程式中的函式,這些函式的程式碼位於一個或者多個DLL
中。當PE
檔案被裝入記憶體的時候,Windows
裝載器才將DLL
裝入,並將呼叫匯入函式的指令和函式實際所處的地址聯絡起來(動態連線),這操作就需要匯入表完成。其中匯入地址表就指示函式實際地址。 多數加殼軟體在執行時會重建匯入地址表,因此獲取加殼程式正確的匯入地址表也是手動脫殼操作中的一個關鍵問題。
2 一些脫殼方法
2.1單步跟蹤法
單步跟蹤法的原理就是透過Ollydbg
的單步(F8
)、單步進入(F7
)和執行到(F4
)功能,完整走過程式的自脫殼過程,跳過一些迴圈恢復程式碼的片段,並用單步進入確保程式不會略過OEP
。這樣可以在軟體自動脫殼模組執行完畢後,到達OEP
,並dump
程式。
2.2 ESP定律法
ESP
定律法是脫殼的利器,是應用頻率最高的脫殼方法之一。
ESP
定律的原理在於程式中堆疊平衡的合理利用。由於在程式自解密或者自解壓過程中,不少殼會先將當前暫存器內容壓棧,如使用pushad
,在解壓結束後,會將之前的暫存器值出棧,如使用popad
。因此在暫存器出棧時,往往程式程式碼被自動恢復,此時硬體斷點觸發。然後在程式當前位置,只需要少許單步跟蹤,就很容易到達正確的OEP
位置。
2.3記憶體映象法(二次斷點法)
記憶體映象法是在加殼程式被載入時,透過OD
的ALT+M
快捷鍵,進入到程式虛擬記憶體區段。然後透過加兩次記憶體一次性斷點,到達程式正確OEP
的位置。
記憶體映象法的原理在於對於程式資源段和程式碼段下斷點,一般程式自解壓或者自解密時,會首先訪問資源段獲取所需資源,然後在自動脫殼完成後,轉回程式程式碼段。這時候下記憶體一次性斷點,程式就會停在OEP
處。
2.4一步到達OEP
所謂的一步到達OEP
的脫殼方法,是根據所脫殼的特徵,尋找其距離OEP
最近的一處彙編指令,然後下int3
斷點,在程式走到OEP
的時候dump
程式。 如一些壓縮殼往往popad
指令距離OEP
或者Magic Jump
特別近,因此使用Ollydbg
的搜尋功能,可以搜尋殼的特徵彙編程式碼,達到一步斷點到達OEP
的效果。
2.5最後一次異常法
最後一次異常法的原理是,程式在自解壓或自解密過程中,可能會觸發無數次的異常。如果能定位到最後一次程式異常的位置,可能就會很接近自動脫殼完成位置。現在最後一次異常法脫殼可以利用Ollydbg
的異常計數器外掛,先記錄異常數目,然後重新載入,自動停在最後一次異常處。
2.6 模擬跟蹤法
模擬跟蹤法的原理就是使用Ollydbg
下條件斷點,SFX
相當於是一個自解壓段,在自解壓段結束時(eip
的值轉到程式碼段時),已經距離OEP
很近,但是這種跟蹤方法會比較耗時。
2.7 “SFX”法
“SFX
”法利用了Ollydbg
自帶的OEP
尋找功能,可以選擇直接讓程式停在OD
找到的OEP
處,此時自解壓已經完成,可以直接dump
程式。
3一些脫殼實踐
下面給出整理的使用以上方法,自己嘗試手動脫這幾種常用殼的脫殼筆記。
3.1UPX脫殼筆記
首先進行偵殼:
首先把程式扔到OllyIce
裡面可以看到:
然後這裡嘗試使用ESP
定理:即在ESP
第一次改變時,對ESP
的地址設定硬體字訪問斷點,這樣可以在程式碼被UPX
演算法還原之後,跳轉到程式的正常入口處。
然後F5
執行,並沒有直接到跳轉到程式入口處的大跳位置,但是可以看到UPX
的大跳就在眼前:
所以被還原後的程式入口點就是0x00445151
(透過單步往下走,F4
略過往回走的迴圈語句,也可以看到這個大跳的位置。)接下來走到大跳位置,跳到正常程式入口處:
然後去掉硬體斷點,並使用LoadPE
的dump
功能dump
目標程式:
先修正映像大小,然後再選擇完整脫殼,這樣可以得到第一步dump的程式,然後再使用ImportREC
修復dump
程式的OEP
,OEP
的資訊透過OD
自帶的dump
功能查詢或者直接填45151
:
將正確的入口地址填入ImportREC
中,然後自動搜尋IAT
資訊:
然後點選獲取輸入表得到修正IAT
之後的程式函式輸入表,然後再點選顯示無效函式,愉快地發現沒有無效函式,那麼就可以直接修復轉存檔案了。
選擇剛剛第一步dump
下來的轉儲檔案進行修復,修復完成之後脫殼完成:
這裡對於壓縮殼UPX
,直接使用了ESP
定律,可以很方便找到OEP
並dump
程式。
4.2 tElock脫殼筆記
這裡脫的是一個tElock
的殼:
1、先使用最簡單的最後一次異常法: 首先把程式扔到OllyIce
裡面設定OD
除錯選項中的異常選項,
僅保留記憶體非法訪問異常,然後使用異常計數器外掛,在使用前要清空斷點設定:
等到程式正常執行後,重新載入程式,再選擇第二步,停在最後一次異常之前:
然後用Alt+M
轉到記憶體視窗,對主程式code
段下記憶體斷點,SHIFT+F9
執行:
這樣程式就中斷在了正確的OEP
處,可以選擇從模組中刪除分析以顯示正常分析的彙編程式碼。然後使用LoadPE dump
程式,並修正程式映像大小。但是在使用ImportREC v1.6F Fix
版,輸入正確的OEP
,獲取函式輸入表資訊時,會發現無效的指標。使用方法一修復後,再使用方法三可以完全修復:
再點選Fix dump
,可以修復之前dump
下來的程式,脫殼完成:
2、使用二次記憶體斷點法: 首先載入程式,將所有的異常型別忽略,然後在idata
段設定記憶體斷點, 然後SHIFT+F9
:
停下來後再次在code段設定記憶體斷點,再次SHIFT+F9執行,可以直接達到正確的OEP中:
然後LoadPE dump
,然後修復IAT
。修復方法同方法1。
3、尋找magic jump
以及修復函式表完成後dump
程式: 前兩步還是加記憶體斷點(idata
、code
),然後定位到程式的正確OEP
處
然後如果這時使用LoadPE dump
後修復,就和前兩種一樣了。這裡先是使用ImportREC
獲取函式輸入表第一個位置的指標地址。
然後得到函式指標偏移地址在0x005512C
,加上基地址後為0x045512C
,這時在該位置下硬體訪問雙字斷點。再重新SHIFT+F9
忽略異常執行後,由於下了斷點,會觸發tElock
的CRC
校驗錯誤:
所以這裡要先繞過CRC
校驗,才能成功執行到硬體斷點位置,所以首先暫停程式,然後使用Alt+F9
返回使用者程式碼。點選確定按鈕後,程式暫停在呼叫ExitProcess
的位置:
現在要向上找一找能跳過這個退出的跳轉(CRC
判斷跳轉),然後進行修改並跳過:
找到了應該修改的位置,但是如果修改之後重新執行是會被恢復的,所以先記下來這個跳轉的地址,0x00469622
。重新執行之後,在idata
斷設定記憶體斷點,SHIFT+F9
停下後,再Ctrl+G
找到修改點再修改。修改完之後再設定之前的硬體斷點,這樣不會觸發CRC
校驗錯誤了。
無數次的SHIFT+F9
之後,在暫存器視窗可以看到指標以及能夠正常顯示:
然後此時F8
單步,找magic jump
……看小生大大的視屏是透過分析疑似CRC
跳轉得到magic jump
的位置:
這裡記下來magic jump
的地址是0x0046973B
,然後清空udd
檔案,刪除硬體斷點,再次重新執行程式,然後在idata
下記憶體斷點停住,然後Ctrl+G
找到magic jump
位置處,修改跳轉:
然後在code
段下記憶體斷點:
然後SHIFT+F9
執行,停下來就到了OEP
的位置:
這時候再dump
程式,IAT
表已經被修復,可以直接獲得脫殼版程式:
這裡嘗試使用了另外兩種脫殼方法,並且透過預先找OEP
的方式,修復了CRC
校驗後,直接dump
到了IAT
被修復了的程式。
3.3 PEncrypt脫殼筆記
首先進行偵殼:
先把程式扔到OllyIce
裡面,然後程式停在這裡,看起來蠻怪的:
好吧,重新載入程式,嘗試使用最後一次異常法,不忽略所有異常,然後使用異常計數器外掛,程式停在最後一次異常處:
如果此時F8
單步下去,程式會觸發異常處理,然後又到不了OEP
了。這時需要看一下堆疊資料情況:
這時需要在0040CCD7
處F2
下斷點,然後SHIFT+F9
執行,可以跳過這個坑:
然後接下來就是F8+F4
的操作,一路直到OEP
:
用LoadPE
脫殼,然後用ImportREC
修復後,雖然沒有無效指標,但是還是不能執行:
這時候用LoadPE
的重建PE
功能:
然後就可以正常執行了:
這個殼使用了單步跟蹤的脫殼方法,一路跳過程式“陷阱”,最後達到OEP
。並且使用了LoadPE
的重建PE
功能,對程式進行了重建,最終完成了這個加密殼的脫殼全過程。
3.4 FSG變形殼脫殼筆記
首先進行偵殼:
使用ESP
定律,首先把程式扔到OllyIce
裡面,F8
單步走,觀察ESP
變化,在ESP
第一次發生變化時,對ESP
對應的地址處設定記憶體硬體訪問WORD
斷點,然後SHIFT+F9
執行,在程式停下來之後,取消硬體斷點,進行F8
單步:
用F4
略過向後的跳轉(迴圈),然後繼續往下找,一直到這裡:
在這個jmp
下面F4
,程式會跑飛。說明程式程式碼在這個迴圈中就已經釋放完畢,所以向上找找這個迴圈中有沒有帶條件的大跳。這樣很容易找到magic jump
的位置,然後我們Enter
或者Ctrl+G
到00402666
的位置,發現果然是OEP
,重新分析,然後F2
下斷點,讓程式走到OEP
:
如果是FSG1.33
,直接使用LoadPE dump
檔案,然後使用ImportREC
修復,就可以正常脫殼了。但是這裡在使用ImportREC
修復時,會出現一個無效指標:
這裡直接剪掉(或者刪掉)這個指標,然後修復轉存檔案,發現無法正常開啟:
然後再把修復後的程式,丟到OllyIce
中F9
直接執行:
這裡是變形殼新增的一個暗樁,會導致程式出現異常退出,這裡直接nop
掉或者把之前的jle
(校驗)改成jmp
,然後儲存修改另存檔案。然後就可以執行了
4 參考
【百度百科(各種概念)、自己之前的脫文……】 另附一篇脫殼步驟彙總: http://www.52pojie.cn/thread-259984-1-1.html
相關文章
- upx手動脫殼2020-10-26
- iOS逆向學習之五(加殼?脫殼?)2019-10-10iOS
- 十、iOS逆向之《越獄砸殼/ipa脫殼》2021-03-18iOS
- 容器技術之Docker基礎入門2020-05-22Docker
- 脫殼基礎知識以及簡單應用2019-06-17
- JDBC基礎入門教程,輕鬆掌握jdbc基礎+核心技術,超全面!2021-12-15JDBC
- 學Python下載什麼軟體?Python基礎入門!2021-05-06Python
- 帆軟基礎之填報入門2020-10-07
- Token技術有什麼優勢?網路安全基礎入門2021-03-09
- 網路安全技術好學嗎?網路安全基礎入門2021-01-07
- 2018最新區塊鏈技術,從入門到精通視訊教程(比特幣基礎技術)2018-10-04區塊鏈比特幣
- 羽夏逆向——逆向基礎2021-11-19
- docker基礎部署入門,微服務必備技術,月薪上萬不是夢2020-11-10Docker微服務
- Spring入門學習手冊 6:Spring MVC基礎中的基礎2019-02-01SpringMVC
- Python語言適合做桌面軟體開發嗎?Python基礎入門2021-05-31Python
- 逆向基礎(六)2020-08-19
- 逆向基礎(五)2020-08-19
- 逆向基礎(四)2020-08-19
- 逆向基礎(三)2020-08-19
- 逆向基礎(十一)2020-08-19
- 逆向基礎(十)2020-08-19
- 逆向基礎(十二)2020-08-19
- 逆向基礎(一)2020-08-19
- 逆向基礎(二)2020-08-19
- 逆向基礎(九)2020-08-19
- 逆向基礎(八)2020-08-19
- 逆向基礎(七)2020-08-19
- 軟體測試員必備基礎:3分鐘帶你入門自動化測試!2019-02-02
- HTML 基礎入門2019-02-16HTML
- Maven入門基礎2018-11-24Maven
- Java 入門基礎2018-11-29Java
- Redis入門基礎2018-08-09Redis
- goalng 基礎入門2018-05-11Go
- sqlServer 基礎入門2024-04-23SQLServer
- Ansible 基礎入門2024-03-08
- shell入門基礎2024-04-15
- mongodb基礎入門2020-01-21MongoDB
- MySQL 基礎入門2020-05-05MySql