反組譯器的選擇#
靜態逆向工程(static reverse engineering) 是解剖應用程式執行檔、判斷它做了什麼的過程。理想上我們希望把編譯過程反轉回原始碼,但那通常太難,比較實際的做法是反組譯執行檔。
與其只拿十六進位編輯器加一本機器碼參考手冊硬幹,不如用工具:
- objdump(Linux):把反組譯輸出直接印到主控台或檔案,之後就靠你自己用文字編輯器在裡面遊走。簡單,但不太好用。
- IDA Pro:由 Hex Rays 開發,功能最完整的互動式反組譯器,是靜態逆向的首選工具,支援眾多常見執行檔格式與幾乎所有 CPU 架構。完整版價格不斐,但也有免費版。
IDA Pro 免費版只能反組譯 x86 程式碼、不得用於商業環境,但拿來熟悉反組譯器綽綽有餘。免費版僅提供 Windows 版本,不過在 Linux 或 macOS 上透過 Wine 執行應該沒問題。
IDA Pro 免費版快速操作指南
載入檔案
安裝後啟動 IDA Pro,用 File ▸ Open 選擇目標執行檔,會出現 Load a new file 視窗。視窗中選項很多,但多數是給進階使用者的,你只需要注意兩個:
- 執行檔格式:預設常是 Portable executable,通常是正確選擇,但最好還是確認一下。
- Processor type:指定處理器架構,預設是 x86。當你要反組譯非典型處理器架構的二進位資料時,這個選項特別重要。

圖表 6-5:載入新檔案的選項
確認無誤後按 OK 開始反組譯。這兩個選項該怎麼填取決於你的目標檔案;IDA 會盡力自動偵測所需格式,通常你不需要手動選。反組譯期間,它會盡可能找出所有可執行程式碼、標註反編譯出的函式與資料,並判斷反組譯區域之間的交叉參照(cross-reference)。反組譯可能需要不少時間。
主要視窗
主介面中有三個地方要留意:預設的反組譯檢視(範例中顯示的是 IDA Pro graph view,很適合觀察單一函式的執行流程;按空白鍵可切換成依指令載入位址排列的線性原生檢視)、顯示反組譯進度與錯誤訊息的狀態視窗,以及已開啟視窗的分頁列。

圖表 6-6:IDA Pro 的主介面
透過 View ▸ Open subviews 可以開啟更多視窗,其中幾乎一定會用到的有:
| 視窗 | 內容 |
|---|---|
| IDA View | 執行檔的反組譯結果 |
| Exports | 執行檔匯出的函式 |
| Imports | 執行期動態連結進此執行檔的函式 |
| Functions | IDA Pro 辨識出的所有函式清單 |
| Strings | IDA Pro 在分析過程中辨識出的可列印字串清單 |
後四者基本上就是資訊清單,IDA View 才是你花最多時間的地方。
在反組譯中導覽
雙擊任何看起來像函式名稱或資料參照的東西,會自動跳到該參照的位置。分析對其他函式的呼叫時特別好用:看到
CALL sub_400100,雙擊sub_400100就能直接跳過去。按 ESC 或工具列的返回鈕可回到原本的呼叫端;你可以像在瀏覽器裡一樣在反組譯視窗中前進後退。

圖表 6-7:IDA Pro 反組譯視窗的返回鈕
把游標移到參照上按 X(或右鍵選 Jump to xref to operand),會叫出交叉參照對話框,列出執行檔中所有引用該函式或資料值的位置;雙擊項目即可跳到該處。
重新命名
IDA 預設會為被參照的值產生自動名稱:函式命名為 sub_XXXX(XXXX 是記憶體位址),loc_XXXX 則代表目前函式中的分支位置,或不屬於任何函式的位置。這些名字對理解程式碼幫助有限,但你可以把游標移到參照文字上按 N(或右鍵選 Rename)改成有意義的名字,變更會傳播到所有引用它的地方。
分析堆疊變數與參數#
參數一般透過堆疊傳遞,而堆疊同時也存放暫時性的區域變數——那些塞不進可用暫存器的重要值。IDA Pro 會分析函式,判斷它接受幾個參數、使用了哪些區域變數,並把這些資訊標示在反組譯出的函式開頭。

圖表 6-8:顯示區域變數與參數的反組譯函式
你可以重新命名這些區域變數與參數,也能查它們的交叉參照。
區域變數與參數的交叉參照只會停留在同一個函式內——這是它們與全域資料參照最大的差別。
定位關鍵功能#
接下來的問題是:這個執行檔到底在哪裡處理網路協定?最直接的方法是把執行檔每一部分逐一檢視、判斷各自的職責,但若目標是大型商業產品,這種做法效率極差。以下四種途徑能讓你快速鎖定值得深入分析的區域。
1. 萃取符號資訊#
把原始碼編譯成原生執行檔是個有損過程,尤其是符號資訊(symbolic information)——變數與函式名稱、記憶體結構的形狀等。原生執行檔正確執行時很少需要這些資訊,編譯過程可能直接丟棄;但丟掉之後就很難對建置出的執行檔除錯。
所有編譯器都支援把符號資訊轉換並產生除錯符號(debug symbols),其中包含指令對應的原始碼行號,以及函式與變數的型別資訊。開發者鮮少刻意留下除錯符號,通常會在公開發行前移除,以免別人挖出他們的商業機密(或糟糕的程式碼)。但有時他們會失手,而你可以善用這種失誤。
| 平台 | 符號存放方式 | 逆向者的機會 |
|---|---|---|
| Windows | 執行檔中只有一個區段指向 program database(PDB) 檔的位置,所有除錯資訊都在該 PDB 檔內 | PDB 檔在閉源軟體中鮮少隨執行檔散布,但 Microsoft 是重要例外:它為多數 Windows 內建執行檔(含核心)釋出公開符號 |
| macOS | 除錯資訊放在與執行檔並列產生的 debugging symbols package(dSYM) 目錄中 | dSYM 很少隨商業應用散布,但 Mach-O 格式本身可儲存函式與資料變數名稱等基本符號資訊;除非開發者跑過 Strip 工具移除,否則仍可能有料 |
| Linux | ELF 把所有除錯與符號資訊打包進單一執行檔,除錯資訊放在自己的區段中 | 同樣只能靠 Strip 移除;開發者忘了做就是你的運氣(當然,Linux 上多數程式你本來就拿得到原始碼) |
把除錯符號與執行檔分開的好處,是可以在散布執行檔時不帶除錯資訊,同時又讓除錯資訊隨手可得。逆向 Windows 執行檔時,IDA Pro 應該會自動到 Microsoft 的公開符號伺服器查找符號檔並處理。若你手上剛好有符號檔(例如隨執行檔附上),把它放在執行檔旁邊的目錄再讓 IDA Pro 反組譯即可;也可以在初次反組譯後用 File ▸ Load File ▸ PDB File 載入。
這些 PDB 檔並不含編譯過程的全部除錯資訊——Microsoft 會抽掉不願公開的部分,例如詳細型別資訊——但通常仍保有大部分函式名稱,而那往往正是你要的。
除錯符號在 IDA Pro 中最大的作用,是替反組譯視窗與 Functions 視窗裡的函式命名。若符號還含型別資訊,你會在函式呼叫上看到參數型別的標註。

圖表 6-9:帶有除錯符號的反組譯結果
即使沒有 PDB 檔,你仍可能從執行檔本身取得部分符號資訊:動態函式庫必須匯出一些函式供其他執行檔使用,這些匯出會提供外部函式名稱等基本符號資訊,讓你能從 Exports 視窗一路往下挖。Windows 網路函式庫 ws2_32.dll 就是典型例子。

圖表 6-10:ws2_32.dll 函式庫的匯出項目
2. 檢視匯入的函式庫#
在通用作業系統上,網路 API 的呼叫不太可能直接編進執行檔,而是在執行期動態連結。要知道執行檔動態匯入了什麼,看 IDA Pro 的 Imports 視窗即可。

圖表 6-11:Imports 視窗
- 你會看到各種網路 API 從
ws2_32.dll匯入——那是 Windows 上的 BSD sockets 實作。雙擊項目會在反組譯視窗中顯示該匯入,接著可以用 IDA Pro 顯示指向該位址的交叉參照,找出所有引用處。 - 除了網路函式,你也可能看到匯入了各種密碼學函式庫。追這些參照能帶你找到執行檔中使用加密的地方,再往回追到原始呼叫端,就能弄清楚它怎麼被使用。常見的加密函式庫包括 OpenSSL 與 Windows 的
Crypt32.dll。
3. 分析字串#
多數應用程式都含有可列印文字的字串:執行期要顯示的文字、記錄用的文字,或是除錯過程遺留、實際上沒被用到的文字。這些文字——尤其是內部除錯資訊——常常暗示某個反組譯出的函式在做什麼。依開發者加除錯資訊的方式,你可能找到函式名稱、原始 C 檔名,甚至印出該除錯字串的原始碼行號(多數 C/C++ 編譯器都支援在編譯期把這些值嵌入字串的語法)。
IDA Pro 會在分析過程中嘗試找出可列印文字字串,用 Strings 視窗即可檢視。點選感興趣的字串會看到它的定義,接著就能找出引用它的地方,回溯到相關功能。
字串分析還有另一個用途:判斷執行檔靜態連結了哪些函式庫。例如 ZLib 壓縮函式庫常被靜態連結,連結後的執行檔一定會含有這樣的字串(版本號可能不同):
inflate 1.2.8 Copyright 1995-2013 Mark Adler快速辨識出執行檔內含哪些函式庫,往往就能猜出協定的結構——看到 ZLib 就該懷疑封包內容有壓縮,看到 OpenSSL 就該懷疑有 TLS 或自訂加密層。
4. 自動辨識演算法#
某些功能天生適合自動化辨識。例如加密演算法通常含有若干魔術常數(magic constants)——演算法定義、因特定數學性質而選定的數值。找到這些常數,就知道某個加密演算法至少被編進了執行檔(雖然不代表一定有被使用)。以下是 MD5 雜湊演算法的初始化程式碼,用的就是魔術常數:
void md5_init( md5_context *ctx )
{
ctx->state[0] = 0x67452301;
ctx->state[1] = 0xEFCDAB89;
ctx->state[2] = 0x98BADCFE;
ctx->state[3] = 0x10325476;
}有了對 MD5 演算法的認識,你可以在 IDA Pro 中選取反組譯視窗後用 Search ▸ Immediate value 搜尋這段初始化程式碼。

圖表 6-12:IDA Pro 中搜尋 MD5 常數的搜尋框
用 IDA Pro 搜尋框定位演算法既耗時又容易出錯。以上述搜尋為例,它同時會撈到 MD5 和 SHA-1——因為 SHA-1 用了同樣的四個魔術常數(再多加第五個)。
比較省事的做法是交給專門工具。PEiD 可判斷一個 Windows PE 檔是否被 UPX 之類的已知加殼工具處理過,並附帶若干外掛,其中一個能偵測潛在的加密演算法並指出它們在執行檔中被引用的位置。用法是啟動 PEiD、點右上角的 … 按鈕選擇要分析的 PE 執行檔,再點右下角按鈕選 Plugins ▸ Krypto Analyzer 執行外掛。若執行檔含有任何密碼學演算法,外掛會辨識出來並顯示結果,你再把它給出的參照位址值輸入 IDA Pro 分析即可。
