使用腳本轉存為可執行文件#
此章介紹脫殼後的兩個步驟,轉存可執行文件和重建導入函數表。
OEP
上一章中,已經調試出來了 OEP,轉到 OEP 處並操作 ida 重新分析程序,準備執行轉存操作,使用如下 idc 腳本來轉存。
static Byte(ea) {
return (ea) & 0xff;
}
static main()
{
auto fp, ea;
fp = fopen("dump.bin", "wb"); // 打開要寫入的文件
for (ea=0x400000; ea < 0x40b200; ea++) // 循環指定地址範圍
{
fputc(Byte(ea), fp); // 將指定地址中的數據寫入文件中
}
fclose(fp); // 關閉文件
}
注:在實戰的過程中,ida7.7 中使用如上代碼轉存的內容會有問題,轉存的內容不是正常的內容
所以這裡就換成了 python3 的腳本來轉存,腳本如下:
import idaapi
import idc
import struct
start_ea = 0x400000
end_ea = 0x40b200
step = 4 # 每個地址處的數據佔用4個字節
file_path = "dump.bin"
with open(file_path, "wb") as f:
for ea in range(start_ea, end_ea, step):
# 讀取指定地址處的4個字節數據並進行小端字節序轉換
bin_data = struct.pack("<L", idaapi.get_32bit(ea))
f.write(bin_data)
文件基址是 0x400000,從 ida segments 選項卡中查找轉存的最高地址,從下圖中可以看到 Overlay 區塊的結尾 0x40b200。
之後打開菜單欄 - 文件 - 腳本文件運行,這個功能 idc 腳本和 python 腳本都可以。idc 腳本執行後,會在 idc 當前目錄下生成一個 bin 文件。
bin 文件的文件頭如下圖就算是正常的。
將 dump.bin 文件備份,然後重命名為.exe 的可執行文件。
這個文件的圖標沒有顯示出來,所以還有問題需要解決。
然後通過 pe editor 打開
pe editor 1.7
點擊 sections,打開區段視圖。
區段視圖
在每一個區段上右鍵單擊並選擇 dumpfixer。
這個時候圖標正常顯示了,但程序還是無法運行,因為還未修復 IAT。
什麼是 IAT#
IAT(Import Address Table)是 Windows PE 格式中的一種重要的數據結構,用於在程序運行時動態地加載和鏈接外部 DLL 庫(動態鏈接庫)的符號。IAT 保存了外部 DLL 庫中所有要調用的函數的名稱和地址,可被程序動態鏈接器在運行時使用。
IAT 保存程序執行的所有導入函數的地址
加殼文件解密後的 IAT
原始文件的 IAT
上面兩張圖都標記了 0x403238 地址,內容看上去差不多。
打開原始文件
的 IDA 左下角顯示了這個內存地址對應的文件偏移是 0x1038,如上圖所示,此時就可以打開十六進制編輯器查看它的內容。
010editor 打開原始文件 0x1038 處的字節
上圖中0x1038
處的值是0x355e
。
如果0x355e
加上基址0x400000
就是0x40355e
,為了查看這個地址的內容,需要用 ida 重新手動加載文件中的所有區段(加載原始文件
)。
0x40355e 處的內容
選擇加載所有的區段,轉到 0x40355e 處,右側也可以看到 api 的函數名為GetModuleHandleA
。
通過這些偏移的數值加上基址的值,就能找到對應的函數名字符串,根據這個字符串可以獲取這些函數在系統上的本機地址,本例中獲取了GetModuleHandleA
的地址,然後將5E 35 00 00
字節替換為本機地址。
系統根據初始值 0x355e 加上基址後獲取對應的函數名字符串,再將函數的本機地址存放到 0x403238。
再打開一個 ida 窗口加載轉存出來的文件dump - bak.exe
,轉向0x403238
。
上圖中,文件的偏移地址是 0x3238 和原始文件不匹配,主要原因是 dumpfixer 將文件佔用(rawsize)改成和內存佔用(rawsize)一樣,導致了偏移改變。
在 010editor 打開dump - bak.exe
,來到 0x3238 處。
這裡是 api 函數的本機地址,不是指向 api 名稱字符串的偏移。
因為轉存的時候,程序已經獲取了調用 api 函數的本機地址並且將它們保存到 IAT,所以加殼程序中的GetModuleHandleA API
本機地址就保存在這個地址上。
GetModuleHandleA API
函數
上述轉存有個問題,就是當程序執行時,會從 IAT 中讀取偏移,再加上基址地址,獲取 API 函數名字符串,通過系統獲取這些 API 函數的本機地址,再保存回 IAT。而轉存時保留的是函數的實際地址,程序無法按這一流程正確地填充 IAT,最終會導致程序崩潰。
重建 IAT#
重建 IAT 的思路就是恢復這些指向 api 函數字符串的偏移值,修復 IAT 需要一個 Scylla 的工具。
運行 scylla,在 attach to an active process 中,選擇在 ida 中暫停在 OEP 的加殼程序的進程。
加殼程序運行到 OEP
填寫 OPE 的值為 00401000,點擊 IAT Autosearch。
上圖中顯示起始地址是 0x403184,大小是 0x108。
點擊 Get Imports。
上圖中,顯示有 22 處未修復。
右鍵選擇未識別的函數,選擇 scylla plugins-pecompact v2.x 進行修復。
成功修復未識別的函數
有一些可疑函數,選擇 show suspect,確認 0x403278 處的函數是否修復成功。
上圖中,可以看到成功修復,確認沒問題後,點擊 scylla 右下角的 FIX DUMP。
選擇之前轉存的.exe 文件,寫入修復後的 IAT。
修復後的程序可正常運行,說明修復成功。
使用 IDA 加載脫殼並完成 IAT 修復的文件,程序從 OEP 也就是 0x401000 開始執行,修復的和原始文件一樣。
IDA 加載 IAT 修復之後的可執行文件
修復後的 IAT
這章主要介紹了如何轉存區段內容並重建導入 IAT 函數表,並完成最後的脫殼工作,完成了這個 upx 加殼程序的脫殼,學習了整個脫殼流程。