This shows you the differences between two versions of the page.
— |
study:apk-decompiler:250729-001:index [2025/07/29 15:15] (current) jethro created |
||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ~~NOTOC~~ | ||
+ | ====== 人人都會的 Android Apk 反編譯 #5 (2025-07-29) ====== | ||
+ | * Source: [[https://github.com/aszx87410/blog/issues/5]] | ||
+ | * {{:study:apk-decompiler:250729-001:pasted:20250729-150752.png?300}} | ||
+ | ===== Local Backup ===== | ||
+ | * 對於 Android 工程師來說,了解如何反編譯可以增進自己對 Android 底層的理解,也可以思考如何保護自己的 apk 不被反編譯。 | ||
+ | * 對於一般人來說,許多現成的工具可以幫助我們非常輕鬆的、只要打打幾個指令就可以反編譯 apk,看到 java source code,滿足自己的好奇心。 | ||
+ | * 本篇文章只介紹一些工具的使用,適合初學者觀看。若是想了解更底層的知識,可以參考文末附上的延伸閱讀。 | ||
+ | ===== 事前準備 ===== | ||
+ | * 首先,我們需要一個用來被破解的 apk,簡單用任何你平常熟悉的工具自己 build 一個就好了。基本架構很簡單,只要一個 MainActivity 跟兩個TextView就好: | ||
+ | * <sxh java>public class MainActivity extends Activity { | ||
+ | @Override | ||
+ | protected void onCreate(Bundle savedInstanceState) { | ||
+ | super.onCreate(savedInstanceState); | ||
+ | setContentView(R.layout.activity_main); | ||
+ | TextView text = (TextView)findViewById(R.id.text); | ||
+ | text.setText("Taiwan No1"); | ||
+ | } | ||
+ | } | ||
+ | <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||
+ | android:layout_width="match_parent" | ||
+ | android:orientation="vertical" | ||
+ | android:layout_height="match_parent"> | ||
+ | |||
+ | <TextView | ||
+ | android:text="@string/hello_world" | ||
+ | android:layout_width="wrap_content" | ||
+ | android:layout_height="wrap_content" /> | ||
+ | |||
+ | <TextView | ||
+ | android:id="@+id/text" | ||
+ | android:layout_width="wrap_content" | ||
+ | android:layout_height="wrap_content" /> | ||
+ | |||
+ | </LinearLayout></sxh> | ||
+ | * 安裝到手機上之後,會看到這樣的畫面:\\ {{:study:apk-decompiler:250729-001:pasted:20250729-150846.png?300}} | ||
+ | ===== 實際動手 ===== | ||
+ | * 好,這個就是我們要拿來測試的 apk 了! | ||
+ | * 接著你需要一些非常好用的工具: | ||
+ | * 1. [[http://ibotpeaches.github.io/Apktool/|apktool]] | ||
+ | * 2. [[http://jd.benow.ca/|jd-gui]] | ||
+ | * 3. [[https://sourceforge.net/projects/dex2jar/|dex2jar]] | ||
+ | * 如何安裝就不再贅述了,讀者們可以參考看看文件或是上網搜尋一下就會有一堆解答~ | ||
+ | * apktool是拿來把 apk 拆開用的,可以反編譯 apk 之後,看到 smali 檔案跟 resource | ||
+ | * dex2jar可以把 apk 轉成 jar,再用jd-gui檢視 java code | ||
+ | * 接著我們開啟 terminal,到剛剛那個示範 apk 的目錄底下,執行apktool d APKNAME.apk | ||
+ | * {{:study:apk-decompiler:250729-001:pasted:20250729-151004.png?500}} | ||
+ | * 執行以後,會自動生成一個APKNAME的資料夾,裡面就是反編譯出來的東西了。 | ||
+ | * <sxh>. | ||
+ | ├── AndroidManifest.xml | ||
+ | ├── apktool.yml | ||
+ | ├── original | ||
+ | ├── res | ||
+ | └── smali</sxh> | ||
+ | * 其中比較值得講的是smali這個資料夾,其實這裡面就是你的 source code,只是格式不太一樣。 | ||
+ | * 你可以在smali這資料夾裡面找到你的MainActivity.java,內容如下: | ||
+ | * (覺得長得很奇怪是很正常的事,但是認真多看幾眼,你會發現其實沒那麼難懂) | ||
+ | * <sxh java>.class public Lapktest/huli/com/apkdecompile/MainActivity; | ||
+ | .super Landroid/app/Activity; | ||
+ | .source "MainActivity.java" | ||
+ | |||
+ | # direct methods | ||
+ | .method public constructor <init>()V | ||
+ | .locals 0 | ||
+ | |||
+ | .prologue | ||
+ | .line 8 | ||
+ | invoke-direct {p0}, Landroid/app/Activity;-><init>()V | ||
+ | |||
+ | return-void | ||
+ | .end method | ||
+ | |||
+ | # virtual methods | ||
+ | .method protected onCreate(Landroid/os/Bundle;)V | ||
+ | .locals 2 | ||
+ | .param p1, "savedInstanceState" # Landroid/os/Bundle; | ||
+ | |||
+ | .prologue | ||
+ | .line 12 | ||
+ | invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V | ||
+ | |||
+ | .line 13 | ||
+ | const v1, 0x7f040019 | ||
+ | |||
+ | invoke-virtual {p0, v1}, Lapktest/huli/com/apkdecompile/MainActivity;->setContentView(I)V | ||
+ | |||
+ | .line 14 | ||
+ | const v1, 0x7f0c0050 | ||
+ | |||
+ | invoke-virtual {p0, v1}, Lapktest/huli/com/apkdecompile/MainActivity;->findViewById(I)Landroid/view/View; | ||
+ | |||
+ | move-result-object v0 | ||
+ | |||
+ | check-cast v0, Landroid/widget/TextView; | ||
+ | |||
+ | .line 15 | ||
+ | .local v0, "text":Landroid/widget/TextView; | ||
+ | const-string v1, "Taiwan No1" | ||
+ | |||
+ | invoke-virtual {v0, v1}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V | ||
+ | |||
+ | .line 16 | ||
+ | return-void | ||
+ | .end method</sxh> | ||
+ | * 你可以仔細對照一下剛剛自己寫的 java code,會發現只是換了種格式而已: | ||
+ | * <sxh>setContentView(R.layout.activity_main);</sxh> | ||
+ | * 其實就等於 | ||
+ | * <sxh>.line 13 | ||
+ | const v1, 0x7f040019 | ||
+ | invoke-virtual {p0, v1}, Lapktest/huli/com/apkdecompile/MainActivity;->setContentView(I)V</sxh> | ||
+ | * 你可能會好奇,這個0x7f040019是哪來的? | ||
+ | * 事實上,你可以在res/values/public.xml這個檔案裡面找到答案: | ||
+ | * <sxh xml><public type="layout" name="activity_main" id="0x7f040019" /></sxh> | ||
+ | * 到這裡,應該就可以大概猜出 Android 在編譯時候的流程: | ||
+ | * 1. 把所有資源檔壓縮、處理並且包在一起,產生id與記憶體位置對照表 | ||
+ | * 2. 把程式碼裡面所有的R.xx.xxx透過剛剛產生的表,換成實際的記憶體位置 | ||
+ | * 3. 把 java code 變成 smali code(有點像把 C 變成組合語言的程式碼那樣) | ||
+ | ===== 修改 ===== | ||
+ | * 在剛剛的smali裡面,有這麼一段: | ||
+ | * <sxh>.line 15 | ||
+ | .local v0, "text":Landroid/widget/TextView; | ||
+ | const-string v1, "Taiwan No1" | ||
+ | |||
+ | invoke-virtual {v0, v1}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V</sxh> | ||
+ | * 讓我們把Taiwan No1換成T@iw@n n0!。 | ||
+ | * 還記得另一個TextView有用到R.string.hello_world嗎? | ||
+ | * 在res/values/strings.xml裡面,可以找到這一串的定義: | ||
+ | * <sxh><string name="hello_world">Hello world!</string></sxh> | ||
+ | * 改成: | ||
+ | * <sxh><string name="hello_world">HELLO WORLD</string></sxh> | ||
+ | * 確定都有改完以後,就可以把這些程式碼再度「組裝」回去。 | ||
+ | * 還記得剛剛反編譯的指令嗎?apktool d APK_NAME.apk | ||
+ | * 這邊的d就是decompile的意思,所以如果要逆向組裝回去,就是b,build。 | ||
+ | * <sxh>apktool b APK_NAME</sxh> | ||
+ | * 執行完之後可以在APK_NAME/dist下面找到一個 apk。 | ||
+ | * 但要注意的是這個 apk 還沒有被 sign 過,因此無法安裝。 | ||
+ | * 可以隨便生成一個 keystore 或是找現成的來簽署。 | ||
+ | * <sxh>jarsigner -verbose -digestalg SHA1 -keystore ~/KEY.keystore APK_NAME.apk KEY_ALIAS</sxh> | ||
+ | * 安裝完以後就會看到這樣的畫面: | ||
+ | * {{:study:apk-decompiler:250729-001:pasted:20250729-151311.png?300}} | ||
+ | * 沒錯!就是這麼簡單,一個 apk 就這樣被修改了! | ||
+ | * 可是smali的程式碼不好懂,能不能直接看到 java code呢? | ||
+ | * 這時候剛剛推薦的工具dex2jar與jd-gui就派上用場了 | ||
+ | * 前者可以把 apk 變成 jar,後者可以開啟一個 jar 並且顯示 java code | ||
+ | * 兩個組合在一起,就可以直接看到原本的程式碼了 | ||
+ | * dex2jar下載下來之後會有一堆的 shell script,dex2jar就是我們想要的那個 | ||
+ | * <sxh>./d2j-dex2jar.sh app.apk</sxh> | ||
+ | * 執行完之後會有一個 jar,用 jd-gui 打開,會看到你的程式碼一覽無遺: | ||
+ | * {{:study:apk-decompiler:250729-001:pasted:20250729-151348.png?500}} | ||
+ | ===== 總結 ===== | ||
+ | * 沒接觸過反編譯的人可能會很驚訝:什麼!要改掉一個 apk 居然這麼簡單! | ||
+ | * 沒錯,就是這麼簡單,而且這只是一個很基本的範例而已。事實上,你想要加入新的程式碼、加入新的資源(圖片、聲音等等)也是可以的。 | ||
+ | * 也就是說,你不只可以修改,還可以擴充原本的 apk! | ||
+ | * 但也有些方法可以防止不肖人士反編譯 apk,例如說加殼、混淆、動態載入等,關於這些方法我們下次有機會再介紹給大家囉! | ||
+ | ===== 延伸閱讀 ===== | ||
+ | * 1. [[https://magiclen.org/android-decompiler/|Android 反編譯與防止被反編譯]] | ||
+ | * 2. [[http://aiur3908.blogspot.tw/2015/07/android-proguard.html|[Android] 程式碼混淆(ProGuard)與反組譯]] | ||
+ | * 3. [[http://blog.davidou.org/archives/553|[Android] 反組譯 破解Android的apk安裝檔]] | ||
+ | * 4. [[http://www.wangchenlong.org/2016/03/19/reverse-analyze-apk/|反编译的常用工具与使用方法]] | ||
+ | * 5. [[http://blog.csdn.net/wdaming1986/article/details/8299996|Smali--Dalvik虚拟机指令语言-->【android_smali语法学习一】]] | ||
+ | * 6. [[http://blog.isming.me/2015/01/14/android-decompile-smali/|android反编译-smali语法]] | ||
+ | ====== Reference ===== | ||
+ | * | ||
+ | ====== ====== | ||
+ | * {{counter}} person(s) visited this page until now. | ||
+ | * [[:study:apk-decompiler:index|Back]] | ||
+ | ====== ====== | ||
+ | <html> | ||
+ | <!-- | ||
+ | PDF for A4-Portrait: {{pdfjs 50%,450px > xxx.pdf?page-fit}} | ||
+ | PDF for A4-Landscape: {{pdfjs 700px,500px > xxx.pdf?page-fit}} | ||
+ | PDF for iPad Note: {{pdfjs 700px,500px > xxx.pdf?page-fit}} | ||
+ | |||
+ | {{gallery>work-note:2024-08:12?lightbox&0&150x150&crop}} | ||
+ | |||
+ | Youtube: {{youtube>large:XXXXX}} | ||
+ | Code Highlight: <sxh php; first-line: 70; highlight: [89,92]; title: New title attribute in action> | ||
+ | |||
+ | --> | ||
+ | </html> |