跳轉至內容

逆向工程/檔案格式

來自華夏公益教科書,開放的書籍,為開放的世界

本節將討論逆向工程專有檔案格式。許多軟體開發人員需要逆向工程專有檔案格式,特別是為了實現互操作性。例如,Open Office 專案每年都需要逆向工程 Microsoft Office 檔案格式。此外,逆向工程也用於取證目的。本節中的章節將討論如何理解專有檔案格式。


Clipboard

待辦事項
整個部分都需要幫助和貢獻。如果您瞭解這個研究領域,請幫助並貢獻。本章甚至可能包括關於逆向工程檔案系統的討論。


典型特徵

[編輯 | 編輯原始碼]

檔案頭

[編輯 | 編輯原始碼]

大多數檔案格式以“頭”開頭,一些位元組描述了檔案型別和版本。由於有幾種具有相同副檔名的不相容檔案格式(例如“.doc”和“.cod”),標頭檔案提供了足夠的資訊供程式檢視該檔案是否為該程式可以處理的格式之一。

許多程式設計師在將資料寫入磁碟之前將資料打包在某種“容器格式”中。如果他們使用標準 zlib 將資料壓縮儲存,則檔案將以 2 個位元組 0x1f 0x8b(以十進位制表示,31 139)開頭。

空白空間

[編輯 | 編輯原始碼]

有些檔案主要由空白空間組成,例如,由 OS X 生成的 .ds_store 檔案。在十六進位制編輯器中,空白空間將顯示為一系列 0。檔案格式的建立者可能出於多種原因新增空白空間,例如,此研究的作者關於 .ds_store 檔案推測它們的存在是為了加快寫入資料速度,因為其他資料不需要被移動來騰出空間。它們還可以防止碎片化。

對於大多數目的,空白空間可以忽略。

檔案格式逆向工程是十六進位制編輯器的領域。通常它們更多地用於顯示檔案內容而不是編輯它們。十六進位制編輯器允許您將資料結構疊加在資料之上(有時稱為自定義檢視或類似的),這非常有用。一旦在一個檔案中發現了特定的結構,就可以使用這些機制來記錄結構,以及提供比十六進位制程式碼更具意義的資訊顯示。

Unix/Linux 工具也很有用,例如 strings(1) 和 file(1)。

strings
查詢並在檔案中列印可列印字元序列。這可以提示檔案中嵌入的資料。
file
嘗試確定檔案型別。有時檔案格式設計人員會重複使用已經知名的檔案格式或檔案壓縮演算法。 file(1) 可能會揭示這一點,雖然可能性不大但並非沒有。

這些工具的 Windows 移植版本也可用。例如,作為Cygwin環境的一部分(stringsbinutils的一部分,不要問...)。

與十六進位制編輯器同樣重要的是大腦。檔案格式逆向工程意味著要對十六進位制編輯器和其他工具顯示的內容進行推理。猜測結構、關係和資料的含義,發展理論,然後驗證它們。很少有工具可以幫助你做到這一點。

在少數情況下,額外的工具很有幫助。例如,用於暴力檢查檔案特定部分是否包含一些嵌入的壓縮資料。通常這些工具是作為自定義工具即時編寫或指令碼化的。另一組典型的自定義工具是用來將檔案拆分成單獨的元件的工具 - 一旦發現特定檔案實際上包含單獨的部件,以及它們如何在檔案中分隔。C/C++、Java,以及Perl 等指令碼語言通常在這裡使用(Perl 因為它可以處理二進位制資料,而傳統的 Unix 指令碼工具通常只限於文字資料)。

在某些情況下,專有檔案格式可能包含可執行程式碼。例如,某些嵌入式裝置的韌體更新檔案很可能包含可執行程式碼。通常,這些程式碼被包裝在一個結構中,例如一個檔案系統,被壓縮,並帶有引導/快閃記憶體程式碼等。在這種情況下,針對特定可執行格式的反彙編器/反編譯器可能會有所幫助。

此外,對校驗和演算法、壓縮演算法、編碼技術以及程式語言的文件和熟悉程度非常有幫助。

同樣非常有幫助的是能夠使用生成和讀取專有檔案格式的應用程式。該應用程式可以用來建立測試檔案,還可以驗證自己生成的測試檔案是否正確

首先尋找明顯的東西。例如,魔數、塊結構、檔案中的 ASCII 文字。任何可以或多或少清楚地識別的東西都可以是通往更多內容的入場券。一旦識別出一個特定的結構,就尋找指向該資料的檔案內指標。例如,如果資料由檔案中的其他部分透過絕對地址或相對地址引用。確定位元組序(小端序還是大端序)也非常重要。

選擇目標

[編輯 | 編輯原始碼]

如果您能夠訪問建立檔案的軟體,則始終可以建立包含您選擇的內容的檔案。這使得逆向工程變得容易得多。在密碼學術語中,您正在進行已知明文攻擊

一旦你形成了關於檔案中的某些資料可能代表什麼的理論,你就可以透過建立一個修改後的檔案來驗證該理論。使用十六進位制編輯器或自定義工具將它替換為其他資料。然後將修改後的檔案載入到原始應用程式中。如果應用程式載入檔案並顯示預期的更改,那麼該理論可能就是正確的。有時由於可能存在的防禦機制,更改應用程式並重新載入它並不容易。有些應用程式在執行之前會檢查程式碼的雜湊值和簽名。

壓縮、加密和混淆

[編輯 | 編輯原始碼]

部分或完全壓縮、加密或混淆的檔案格式是最難破解的。當然,壓縮不同於加密,通常出於不同的目的進行。然而,產生的檔案格式通常看起來很相似:一堆亂碼。當檔案格式設計人員進行加密時,這是預期的結果,但當應用壓縮時,這也是一個經常想要的副作用。

如果使用十六進位制編輯器或類似工具檢查檔案顯示它只是包含亂碼,例如沒有易於識別的文字字串、模式或類似內容,這可能表明特定檔案被壓縮、加密或混淆。逆向工程這些檔案的方法是相似的。然而,從法律角度來看,可能會有很大差異。許多國家有關於繞過複製保護的法律,而加密可以被視為一種複製保護。有關更多提示,請參閱逆向工程/法律方面,並在嘗試逆向工程加密或其他受保護的檔案格式之前諮詢合格的法律顧問。類似的問題也可能出現在檔案格式僅使用混淆的情況下。格式“所有者”可能會爭辯說混淆被用作某種複製保護、加密或其他東西,繞過它可能會違反某些法律。再次,請諮詢合格的法律顧問。

本節的剩餘部分只討論檔案壓縮的反向工程。這通常只是完整反向工程過程的初始步驟。一旦成功解壓縮,就需要應用其他反向工程方法來識別檔案內容和結構。

眾所周知的壓縮演算法

[編輯 | 編輯原始碼]

檔案格式設計者通常會使用眾所周知的壓縮演算法。無論是使用特定演算法的特定且眾所周知的實現(眾所周知的工具),還是重新實現一個眾所周知的演算法而無需修改。在最簡單的情況下,這已經被記錄在案。例如,眾所周知 OpenOffice 檔案格式使用 ZIP 存檔,因此沒有必要對該格式進行反向工程。

不幸的是,對於許多格式,我們沒有這樣的文件。如果使用了特定演算法的眾所周知的實現,反向工程通常相對容易。這種壓縮檔案格式往往以格式識別符號(*魔數*)開頭,清楚地識別特定的壓縮格式。壓縮工具已將其“指紋”保留在原位。

例子:

以下是特定 SOHO 路由器的虛擬韌體更新檔案的頭幾個位元組的十六進位制轉儲

00000000  60 ea 27 00 1e 06 01 00  10 00 02 84 84 86 dc 34  |`.'............4|
00000010  84 86 dc 34 00 00 00 00  00 00 00 00 00 00 00 00  |...4............|
00000020  00 00 44 54 41 2e 41 52  4a 00 00 b1 18 78 a6 00  |..DTA.ARJ....x..|
00000030  00 60 ea 27 00 1e 06 01  00 10 01 00 84 4c 86 dc  |.`.'.........L..|
00000040  34 9b 17 0c 00 e8 a4 25  00 25 10 0d 10 00 00 20  |4......%.%..... |
00000050  00 00 00 44 54 41 2e 4d  45 4d 00 00 50 98 0b 8f  |...DTA.MEM..P...|
00000060  00 00 1f 30 84 dd 7b db  48 da 6f fd ee fd bb da  |...0..{.H.o.....|

該檔案使用以下方式壓縮ARJ. 不僅字串 *DTA.ARJ* 對人眼來說很明顯,而且前兩個位元組60 ea, 已知用於識別 ARJ 壓縮檔案。

Unix/linux 工具 **file**(1) 對許多標準壓縮檔案格式瞭如指掌。

例子:

**file** 為上述韌體檔案返回以下內容

firmware.bin: ARJ archive data, v6, slash-switched, original name: DTA.ARJ, os: MS-DOS

在發現壓縮格式之後,下一步很明顯:獲取使用壓縮工具的版本並使用它來解壓縮資料。然而,結果通常需要更多的反向工程。例如,上面提到的路由器韌體可能包含針對路由器快閃記憶體的不同區域的單獨部分,每個部分都由一個自己的校驗和保護。

使用眾所周知的壓縮演算法和工具的變體有時也可以找到,這更難進行反向工程。在這種情況下,檔案以一些附加資料為字首,並且無法僅透過檢查檔案格式來識別實際壓縮格式。例如,假設另一個虛擬 SOHO 路由器的韌體更新檔案,其構建方式如下

例子:

另一個 SOHO 路由器韌體更新檔案的虛擬結構

+--------------------------+
|  Boot loader             |
+--------------------------+
|  Decompression algorithm |
+--------------------------+
|  Compressed data         |
+--------------------------+

當然,只有在反向工程檔案格式後才能知道格式。那麼該怎麼做呢?好吧,在虛擬情況下,我們假設使用 Unix/Linux 工具 **strings**(1) 檢查檔案會顯示檔案中以下有趣的字串

例子:

**strings** 的簡化輸出

:
:
unknown compression method
invalid window size
incorrect header check
need dictionary
incorrect data check
invalid block type
invalid stored block lengths
too many length or distance symbols
invalid bit length repeat
 inflate 1.1.3 Copyright 1995-1998 Mark Adler 
oversubscribed dynamic bit lengths tree
incomplete dynamic bit lengths tree
oversubscribed literal/length tree
incomplete literal/length tree
oversubscribed distance tree
incomplete distance tree
empty distance tree with lengths
invalid literal/length code
invalid distance code
invalid distance code
invalid literal/length code
incompatible version
buffer error
insufficient memory
data error
stream error
file error
stream end
need dictionary
1.1.3
application.bin
:
:

這些字串非常有啟發性,那些有知識的人會認出 *Mark Adler* 的名字是以下作者之一zlib zlib, 這是以下的基礎info-zip以及 GNU 的 gzip. 那些不太瞭解的人至少可能想到搜尋名稱和關鍵字壓縮。

可以肯定地假設至少部分檔案是 ZIP 壓縮的。進一步探查可能會發現該檔案不包含完整的 ZIP 存檔,而只是一個使用 ZIPdeflate演算法壓縮的節,並應該使用 ZIPinflate演算法解壓縮(可能是 1.1.3 版,因為 **strings** 的輸出顯示)。因此,可以利用自定義工具進一步將虛擬檔案分離為其元件,該工具迭代地將inflate演算法應用於檔案,直到生成的結果有意義(例如,直到結果包含一些可識別的純文字字串)。

未知或自制壓縮演算法

[編輯 | 編輯原始碼]

如果建立或讀取檔案的軟體可用,則很有可能反向工程檔案格式。您可以在讀取/寫入檔案時對正在執行的應用程式進行即時分析。這樣做可能是確定檔案資料結構的最簡單方法。

如果軟體不可用,如果存在未知或自制/臨時壓縮演算法,或者已知演算法的非標準實現,那麼一切皆有可能。要弄清楚應用演算法的細節,以便可以構建相應的解壓縮演算法,就必須極其幸運,儘管密碼學家強烈反對使用臨時加密方案,因為這些方案通常無法經受住嚴格的密碼分析。

有時可以找到額外的資訊。例如,如果供應商已為特定演算法提交了專利申請,或者已知在其他產品(例如通訊協議)中愛上了特定壓縮技術。有時可能會發現檔案格式實際上屬於某個 OEM 或第三方產品,並且有關該產品的的資訊是可用的。

否則,試錯方法可能會揭示有關檔案的一些資訊。例如,執行長度編碼是一種流行的、簡單的且易於實現的壓縮演算法,因此它們有時可以在自制實現中找到。值得嘗試調查一下檔案是否可能以這種方式壓縮。調查其他一些眾所周知的壓縮技術也值得一試。

最後但並非最不重要的一點是,密碼分析技術可能會揭示有關壓縮的一些有趣資訊。例如,重複出現的塊資訊可能指向特定的壓縮演算法。但是,這需要付出很多努力、時間和技能。


這頁或本節 反向工程 書籍是一個 存根。如果您有關於此主題的資訊,請在此處寫下。

華夏公益教科書