0.前言
單純從技術角度上來講,掌握反編譯功能確實是一項非常有用的技能。另外既然別人可以反編譯程序,我們當然有理由應該對程序進行一定的保護,因此代碼混淆也是我們必須要掌握的一項技術。看完此篇如果對代碼混淆也感興趣,可以參考Android安全——混淆技術完全解析。
?
1.反編譯
Android的反編譯主要又分為兩個部分,一個是對代碼反編譯,一個是對資源反編譯。
?
1.1 代碼反編譯
要想將APK文件中的代碼反編譯出來,我們需要用到以下兩款工具:
(a)dex2jar:這個工具用于將dex文件轉換成jar文件。
下載地址:http://sourceforge.net/projects/dex2jar/files/
(b)jd-gui:這個工具用于將jar文件轉換成Java代碼。
下載地址:http://jd.benow.ca/
?
(1)我們首先將APK文件進行解壓,可以先將文件后綴名改成zip,然后用解壓軟件打開。解壓之后你會發現里面有一個classes.dex文件。
(2)classes.dex就是存放所有Java代碼的地方,我們將它拷貝到dex2jar解壓后的目錄下,并在cmd中也進入到同樣的目錄,然后執行:
d2j-dex2jar classes.dex
(3)如果沒有報任何錯誤,這就說明我們已經轉換成功了。現在觀察dex2jar目錄,你會發現多了classes-dex2jar.jar這個文件。但是對于我們而言,jar文件也不是可讀的,因此這里還需要再借助一下jd-gui這個工具來將jar文件轉換成Java代碼。(4)最后一步就是使用jd-gui工具打開classes-dex2jar.jar這個文件。我們便得到了Java代碼。基本已經做到了90%以上的還原工作,像setContentView()方法傳入的參數,反編譯也就只能將相應的id值進行還原,而無法變成像R.layout.activity_main這樣直觀的代碼展示。另外,除了MainActivity之外,引用的library也會作為代碼的一部分被打包到classes.dex文件當中,因此反編譯的時候這些代碼也會一起被還原。
?
1.2 資源反編譯
要想將APK文件中的資源反編譯出來,又要用到另外一個工具了:
Apktool:用于最大幅度地還原APK文件中的9-patch圖片、布局、字符串等等一系列的資源。
下載地址:http://ibotpeaches.github.io/Apktool/install/
(1)下載該工具后目錄下會存在apktool.bat和apktool.jar這兩個文件。
(2)我們將APK文件拷貝到和這兩個文件同樣的目錄下,然后cmd也進入到這個目錄下,并在cmd中執行如下命令:
apktool d <APKName>.apk
(3)第二步成功后我們會發現在當前目錄下多了一個<APKName>文件夾,這個文件夾中存放的就是反編譯的結果了。我們可以打開AndroidManifest.xml、res/layout即可查看資源信息。
【拓展】
第二步命令中d是decode的意思,表示我們要對Demo.apk這個文件進行解碼。那除了這個基本用法之外,我們還可以再加上一些附加參數來控制decode的更多行為:
-f //如果目標文件夾已存在,則強制刪除現有文件夾(默認如果目標文件夾已存在,則解碼失敗)。
-o //指定解碼目標文件夾的名稱(默認使用APK文件的名字來命名目標文件夾)。
-s //不反編譯dex文件,也就是說classes.dex文件會被保留(默認會將dex文件解碼成smali文件)。
-r //不反編譯資源文件,也就是說resources.arsc文件會被保留(默認會將resources.arsc解碼成具體的資源文件)。
2.? 重新打包
首先我們來看一下通過apktool反編譯后的包目錄情況,如下圖所示:
(1)其中,original文件夾下存放的是未經反編譯過、原始的AndroidManifest.xml文件。
(2)res文件夾下存放的是反編譯出來的所有資源。
(3)smali文件夾下存放的是反編譯出來的所有代碼。
(4)AndroidManifest.xml則是經過反編譯還原后的manifest文件。
這里值得一提的是smali文件夾,如果你進入到這個文件夾中你會發現它的目錄結構和我們源碼中src的目錄結構是幾乎一樣的,主要的區別就是所有的Java文件都變成了smali文件。smali文件其實也是真正的源代碼,只不過它的語法和Java完全不同,它有點類似于匯編的語法,是Android虛擬機所使用的寄存器語言,如果你能夠看得懂smali文件的話,那么你就可以做很恐怖的事情了——你可以隨意修改應用程序內的邏輯,將其進行破解。我們可以稍微改變smali文件里的部分內容,并重新打包,只需要在cmd中執行如下命令:
apktool b Demo -o <New_APKName>.apk
其中b是build的意思,表示我們要將Demo文件夾打包成APK文件,-o用于指定新生成的APK文件名。成功后便在當前目錄下生成了apk文件。
3.??重新簽名
不過目前這個<New_APKName>.apk還是不能安裝的,因為它還沒有進行簽名。我們顯然沒有辦法拿到原作者的簽名,因此我們只能拿自己的簽名文件對這個APK文件重新進行簽名,重新打包出來的軟件也就是個盜版軟件。使用Android Studio或者Eclipse都可以非常簡單地生成一個簽名文件。
有了簽名文件之后在cmd中執行簽名命令就可以進行簽名了,命令格式如下:
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore 簽名文件名 -storepass 簽名密碼 待簽名的APK文件名 簽名的別名
(1)其中jarsigner命令文件是存放在jdk的bin目錄下的,需配置系統的環境變量。下同。
(2)簽名之后的APK文件現在已經可以安裝到手機上了,不過在此之前為了使得我們的程序在Android系統中運行得更快,我們需要對簽名后的APK文件進行一次對齊操作(使用的是zipalign工具,存放于<Android SDK>/build-tools/<version>目錄下),命令格式如下:
zipalign 4 <New_APKName>.apk <New_APKName_aligned >.apk
(3)其中4是固定值不能改變,后面指定待對齊的APK文件名和對齊后的APK文件名。運行這段命令之后就會生成一個<New_APKName_aligned >.apk文件,便可以在手機上運行我們重新打包過后的APK了。
?
轉載整理自郭大俠博客:http://blog.csdn.net/guolin_blog/article/details/49738023