使用 jadx 反編譯 class、DEX、JAR 和 APK 文件
1. 引言
我們可以將逆向工程視為一件好事或壞事,但它在許多情況下都是可以合理使用的。反編譯就是其中一種方法。 Java 應用程式尤其適合這種操作。 Java 字節碼類別檔案由 Java 虛擬機器 (JVM) 使用。在 Android 系統中,Dalvik 執行檔 (DEX) 由 Dalvik 虛擬機器 (DVM) 運作。
在本教程中,我們將學習如何檢查 JAR 和 APK 檔案以及反編譯類別檔案和 DEX 檔案。
2. 如何獲取jadx
在 Ubuntu 和 Windows 系統上,我們需要下載原始碼並進行編譯。所以,讓我們克隆GitHub 倉庫:
$ git clone https://github.com/skylot/jadx.git
讓我們切換到jadx資料夾:
$ cd jadx
現在,讓我們使用 Gradle Wrapper 建置程式:
$ ./gradlew build
之後,我們在build/jadx/bin子資料夾中找到執行 jadx 的腳本。為了在當前會話中使用它,我們將此資料夾新增到PATH環境變數中:
$ export PATH=~/jadx/build/jadx/bin:$PATH
3. 運行jadx
我們可以使用 jadx 作為命令列工具:
$ jadx
為了更方便使用,我們提供了一個圖形化應用程序, jadx-gui :
$ jadx-gui
4. 應用範例
為了示範反編譯,我們將使用一個簡單的類似 Hello-World 的ExampleForJadx應用程式。
它從資源文字檔案中讀取著名訊息,並以大寫字母將其列印到標準輸出。
我們使用兩個類別來完成這項任務: ExampleForJadx ,其中包含main()方法; ExampleForJadxUtils ,其中包含檔案讀取器和文字操作函數。
5. 反編譯字節碼類文件
讓我們反編譯ExampleForJadx.class檔案:
$ jadx ExampleForJadx.class
之後,我們可以使用tree指令查看結果:
$ tree
.
├── ExampleForJadx
│ ├── resources
│ └── sources
│ └── com
│ └── baeldung
│ └── exampleforjadx
│ └── ExampleForJadx.java
└── ExampleForJadx.class
6 directories, 2 files
我們看到 jadx 恢復了相應的 Java 原始碼檔案並回憶起了類別的包結構。
6. 反編譯應用程式 JAR 文件
同樣簡單的方法是,我們可以提取並反編譯儲存在ExampleForJadx.jar檔案中的整個應用程式:
$ jadx ExampleForJadx.jar
同樣, tree向我們展示了最終的資料夾結構:
$ tree
.
├── ExampleForJadx
│ ├── resources
│ │ ├── com
│ │ │ └── baeldung
│ │ │ └── exampleforjadx
│ │ │ ├── ExampleForJadx.class
│ │ │ └── ExampleForJadxUtil.class
│ │ ├── exampleforjadx
│ │ │ └── HelloWorld.txt
│ │ └── META-INF
│ │ └── MANIFEST.MF
│ └── sources
│ └── com
│ └── baeldung
│ └── exampleforjadx
│ ├── ExampleForJadx.java
│ └── ExampleForJadxUtil.java
└── ExampleForJadx.jar
11 directories, 7 files
我們識別出了Java應用程式的組成部分。我們有清單檔案MANIFEST.MF ,包含HelloWorld.txt檔案的resources資料夾,當然還有兩個類別的原始程式碼檔案。
7. 程式碼產生模式
讓我們來看看與原始程式碼片段對應的生成程式碼:
public String resourceFileReader(String fileName) throws IOException, FileNotFoundException {
try (InputStream in = getClass().getResourceAsStream(fileName);
BufferedReader reader = new BufferedReader(new InputStreamReader(in))) {
String result = null;
if (in != null) {
result = reader.lines()
.collect(Collectors.joining("\n"));
}
return result;
}
}
在jadx-gui中,我們看到:
因此,原有的 try-with-resource 結構被一系列 try-catch 程式碼區塊所取代。即使在如此簡單的例子中,我們也不應該期望能夠實現一對一的恢復。
我們可以將反編譯模式設定為auto 、 restructure 、 simple或fallback 。這些模式可以在圖形使用者介面 (GUI) 的Preferences中找到,也可以透過jadx -m ( –decompilation-mode )開關進行設定。這些模式涵蓋了從最易於閱讀到生成程式碼最底層的各種情況。
8. Android 應用程式範例
例如,我們將使用由Appliberated在 GitHub 上提供的、採用 MIT 授權的HelloWorldSelfAware應用程式。我們可以下載已發布的應用程式。它會列印「Hello World」問候語,以及有關 Android 系統的資訊:
9. 檢查 APK 文件
讓我們用jadx-gui開啟HelloWorldSelfAware APK 檔案:
首先,我們來介紹開發者所建立的三個類別: MainActivity 、 AndroidInfo和Utils 。在上圖中,它們被綠色框框起來。接下來,黃色框框內是 R 類,也就是 Java 自動產生的原始碼,用來表示資源。最後,紅色框框內是 Java 在編譯過程中產生的合成類別和橋接方法。
最後,我們來檢查一下二進位類別檔案classes.dex :
10. 結論
本文介紹了jadx ,一款出色的 Java 應用程式反編譯工具。首先,我們從原始碼建構了命令列工具jadx和圖形介面工具jadx-gui 。然後,我們使用它反編譯了類別文件並分析了 JAR 檔案。接下來,我們分析了 Android 應用程序,提取了其組件並反編譯了 DEX 檔案。
最後要指出的是,jadx 不只是一個反編譯工具。此外,它還可以從提取的原始程式碼產生 Gradle 專案、生成控制流程圖 (CFG) 或偵錯 Android 應用程式。
和往常一樣,範例程式碼可在 GitHub 上找到。