Android混淆及反編譯的方式

Sun
彼得潘的 Swift iOS / Flutter App 開發教室
8 min readNov 18, 2019

一般來說andorid App可以把副檔名改掉,APK變成ZIP解壓縮之後裡面會有DEX檔案,用下面工具就可以把DEX變成jar然後進行反編譯的動作。

JD-GUI 反編譯工具 http://java-decompiler.github.io/

DEX2jar DEX轉JAR https://sourceforge.net/projects/dex2jar/

使用終端機進行dex2jar

sudo chmod +x d2j-dex2jar.sh 打開權限

./d2j-dex2jar.sh classes.dex

之後就會產生一個jar檔在資料夾裡面

如果想要增加被別人反編譯的難度就必須要做到檔案混淆的動作,andorid studio內建功能Proguard就可以做到這些效果。

混淆方法:

1.在Gradle Scripts->build.gradle 檔案裡面設定:

minifyEnabled true

useProguard true

proguardFiles getDefaultProguardFile(‘proguard-android.txt’), ‘proguard-rules.pro’

在Gradle Scripts->gradle.properties

android.enableR8 = false

2.在proguard-rules.pro這裡必須要設定混淆規則,一定要設定不然proguard沒有規則不會進行混淆,基本規則大概如下

# 代碼混淆壓縮比,一般在0~7之間,預設為5一般這不做調整。

-optimizationpasses 5

# 混合時不用大小寫混合,混合後的類別名為小寫。

-dontusemixedcaseclassnames

# 指定不去忽略非公共庫的類別。

-dontskipnonpubliclibraryclasses

# 這句話能夠使我們的項目混淆後產生映射文件。

# 包含有類別名->混淆後類別名的映射關係。

-verbose

# 指定不忽略非公共庫的類別。

-dontskipnonpubliclibraryclassmembers

-dontshrink

# 不做預校驗,preverifyproguard的四個步驟之一,Android不需要preverify,去掉這一步能夠加快混淆速度。

-dontpreverify

# 保留Annotation不混淆。

-keepattributes *Annotation*,InnerClasses

# 避免混淆泛型。

-keepattributes Signature

# 異常時保留顯示行號。

-keepattributes SourceFile,LineNumberTable

# 指定混淆採用的算法,後面的參數是個過濾器。

# 此過濾器事google推薦的算法一般不做更改。

-optimizations !code/simplification/cast,!field/*,!class/merging/*

# 保留我們使用的四大组件,自定義的Application等等這些類別不被混淆。

# 因為这些子類別都有可能被外部調用。

-keep public class * extends android.app.Activity

-keep public class * extends android.app.Appliction

-keep public class * extends android.app.Service

-keep public class * extends android.content.BroadcastReceiver

-keep public class * extends android.content.ContentProvider

-keep public class * extends android.app.backup.BackupAgentHelper

-keep public class * extends android.preference.Preference

-keep public class * extends android.view.View

-keep public class com.android.vending.licensing.ILicensingService

保留support下的所有類別。

-keep class android.support.** {*;}

# 保留繼承。

-keep public class * extends android.support.v4.**

-keep public class * extends android.support.v7.**

-keep public class * extends android.support.annotation.**

# 保留R下面的資源。

-keep class **.R$* {*;}

# 保留本地native方法不被混淆。

-keepclasseswithmembernames class * {

native <methods>;

}

# 保留在Activity中的方法参数是view的方法,

# 這樣以来我們在layout中寫的onClick就不會被影響。

-keepclassmembers class * extends android.app.Activity{

public void *(android.view.View);

}

# 保留列舉類不被混淆。

-keepclassmembers enum * {

public static **[] values();

public static ** valueOf(java.lang.String);

}

# 保留我们自定义控件(继承自View)不被混淆

-keep public class * extends android.view.View{

*** get*();

void set*(***);

public <init>(android.content.Context);

public <init>(android.content.Context, android.util.AttributeSet);

public <init>(android.content.Context, android.util.AttributeSet, int);

}

-keep public class * {

<methods>;

}

# 保留Parcelable序列化類別不被混淆。

-keep class * implements android.os.Parcelable {

public static final android.os.Parcelable$Creator *;

}

# 保留Serializable序列化的類別不被混淆。

-keepclassmembers class * implements java.io.Serializable {

static final long serialVersionUID;

private static final java.io.ObjectStreamField[] serialPersistentFields;

!static !transient <fields>;

!private <fields>;

!private <methods>;

private void writeObject(java.io.ObjectOutputStream);

private void readObject(java.io.ObjectInputStream);

java.lang.Object writeReplace();

java.lang.Object readResolve();

}

# 對於帶有回調函數的onXXEvent**On*Listener的,不能被混淆。

-keepclassmembers class * {

void *(**On*Event);

void *(**On*Listener);

}

# webView處理,如未使用到webView忽略即可。

-keepclassmembers class fqcn.of.javascript.interface.for.webview {

public *;

}

-keepclassmembers class * extends android.webkit.webViewClient {

public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);

public boolean *(android.webkit.WebView, java.lang.String);

}

-keepclassmembers class * extends android.webkit.webViewClient {

public void *(android.webkit.webView, jav.lang.String);

}

在Gradle那邊打開功能裡面就有bulid Tasks 直接按下bulid 之後,APK在build->outputs->apk->release 裡面是混淆過的,而debug是沒有混淆的版本

附上圖片比較混淆前後的class:

可以看到我這規則除了方法 跟類別名稱 其他屬性都改成abc,這只是簡單的舉例可能還是很容易反編譯,當code量很大時,反編譯難度就會大幅增加。

--

--