編輯:關於android開發
之前一直有猶豫過要不要寫這篇文章,畢竟去反編譯人家的程序並不是什麼值得驕傲的事情。不過單純從技術角度上來講,掌握反編譯功能確實是一項非常有用的技能,可能平常不太會用得到,但是一旦真的需要用到的了,而你卻不會的話,那就非常頭疼了。另外既然別人可以反編譯程序,我們當然有理由應該對程序進行一定程度的保護,因此代碼混淆也是我們必須要掌握的一項技術。那麼最近的兩篇文章我們就圍繞反編譯和混淆這兩個主題來進行一次完全解析。
我們都知道,Android程序打完包之後得到的是一個APK文件,這個文件是可以直接安裝到任何Android手機上的,我們反編譯其實也就是對這個APK文件進行反編譯。Android的反編譯主要又分為兩個部分,一個是對代碼的反編譯,一個是對資源的反編譯,我們馬上來逐個學習一下。
在開始學習之前,首先我們需要准備一個APK文件,為了尊重所有開發者,我就不拿任何一個市面上的軟件來演示了,而是自己寫一個Demo用來測試。
這裡我希望代碼越簡單越好,因此我們建立一個新項目,在Activity裡加入一個按鈕,當點擊按鈕時彈出一個Toast,就這麼簡單,代碼如下所示:
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中的資源如下所示:
<code class="language-xml hljs "><!--{cke_protected}{C}%3C!%2D%2D%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%2D%2D%3E--> <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"> </relativelayout></code><button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button"><code class="language-xml hljs "> </code></button>
然後我們將代碼打成一個APK包,並命名成Demo.apk,再把它安裝到手機上,結果如下所示:
要想將APK文件中的代碼反編譯出來,我們需要用到以下兩款工具:
dex2jar 這個工具用於將dex文件轉換成jar文件將這兩個工具都下載好並解壓,然後我們就開始對Demo程序進行反編譯。解壓dex2jar壓縮包後,你會發現有很多個文件,如下圖所示:
d2j-dex2jar classes.dex
執行結果如下圖所示:
其實細心的朋友可能已經觀察到了,剛才Demo.apk的解壓目錄當中不是已經有資源文件了嗎,有AndroidManifest.xml文件,也有res目錄。進入res目錄當中,內容如下圖所示:
apktool 這個工具用於最大幅度地還原APK文件中的9-patch圖片、布局、字符串等等一系列的資源。
關於這個工具的下載我還要再補充幾句,我們需要的就是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的更多行為:
-f 如果目標文件夾已存在,則強制刪除現有文件夾(默認如果目標文件夾已存在,則解碼失敗)。 -o 指定解碼目標文件夾的名稱(默認使用APK文件的名字來命名目標文件夾)。 -s 不反編譯dex文件,也就是說classes.dex文件會被保留(默認會將dex文件解碼成smali文件)。 -r 不反編譯資源文件,也就是說resources.arsc文件會被保留(默認會將resources.arsc解碼成具體的資源文件)。常用用法就這麼多了,那麼上述命令的執行結果如下圖所示:
C:\Users\Administrator\apktool\framework
這個目錄下生成一個名字為1.apk
的緩存文件,將這個緩存文件刪除掉,然後再重新執行反編譯命令應該就可以成功了。
那麼對於反編譯出來的文件夾,我們能不能重新把它打包成APK文件呢?答案是肯定的,只不過我實在想不出有什麼義正言辭的理由可以讓我們這麼做。有的人會說漢化,沒錯,漢化的方式確實就是將一個APK進行反編譯,然後翻譯其中的資源再重新打包,但是不管怎麼說這仍然是將別人的程序進行破解,所以我並不認為這是什麼光榮的事情。那麼我們就不去討論本身這件事情的對或錯,這裡只是站在技術的角度來學習一下重新打包的相關知識。
首先我們來看一下通過apktool反編譯後的包目錄情況,如下圖所示:
you clicked button
這樣一句Toast,邏輯是寫在MainActivity按鈕點擊事件的匿名類當中的,因此這段代碼反編譯之後一定就會在MainActivity$1.smali這個文件當中,讓我們打開瞧一瞧,部分代碼如下所示:Your app is been hacked
。
然後從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工具,該工具存放於/build-tools/
目錄下,將這個目錄配置到系統環境變量當中就可以在任何位置執行此命令了。命令格式如下:
zipalign 4 New_Demo.apk New_Demo_aligned.apk
其中4是固定值不能改變,後面指定待對齊的APK文件名和對齊後的APK文件名。運行這段命令之後就會生成一個New_Demo_aligned.apk文件,如下所示:
好的,我們把反編譯代碼、反編譯資源、重新打包這三大主題的內容都已經掌握了,關於反編譯相關的內容就到這裡,下篇文章會介紹Android代碼混淆方面的相關技術,敬請期待。
Android開發:程序目錄結構詳解 HelloWorld程序的目錄結構概述 我們可以在文件夾中看到,HelloWorld程序的目錄主要包括
Android-->Genymotion虛擬機(模擬器)的配置,genymotion模擬器配置 --> Genymotion 是一套完整
Android圖文混排(一)-實現EditText圖文混合插入上傳 前段時間做了一個Android會議管理系統,項目需求涉及到EditText的圖文混排,如圖: 在上
注冊界面設計及實現之(三)SharedPerferences實現數據暫存,sharedptr實現開發步驟: 創建一個SharedPerferences接口對象,並使用其