以前一直有猶豫過要不要寫這篇文章,畢竟去反編譯人家的程序並非什麼值得驕傲的事情。不過單純從技術角度上來說,掌握反編譯功能確實是一項很是有用的技能,可能日常不太會用獲得,可是一旦真的須要用到的了,而你卻不會的話,那就很是頭疼了。另外既然別人能夠反編譯程序,咱們固然有理由應該對程序進行必定程度的保護,所以代碼混淆也是咱們必需要掌握的一項技術。那麼最近的兩篇文章咱們就圍繞反編譯和混淆這兩個主題來進行一次徹底解析。 java
咱們都知道,Android程序打完包以後獲得的是一個APK文件,這個文件是能夠直接安裝到任何Android手機上的,咱們反編譯其實也就是對這個APK文件進行反編譯。Android的反編譯主要又分爲兩個部分,一個是對代碼的反編譯,一個是對資源的反編譯,咱們立刻來逐個學習一下。
在開始學習以前,首先咱們須要準備一個APK文件,爲了尊重全部開發者,我就不拿任何一個市面上的軟件來演示了,而是本身寫一個Demo用來測試。
這裏我但願代碼越簡單越好,所以咱們創建一個新項目,在Activity里加入一個按鈕,當點擊按鈕時彈出一個Toast,就這麼簡單,代碼以下所示: linux
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button button = (Button) findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MainActivity.this, "you clicked button", Toast.LENGTH_SHORT).show(); } }); } }
activity_main.xml中的資源以下所示: android
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin"> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button"/> </RelativeLayout>
而後咱們將代碼打成一個APK包,並命名成Demo.apk,再把它安裝到手機上,結果以下所示: git
要想將APK文件中的代碼反編譯出來,咱們須要用到如下兩款工具: github
將這兩個工具都下載好並解壓,而後咱們就開始對Demo程序進行反編譯。解壓dex2jar壓縮包後,你會發現有不少個文件,以下圖所示: 緩存
d2j-dex2jar classes.dex
執行結果以下圖所示: app
其實細心的朋友可能已經觀察到了,剛纔Demo.apk的解壓目錄當中不是已經有資源文件了嗎,有AndroidManifest.xml文件,也有res目錄。進入res目錄當中,內容以下圖所示: ide
關於這個工具的下載我還要再補充幾句,咱們須要的就是apktool.bat和apktool.jar這兩個文件。目前apktool.jar的最新版本是2.0.3,這裏我就下載最新的了,而後將apktool_2.0.3.jar重命名成apktool.jar,並將它們放到同一個文件夾下就能夠了,以下圖所示: 工具
apktool d Demo.apk
其中d是decode的意思,表示咱們要對Demo.apk這個文件進行解碼。那除了這個基本用法以外,咱們還能夠再加上一些附加參數來控制decode的更多行爲: 佈局
經常使用用法就這麼多了,那麼上述命令的執行結果以下圖所示:
那麼對於反編譯出來的文件夾,咱們能不能從新把它打包成APK文件呢?答案是確定的,只不過我實在想不出有什麼義正言辭的理由可讓咱們這麼作。有的人會說漢化,沒錯,漢化的方式確實就是將一個APK進行反編譯,而後翻譯其中的資源再從新打包,可是無論怎麼說這仍然是將別人的程序進行破解,因此我並不認爲這是什麼光榮的事情。那麼咱們就不去討論自己這件事情的對或錯,這裏只是站在技術的角度來學習一下從新打包的相關知識。
首先咱們來看一下經過apktool反編譯後的包目錄狀況,以下圖所示:
而後從AndroidManifest.xml文件中能夠看出,應用圖標使用的是ic_launcher.png這張圖片,那麼咱們將上面籃球這張圖片命名成ic_launcher.png,而後拷貝到全部以res/mipmap開頭的文件夾當中完成替換操做。
在作了兩處改動以後,咱們如今來把反編譯後的Demo文件夾從新打包成APK吧,其實很是簡單,只須要在cmd中執行以下命令:
apktool b Demo -o New_Demo.apk
其中b是build的意思,表示咱們要將Demo文件夾打包成APK文件,-o用於指定新生成的APK文件名,這裏新的文件叫做New_Demo.apk。執行結果以下圖所示:
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore 簽名文件名 -storepass 簽名密碼 待簽名的APK文件名 簽名的別名
其中jarsigner命令文件是存放在jdk的bin目錄下的,須要將bin目錄配置在系統的環境變量當中才能夠在任何位置執行此命令。
簽名以後的APK文件如今已經能夠安裝到手機上了,不過在此以前Android還極度建議咱們對簽名後的APK文件進行一次對齊操做,由於這樣可使得咱們的程序在Android系統中運行得更快。對齊操做使用的是zipalign工具,該工具存放於<Android SDK>/build-tools/<version>目錄下,將這個目錄配置到系統環境變量當中就能夠在任何位置執行此命令了。命令格式以下:
zipalign 4 New_Demo.apk New_Demo_aligned.apk
其中4是固定值不能改變,後面指定待對齊的APK文件名和對齊後的APK文件名。運行這段命令以後就會生成一個New_Demo_aligned.apk文件,以下所示:
好的,咱們把反編譯代碼、反編譯資源、從新打包這三大主題的內容都已經掌握了,關於反編譯相關的內容就到這裏,下篇文章會介紹Android代碼混淆方面的相關技術,敬請期待。