x86 反彙編/彙編器和編譯器
彙編器 比編譯器簡單得多,通常實現為透過一對一的對應關係將彙編程式碼轉換為二進位制機器碼。彙編器很少進行最佳化,除了選擇指令的最短形式或填充延遲槽。
由於彙編是一個如此簡單的過程,反彙編通常也同樣簡單。彙編指令和機器碼字之間存在一對一的對應關係,因此每個機器碼字都將精確地對映到一個彙編指令。然而,反彙編有一些其他困難,無法使用簡單的程式碼字查詢來解決。我們將在這裡介紹彙編器,並在後面討論反彙編。
彙編器在最基本的層面上將彙編指令轉換為機器碼,並且一一對應。它們還可以將命名的變數轉換為硬編碼的記憶體地址,並將標籤轉換為它們在程式碼中的相對地址。
通常,彙編器不執行程式碼最佳化。從彙編器中輸出的機器碼等效於輸入彙編器的彙編指令。一些彙編器在宏的形式下具有高階功能。
在彙編過程中,程式的一些資訊會丟失。首先也是最重要的是,程式資料儲存在與機器碼指令相同的原始二進位制格式中。這意味著很難確定程式的哪些部分實際上是指令。請注意,您可以反彙編原始資料,但結果的彙編程式碼將毫無意義。其次,來自彙編原始碼檔案的文字資訊,例如變數名、標籤名和程式碼註釋,在彙編過程中都會被破壞。當您反彙編程式碼時,指令將相同,但所有其他有用的資訊都會丟失。程式碼將是準確的,但更難閱讀。
正如我們將在後面看到的,編譯器會導致更多資訊丟失,反編譯通常非常困難和複雜,以至於幾乎不可能準確地完成。
由於基於 Intel 的 IA-32 微處理器在家庭 PC 市場中無處不在,因此完成的大多數彙編工作(以及此華夏公益教科書中考慮的大多數彙編工作)都是基於 x86 的。許多這些彙編器(或它們的更新版本)也可以處理 amd64/x86_64/EMT64 程式碼,儘管此華夏公益教科書將主要關注 32 位(x86/IA-32)程式碼示例。
MASM 是微軟的彙編器,是“宏彙編器”的縮寫。然而,許多人將其作為“微軟彙編器”的首字母縮寫,而這種差異根本不是問題。MASM 具有強大的宏功能,能夠編寫非常低階的語法和使用其宏功能的偽高階程式碼。MASM 6.15 目前可以從微軟免費下載,而 MASM 7.xx 目前作為微軟平臺 DDK 的一部分提供。
- MASM 使用 Intel 語法。
- MASM 被微軟用來實現其 Windows 作業系統的一些低階部分。
- 與普遍的看法相反,MASM 自 1980 年以來一直在不斷開發,並且根據需要進行升級。
- MASM 始終由微軟與當前平臺和可執行檔案型別保持相容。
- MASM 目前支援所有 Intel 指令集,包括 SSE2。
許多使用者喜歡 MASM,但更多使用者仍然不喜歡它無法移植到其他系統的事實。
TASM 是 Borland 的“Turbo Assembler”,是 Borland 的一個功能性彙編器,可以與 Borland 的其他軟體開發工具無縫整合。當前釋出版本是版本 5.0。TASM 語法與 MASM 非常相似,儘管它有一個“IDEAL”模式,許多使用者更喜歡它。TASM 不是免費的。
NASM,“Netwide Assembler”,是一個免費、可移植且可重新定位的彙編器,可在 Windows 和 Linux 上執行。它支援各種 Windows 和 Linux 可執行檔案格式,甚至輸出純二進位制檔案。NASM 不像 MASM 或 TASM 那樣“成熟”,但它
- 比 MASM 更可移植
- 比 TASM 更便宜
- 努力做到非常使用者友好
NASM 自帶反彙編器 ndisasm,並支援 64 位(x86-64/x64/AMD64/Intel 64)CPU。
NASM 在 LGPL 下發布。
FASM,“Flat Assembler”,是一個開源彙編器,支援 x86 和 IA-64 Intel 架構。
x86 微處理器彙編程式碼的 AT&T 語法不像 Intel 語法那樣常見,但 GNU 彙編器 (GAS) 使用它,並且它是 Unix 和類 Unix 作業系統上的事實上的彙編標準。
GNU 彙編器 (GAS) 是 GNU 編譯器集合 (GCC) 套件的預設後端。因此,GAS 與 GCC 一樣可移植且可重新定位。但是,GAS 預設使用 AT&T 語法來表示其指令,一些使用者認為它不如 Intel 語法易讀。較新的 gas 版本可以使用指令“.intel_syntax noprefix”切換到 Intel 語法。
GAS 的開發專門用於用作 GCC 後端。由於 GCC 始終向它提供語法正確的程式碼,因此 GAS 通常只有最少的錯誤檢查。
GAS 作為 GCC 包或 GNU binutils 包的一部分提供。 [1]
HLA,“High Level Assembler”的縮寫,是 Randall Hyde 主導的一個專案,旨在建立一個具有高階語法的彙編器。HLA 充當其他彙編器的前端,例如 FASM(預設)、MASM、NASM 和 GAS。HLA 支援“常見”組合語言指令,但也實現了一系列更高層次的結構,例如迴圈、if-then-else 分支和函式。HLA 附帶一個全面的標準庫。
由於 HLA 充當了另一個彙編器的前端,因此程式設計師必須安裝另一個彙編器才能使用 HLA 彙編程式。因此,HLA 程式碼輸出與底層彙編器一樣好,但對於開發人員來說,程式碼更容易編寫。HLA 的高階元件可能會使程式效率降低,但這種代價通常遠遠低於編寫程式碼的便利性。在許多方面,HLA 的高階語法與 Pascal 非常相似,而 Pascal 本身在許多方面又與 C 非常相似,因此許多高階程式設計師會立即掌握 HLA 的許多方面。
以下是一些 HLA 程式碼的示例
mov(src, dest); // C++ style comments
pop(eax);
push(ebp);
for(mov(0, ecx); ecx < 10; inc(ecx)) do
mul(ecx);
endfor;
一些反彙編器和偵錯程式可以將二進位制程式碼反彙編為 HLA 格式,但沒有一個可以忠實地重現 HLA 宏。
一個 編譯器 是一個將一種語言的指令轉換為另一種語言的等效指令的程式。有一種普遍的誤解認為,編譯器總是直接將高階語言轉換為機器語言,但這並非總是如此。許多編譯器將程式碼轉換為組合語言,而有些編譯器甚至將程式碼從一種高階語言轉換為另一種語言。常見的編譯語言有:C/C++、Fortran、Ada 和 Visual Basic。下圖顯示了使用 C 程式語言構建程式的常見編譯時步驟。編譯器生成目標檔案,這些檔案被連結起來形成最終的可執行檔案

就本書而言,我們將只考慮將 C 或 C++ 轉換為彙編程式碼或機器語言的編譯器的案例。一些編譯器,例如 Microsoft C 編譯器,將 C 和 C++ 原始碼直接編譯為機器程式碼。另一方面,GCC 將 C 和 C++ 編譯為組合語言,然後使用匯編器將其轉換為相應的機器程式碼。從反彙編器的角度來看,原始程式的建立方式無關緊要。還要注意,無法完全再現用於建立可執行檔案的原始 C 或 C++ 程式碼。但是,可以建立編譯相同的程式碼,或者執行相同任務的程式碼。
C 語言語句與組合語言之間沒有一對一的關係。請考慮以下 C 語句通常都會編譯成相同的組合語言程式碼
*arrayA = arrayB[x++];
*arrayA = arrayB[x]; x++;
arrayA[0] = arrayB[x++];
arrayA[0] = arrayB[x]; x++;
另外,請考慮以下迴圈結構如何執行相同的任務,以及它們很可能生成相似甚至相同的組合語言程式碼
for(;;) { ... }
while(1) { ... }
do { ... } while(1)
本節的目的是列出一些用於開發生產級軟體的最常見的 C 和 C++ 編譯器。世界上有許多 C 編譯器,但反向工程師不需要考慮所有情況,尤其是在檢視專業軟體時。本頁將討論每個編譯器的優缺點、可用性(下載網站或成本資訊),以及如何從每個編譯器生成彙編列表檔案。
Microsoft C 編譯器可從 Microsoft 免費獲得,作為 Windows Server 2003 SDK 的一部分。它與 MS Visual Studio 中使用的編譯器和庫相同,但沒有附帶花哨的 IDE。MS C 編譯器具有非常好的最佳化引擎。它編譯 C 和 C++,並可以選擇將 C++ 程式碼編譯為 MSIL(.NET 位元組碼)。
Microsoft 的編譯器只支援 Windows 系統和 Intel 相容的 16/32/64 位架構。
Microsoft C 編譯器是cl.exe,連結器是link.exe
在本華夏公益教科書中,cl.exe 經常被用來生成 C 原始碼的彙編列表檔案。要自己生成彙編列表檔案,請使用以下語法
cl.exe /Fa<assembly file name> <C source file>
"/Fa" 開關是告訴編譯器生成彙編列表檔案的命令列選項。
例如,以下命令列
cl.exe /FaTest.asm Test.c
將從 C 原始檔 "Test.c" 生成一個名為 "Test.asm" 的彙編列表檔案。請注意,"/Fa" 開關和輸出檔名稱之間沒有空格。
GNU C 編譯器是 GNU 編譯器集合 (GCC) 套件的一部分。該編譯器適用於大多數系統,並且是免費軟體。許多人專門使用它,以便他們只需處理一個編譯器就可以支援多個平臺。GNU GCC 編譯器是 Linux 和 Unix 系統的事實上的標準編譯器。它是可移植的,允許使用多種輸入語言(C、C++、Obj-C、Ada、Fortran 等),並支援多種目標作業系統和架構。它最佳化得很好,但有一個非激進的 IA-32 程式碼生成引擎。
GCC 前端程式是“gcc”(在 Windows 上為“gcc.exe”),關聯的連結器是“ld”(在 Windows 上為“ld.exe”)。Windows cmd 會自動搜尋帶“.exe”副檔名的程式,因此您不需要鍵入檔名副檔名。
要在 GCC 中生成彙編列表檔案,請使用以下命令列語法
gcc -S /path/to/sourcefile.c
例如,以下命令列
gcc -S test.c
將生成一個名為“test.s”的彙編列表檔案。GCC 生成的彙編列表檔案將採用 GAS 格式。在 x86 上,您可以使用-masm=intel或-masm=att選擇語法。GCC 列表檔案通常沒有 cl.exe 的列表檔案註釋和佈局那麼好。
您可以新增 `-g3` 標誌來啟用原始碼級別的除錯符號,以便您可以在列表中看到行號。-fno-asynchronous-unwind-tables標誌可以幫助消除列表中的某些宏。
該編譯器僅用於 x86、x86-64 和 IA-64 程式碼。它適用於 Windows 和 Linux。Intel C 編譯器是由發明原始 x86 架構的人員編寫的:英特爾。英特爾的開發工具生成針對在英特爾微處理器上執行而最佳化的程式碼,旨在從應用程式中擠出每一絲速度。AMD IA-32 相容處理器不保證獲得相同的速度提升,因為它們具有不同的內部架構。
該編譯器通常用於經典 MacOS 和嵌入式系統。如果您嘗試反向工程消費電子產品,您可能會遇到 Metrowerks CodeWarrior 生成的程式碼。
該編譯器通常用於嵌入式系統。如果您嘗試反向工程消費電子產品,您可能會遇到 Green Hills C/C++ 生成的程式碼。