apk是安卓工程打包的最終形式,將apk安裝到手機(jī)或者模擬器上就可以使用APP。反編譯apk則是將該安卓工程的源碼、資源文件等內(nèi)容破解出來進(jìn)行分析??蛻舳薗A可能會(huì)遇到的問題是,本地測試包與正式發(fā)布的apk包之間可能存在差異(debug與release)。如果能夠進(jìn)行最終上線前的apk反編譯,一方面可以校驗(yàn)apk是否有遺漏的Jar包或者資源文件,另一方面也可以簡要核對本版本apk的基本信息是否正確??杉尤氘a(chǎn)品上線前最終上線清單確認(rèn)的環(huán)節(jié)中。本文主要介紹了apk反編譯的基本原理和主要方法,最后介紹了目前比較成熟的反編譯工具。
一、APK反編譯基本原理
1.APK分析
apk文件的本質(zhì)是壓縮文件,我們將apk文件修改后綴名為zip或者rar等,可以直接解壓縮查看apk文件夾。下圖即為一個(gè)基本的apk文件夾結(jié)構(gòu)圖。

我們簡要看下每個(gè)文件夾和文件里都有什么內(nèi)容:
- assets文件夾:原始資源文件夾,對應(yīng)著Android工程的assets文件夾,一般用于存放原始的圖片、txt、css等資源文件。
- lib:存放應(yīng)用需要的引用第三方SDK的so庫。比如一些底層實(shí)現(xiàn)的圖片處理、音視頻處理、數(shù)據(jù)加密的庫等。而該文件夾下有時(shí)會(huì)多一個(gè)層級(jí),這是根據(jù)不同CPU 型號(hào)而劃分的,如 ARM,ARM-v7a,x86等。
- META-INF:保存apk簽名信息,保證apk的完整性和安全性。
- res:資源文件夾,其中的資源文件包括了布局(layout),常量值(values),顏色值(colors),尺寸值(dimens),字符串(strings),自定義樣式(styles)等。
- AndroidManifest.xml文件:全局配置文件,里面包含了版本信息、activity、broadcasts等基本配置。不過這里的是二進(jìn)制的xml文件,無法直接查看,需要反編譯后才能查看。
- classes.dex文件:這是安卓代碼的核心部分,,dex是在Dalvik虛擬機(jī)上可以執(zhí)行的文件。這里有classes.dex和classes2.dex兩個(gè)文件,說明工程的方法數(shù)較多,進(jìn)行了dex拆分。
- resources.arsc文件:記錄資源文件和資源id的映射關(guān)系。
直接查看apk壓縮文件,只有assets可以直接查看,我們可以校驗(yàn)其中是否已加入必需的資源文件。但是對于版本的基本情況、所需的JAR包等都是無法直接查看的,需要進(jìn)行apk反編譯處理。了解apk的反編譯原理,需要從apk打包原理講起。
2.從APK打包講起
使用IDE進(jìn)行安卓開發(fā),便捷的打包調(diào)試使得打包的很多細(xì)節(jié)都忽略了,安卓官網(wǎng)給出了apk打包的基本流程圖,圖中紅框是我對打包流程幾個(gè)主要模塊的劃分:

我們從中梳理出apk打包的基本流程模塊如下:
-
資源處理
這一過程中主要使用appt工具進(jìn)行資源文件的處理,分析AndroidManifest.xml中的資源文件,生成R.java和resources.arsc文件;aidl工具負(fù)責(zé)處理aidl文件,生成對應(yīng)的java接口文件。 -
代碼編譯
將上一過程中產(chǎn)生的R.java、java接口文件以及工程源代碼一起通過Java Compiler編譯成.class文件,打成Jar包(這部分可以加入代碼混淆),然后與第三方庫的Jar包一起通過dx工具轉(zhuǎn)換成.dex文件。
通過apkbuilder工具將aapt生成的resources.arsc、classes.dex(可能多個(gè))、其他的資源一塊打包生成未經(jīng)簽名的apk文件。 -
添加簽名
通過Jarsigner對生成的未簽名的apk進(jìn)行簽名。
再通過zipalign對簽名后的apk進(jìn)行對其處理,使apk中所有資源文件距離文件起始偏移為4字節(jié)的整數(shù)倍,從而在通過內(nèi)存映射訪問apk文件時(shí)會(huì)更快。
3.APK反編譯原理
通過回顧apk的打包原理,反編譯要做的事情也就明了了。反編譯要做的,一是要將apk里的dex文件轉(zhuǎn)換成Jar包,再通過工具查看編譯前的java源文件。二是通過工具查看apk里對應(yīng)的AndroidManifest.xml、resources.arsc、res各布局文件等二進(jìn)制文件。反編譯所需要的工具主要有以下幾個(gè):
二、APK反編譯實(shí)踐
1.使用dex2jar將dex文件轉(zhuǎn)換成Jar包
在Mac上下載的dex2jar-2.0.zip包直接解壓縮即可,關(guān)鍵需要用到的文件是d2j-dex2jar.sh和d2j-dex2jar_invoke.sh,需要對這兩個(gè)文件先添加可執(zhí)行權(quán)限。然后將目標(biāo)apk改為zip后綴,解壓縮直接拿到其中的dex文件。在終端輸入命令:
./d2j-dex2jar/d2j-dex2jar.sh classes.dex
注意要輸入classes.dex的正確路徑。
命令結(jié)束后會(huì)在當(dāng)前目錄下生成classed-dex2jar.jar文件。如下圖所示:

ps:如果apk的方法數(shù)超過了65535,會(huì)生成多個(gè)dex文件,反編譯的話需要對這多個(gè)dex文件均進(jìn)行轉(zhuǎn)換Jar包處理。
2.使用jd-gui將Jar包文件反編譯成java源文件
jd-gui下載解壓后,直接打開文件夾里面的JD-GUI,即可打開圖形化界面。將我們上一個(gè)步驟生成的classes-dex2jar.jar直接拖動(dòng)進(jìn)入界面中,就可以看到反編譯之后的源碼結(jié)構(gòu)了。

ps:這里有時(shí)候會(huì)看到諸如a.a.a、b等字母標(biāo)示的包名、類名或者方法名,這是由于在某些apk打包的時(shí)候進(jìn)行代碼混淆導(dǎo)致的。使用反編譯工具只能看到混淆之后的代碼結(jié)構(gòu),真正未混淆前的源碼還需要結(jié)合mapping.txt文件進(jìn)行分析。mapping.txt文件里即標(biāo)注出了代碼混淆前后的文件名稱對應(yīng)關(guān)系。
3.使用apktool工具查看apk里的二進(jìn)制文件
下載下來apktool并解壓縮后,調(diào)用java命令執(zhí)行,命令如下:
java -jar apktool.jar d yourApkName.apk
命令執(zhí)行完后,會(huì)在當(dāng)前目錄下新增yourApkName文件夾,其中可以看到可讀的AndroidManifest.xml、res目錄下的各布局文件、assets文件夾等。

original文件夾是原始的AndroidManifest.xml文件,res文件夾是反編譯出來的資源,smali文件夾是反編譯出來的代碼。注意,smali是有點(diǎn)類似于匯編的語法,是Android虛擬機(jī)所使用的寄存器語言。
三、其他APK反編譯工具
以上是apk反編譯常用的主要工具和方法,現(xiàn)在也有一些工具可以將這些反編譯步驟全部集成起來,常用的有:
1.Android-classyshark
下載地址:https://github.com/google/android-classyshark/releases,下載下來之后是一個(gè)可執(zhí)行的jar文件,在終端執(zhí)行java -jar classyshark.jar即可打開圖形化界面。在打開的圖形操作界面中拖入待目標(biāo)apk,即可展示出反編譯之后的結(jié)果。

點(diǎn)擊上方的“Methods count”還能看到各個(gè)類中具體的方法數(shù)。

2.Android Studio 2.2的APK Analyzer
Android Studio 2.2版本新增了APK Analyzer功能,使用方法很簡單,只需要將目標(biāo)apk拖入到Android Studio 2.2中即可。

功能十分強(qiáng)大,可以直接將APK全部反編譯出來,在Android Studio界面上可以直接看到apk版本的信息,直接查看AndroidManifest.xml、R.java等文件。點(diǎn)擊classes.dex可以直接查看反編譯之后的代碼結(jié)構(gòu)。可以說是集合了apktool、dex2jar、jd-gui等反編譯工具的全部功能,十分便捷。
上述是比較常見且較為成熟的apk反編譯工具,但是稍有遺憾的是,以上工具均只能反編譯至混淆后的代碼,如何結(jié)合mapping.txt恢復(fù)成源代碼,還沒有發(fā)現(xiàn)比較好的工具。
四、結(jié)語
在日常安卓端產(chǎn)品測試過程中,曾經(jīng)出現(xiàn)過的問題是本地測試打包與上線打包有差異,原因可能是開發(fā)誤以為某些jar包和資源文件只是本地測試需要,上線不需要,也可能是本地測試打包與上線打包的build types不同,導(dǎo)致本地測試通過,而上線后出現(xiàn)了異常情況。這類問題測試的難點(diǎn)在于,待上線的apk包對于某些情況無法經(jīng)過QA實(shí)時(shí)校驗(yàn)、缺少的jar包和資源文件并不會(huì)導(dǎo)致回歸測試的功能異常等。為了避免這種問題,對于apk正式上線前的上線清單,可考慮加入待發(fā)布apk的反編譯資源包確認(rèn)。QA可仔細(xì)核驗(yàn)最終待發(fā)布的apk,可以通過反編譯的手段進(jìn)一步對apk進(jìn)行分析,查看是否新增的jar包和資源文件、so文件等均沒有遺漏,回歸測試功能點(diǎn)也沒有異常,才能正式上線。
總之,產(chǎn)品發(fā)布是一件需謹(jǐn)慎對待的事情,增加對待上線apk的反編譯分析,一定程度上可以對產(chǎn)品質(zhì)量做最后一道把關(guān)。