banner
lca

lca

真正的不自由,是在自己的心中设下牢笼。

《從零開始學IDA逆向》學習筆記-14(程序脫殼簡介)

image

什麼是加殼?#

本章演示了對 upx 加殼程序進行脫殼。

加殼是指通過一種壓縮或者加密的手段將程序的可執行代碼隱藏起來,避免被輕易的逆向。加殼會在程序中加入額外的區段(STUB,存根),在程序開始運行後,將加密的文件進行解密並保存到內存中其他區段,或者創建原程序中的區段,然後跳轉到解密後的代碼執行。

大部分通過破壞 IAT(import table)也就是導入函數表,以及文件頭(HEADER)來保護文件。它們會加入反調試代碼來避免被脫殼出原始文件。

通過 die 查看是否加殼。

image

上圖可以知道是 upx 3.91 版本加殼,程序是 32 位,i386 架構。

加載加殼文件#

image

加載加殼文件時,取消勾選創建輸入段,勾選手動加載

點擊 ok 後,彈出如下窗口,點擊確定。

image.png

加殼後程序的入口

原始程序入口

加殼後程序的入口,地址是 0x409BE0,而原始文件的地址是 0x401000。

文件和內存佔用#

對比這 2 個文件的區段,在加殼文件的文件頭下面有個 upx0 的區段,佔用的內存比原始文件中的其他區段要大。

image

原始文件

image.png

加殼文件

加殼文件的 upx0 區塊結束於0x409000,而在原始文件 header 以下區段從0x4010000x408200,當一個程序執行時,它在硬盤上可能只佔用 1k,但在內存中可能佔用 20k 或者更大。

image

如上圖,在原始文件 CODE 區段的起始地址是0x401000,區段文件的大小 (Section size in file) 為 0x600 字節,而內存大小 (Virtual size) 佔用 0x1000 字節。

image.png

轉到加殼文件中,如上圖,upx0 區段的起點是0x401000,upx0 區段在硬盤的大小為 0,而內存佔用卻是 0x8000 字節,程序在這裡佔用了足夠大的空間來保存原始的程序代碼,然後跳轉過來執行。

image.png

加殼文件 0x401000 處的跳轉

0x401000 前置的 dword_表示數據類型為 DWORD,"?" 號表示只佔用了內存位置而未保存任何內容,dup 表示 0xc00 個 dword,也就是 0x3000 字節。0x404000 同樣也佔用了 0x1400 字節。

image.png

那麼總共就是 0x8000 個字節用於存儲原始代碼的內容。

image.png

如下圖,在 0x401000 處,按 x 鍵,可以看到此處有兩個引用(稍後回來看這部分內容)。

image.png

可執行代碼的引用

upx1 區段文件佔用是 0xe00,內存佔用是 0x1000。

image.png

upx1 區段的文件及內存佔用

可能程序使用了一些簡單的加密隱藏了原始代碼,對於這個區段的起點 0x409000 有幾處引用。

image.png

0x409000 的引用

有一處引用來自(下方,down)可執行部分,點擊跳轉到該處。

image.png
程序入口

stub 和 oep#

上圖程序入口之後的 stub 中,ESI 寄存器傳入 0x409000 這個地址,如下圖所示,可執行代碼在原始文件已加殼代碼的下方,同屬於 upx1 區塊,所以在 upx1 區塊中,存在原始文件加密後保存的內容以及 0x409be0 之後的 stub 代碼。

image.png

跟蹤到的可執行代碼

下圖中,可以發現,程序從 0x409000 處開始讀取內容,通過某種運算之後再保存到0x401000(EDI=ESI-0x8000)。程序讀取 ESI 指向的內容作為來源,然後執行操作後,再存儲到 EDI 指向的內容,恢復成原始代碼。

image.png

回到 upx0 區段,在 upx0 區段處,有一處引用

image.png

0x401000 處的引用

下圖中有一處無條件跳轉到 0x401000 處,也就是上圖中的 0x401000 處的引用。

image.png

jmp near是直接向之後的地址數跳轉的指令,那麼這裡執行完 stub 並且生成原始代碼後,程序會跳轉到 0x401000 處 (OEP,original entry point),也就是原始程序的入口(程序最開始執行的地方),相應的存根入口 (stub entry point) 是 0x409be0。

之後原始程序入口直接叫做ORIGINAL ENTRY POINTOEP。如果是一個加殼之後的程序,無法知道它的具體位置,而在此程序中,程序實有 OEP 的,OEP 就是 0x401000。

尋找 OEP#

大部分情況下,是無法獲取原程序的,所以無法直接獲得加殼程序的 OEP 地址。那麼,接下來介紹如何尋找 OEP。

當 STUB 完成解密操作並且生成原始代碼之後,會跳轉執行程序。一般來說,在寫入原始代碼的區塊執行的第一條指令就是 OEP。

在進入 OEP 之前設置斷點,查看執行到這裡之前是否已經生成了原始程序。

image.png

在跳轉處設置斷點

選擇 local windows debugger 調試,然後開始調試,運行到斷點處。

image.png

image.png

運行到斷點處

程序運行到斷點處跳轉,按 F8 單步運行。

image.png

彈出警告信息 upx0 區段原先被解析為數據,點擊是,將它解析為代碼。

image.png

運行到 OEP

現在程序已經解密出原始代碼並跳轉執行,這裡的代碼和原始程序中 0x401000 處的代碼非常類似。但是由於沒有定義為函數 (loc_401000),所以無法切換到圖形視圖。不過這也可以自動實現。

image.png

在 IDA 界面左下角有一個隱藏菜單,右鍵選擇 “重新分析程序”,現在回到 0x401000 處,顯示 sub_401000 表示這是一個函數,按空格則可以切換回圖形視圖。

image.png

重新分析後的代碼

image.png

sub_401000

通過執行斷點尋找 OEP#

另一種尋找 OEP 的方法,找到第一個區段第一條執行的指令,這種方法有時候會成功。

在調試器中啟動加殼後的程序並且在入口處暫停。

image.png

Stub entry point

轉到一個區段的起點,也就是 0x401000

image.png

按 F2 設置斷點,並且設置執行時中斷,而不是讀取或寫入的時候,否則會在解密時讀取密碼或者寫入原始代碼時中斷,由於不知道具體的位置,作者設置了覆蓋整個區段的斷點(0x8000 字節)。

image.png

設置完成後所有的指令都變紅了。

image.png

對整個區段設置斷點

然後打開菜單欄-調試器-斷點-斷點列表,禁用其他斷點。

image.png

然後運行程序。

image.png

觸發斷點

當這種方法奏效時,發現 OEP 就是 0x401000,禁用這個斷點。

image.png

OEP

重新分析之後,0x401000 識別為函數。

目前為止,介紹了 2 種尋找 OEP 的方法,創建解密代碼的內存快照。接下來要做的就是 DUMP(轉存)以及重建 IAT 來獲得沒有加殼並且能夠運行的程序。

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。