Android 混淆簡單入門

xxq2dream發表於2019-02-27

為什麼要進行混淆

混淆是一種安全措施,防止在App釋出以後被人反編譯出來直接看到原始碼。做了混淆處理以後即使反編譯出來一些類名也變成了Class a,Class b之類的,增加了閱讀難度。

混淆以後就一定安全了嘛?

答案顯然是否定的。混淆只是增加了反編譯App的難度和成本,人家還是能看出你用了哪些開源庫,甚至一些業務邏輯。所以,其他的安全措施還是不能少,比如加密與服務端之前的資料請求等

用Android Studio怎麼設定混淆

  • Android Studio已經整合了ProGuard作為混淆優化工具,只需要在gradle簡單設定即可開啟混淆
buildTypes {
    release {
        //開啟混淆
        minifyEnabled true
        //Zipalign優化
        zipAlignEnabled true
        // 移除無用的resource檔案
        shrinkResources true
        //前一部分代表系統預設的android程式的混淆檔案,該檔案已經包含了基本的混淆宣告
        proguardFiles getDefaultProguardFile(`proguard-android.txt`), `proguard-rules.pro`
    }

    debug {
        minifyEnabled false
        zipAlignEnabled true
        shrinkResources false
    }
}
複製程式碼
  • 上面的release版本設定minifyEnabled為true即表示開啟混淆,我們可以在proguard-rules.pro檔案中編輯混淆規則
  • ProGuard有預設的混淆規則,而我們編輯的proguard-rules.pro檔案裡面除了一些ProGuard的設定,比如壓縮等級啊,輸出log啊,更多的是設定哪些東西不被混淆
  • zipAlign可以讓安裝包中的資源按4位元組對齊,這樣可以減少應用在執行時的記憶體消耗。所以打包正式版最好也開啟。

哪些情況需要新增混淆規則

1.新增了一些有混淆規則要求的三方庫

  • 比如圖片載入框架Glide,就需要新增以下規則,這些在官網的ProGuard標籤下可以找到
#Glide
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.AppGlideModule
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
  **[] $VALUES;
  public *;
}
複製程式碼
#okhttp
-dontwarn okhttp3.**
-dontwarn okio.**
-dontwarn javax.annotation.**
複製程式碼
  • 一個比較好的習慣是,每新增一個第三方庫到專案中,就在proguard-rules.pro檔案中新增對應的混淆規則

2.實現Parcelable和Serializable介面的類,比如一些需要持久化的實體類,不能混淆,需要新增混淆規則

  • Parcelable的子類和Creator靜態成員變數不混淆
-keep class * implements Android.os.Parcelable { # 保持Parcelable不被混淆            
    public static final Android.os.Parcelable$Creator *;
}
複製程式碼
  • 實現Serializable介面的類成員不能混淆
#保持所有實現 Serializable 介面的類成員
-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
    public <fields>;
}
複製程式碼

3.與服務端互動,利用Gson、fastjson等框架解析所用的實體資料類不能混淆

-keep class com.myApp.test.bean.** { *; }
複製程式碼

這裡需要解釋一下上面的命令,*表示該包下面的類,**表示該包下面的類和子類,{ *; }表示類裡面的內容。所以上面的命令的意思就是保持com.myApp.test.bean包下面的類和子類不混淆,且類裡面的方法和變數也不混淆

4.jni方法不能混淆

-keepclasseswithmembernames class * { # 保持native方法不被混淆    
    native <methods>;
}
複製程式碼

keepclasseswithmembernames命令的意思是如果擁有某成員,保留類和類成員。以上的命令的意思就是說保留擁有native方法的類和類裡面的native方法不混淆

5.WebView的JS呼叫也需要保證寫的介面方法不混淆

  • JS的介面方法可能是內部類,要保持內部類不被混淆,就需要用到符號$
# 保持MyWebView的內部類MyJavaScriptInterface不被混淆
-keep public class com..xxx.activity.MyWebView$MyJavaScriptInterface

# 保持MyWebView的內部類MyJavaScriptInterface中的所有public內容不被混淆 
-keep public class com..xxx.activity.MyWebView$MyJavaScriptInterface {
    public *;
}
複製程式碼

6.enum型別的2個特殊方法不能被混淆

-keepclassmembers enum  * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}
複製程式碼

7.反射用的類不能被混淆


ProGuard常用的一些設定選項

#指定壓縮級別
-optimizationpasses 5
複製程式碼
#不跳過非公共的庫的類成員
-dontskipnonpubliclibraryclassmembers
複製程式碼
#輸出詳細日誌
-verbose
複製程式碼
#保留一些屬性,如行號LineNumberTable
-keepattributes LineNumberTable
複製程式碼
#優化時允許訪問並修改有修飾符的類和類的成員
-allowaccessmodification
複製程式碼
#忽略警告,一般有警告會編譯失敗,如果是一些無關緊要的警告可以忽略從而順利打包,否則要修復那些有問題的地方,以免App不能正常使用
-ignorewarnings
複製程式碼
#混淆時採用的演算法
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
複製程式碼
#優化時允許訪問並修改有修飾符的類和類的成員
-allowaccessmodification
複製程式碼

其他的一些設定及資訊,可以參考官網—ProGuard


今天你進步了嘛?歡迎關注我的微信公眾號,和我一起每天進步一點點!

AntDream