1. 程式人生 > >Android混淆之Proguard的語法總結

Android混淆之Proguard的語法總結

前言

首先我們來思考這樣一個問題,為什麼我們需要混淆專案程式碼? 原因很簡單,作為開發者或者企業,你總不會希望自己辛辛苦苦創造出來的東西輕易的被黑客反編譯或破解吧,尤其是現在很多app專案嵌入了支付的功能,如果被發現了程式碼漏洞,後果不堪設想,為了有效預防這個問題,Android中提供了proguard檔案來對專案進行混淆。

proguard的官方介紹

Proguard通過移除沒有用到的程式碼以及通過特定規則重新命名類、變數、方法來壓縮、優化、混淆你的程式碼。這樣做可以讓你的apk更小,更難被逆向分析。由於可以提高被逆向分析的難度,對相關功能安全敏感的應用使用它是十分必要的

proguard的語法介紹

buildTypes {
    debug {
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}

首先Android需要在專案的buildTypes中將minifyEnabled的值設為true proguard-android.txt:SDK中預設proguard的配置規則 proguard-rules.pro:自定義proguard的配置規則

壓縮

壓縮會移除未被使用的類和成員,並且會在優化動作執行之後再次執行

# 關閉壓縮,預設開啟
-dontshrink 

優化

優化會在位元組碼級別上做優化,讓應用執行的更快

# 關閉優化,預設開啟
-dontoptimize
# 表示對程式碼優化的次數,一般為5
-optimizationpasses n
# 指定更精細級別的優化
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*

混淆

混淆會將簡短的無意義的名稱,對類,欄位和方法進行重新命名

# 關閉混淆,預設開啟
-dontobfuscate

預驗證

預驗證將對Java class進行預驗證,Android中沒有預驗證過程

# 關閉預驗證,預設關閉
-dontpreverify

類名

對類名進行keep操作只是將類名keep住,但方法和變數仍然會被混淆

# 一顆星表示keep當前本包下的類名,子包下的類名是會被混淆的
-keep class com.example.ljz.*
# 兩顆星表示keep當前本包下的類名和子包下的類名
-keep class com.example.ljz.**
# 表示keep當前類名
-keep class com.example.ljz.net.NetWorkCache
# 表示keep當前類的內部類的類名
-keep class com.example.ljz.net.NetWorkCache$NetWorkBean

內容

對內容進行keep操作不僅可以將類名keep住,還可以對方法和變數keep住

# 一顆星表示keep當前本包下的類名、類的內容
-keep class com.example.ljz.*{*;}
# 兩顆星表示keep當前本包下的類名、類的內容和子包下的類名、類的內容
-keep class com.example.ljz.**{*;}
# 表示keep當前類名、類的內容
-keep class com.example.ljz.net.NetWorkCache{*;}
# 表示keep當前類的內部類的類名、內部類的內容
-keep class com.example.ljz.net.NetWorkCache$NetWorkBean{*;}

特定內容

對特定的內容進行keep操作

-keep class com.example.ljz.net.NetWorkCache{
    <init>;# 匹配所有構造器
    <fields>;# 匹配所有變數
    <methods>;# 匹配所有方法

    public <methods>;# 匹配所有共有的方法
    private <methods>;# 匹配所有私有的方法
    public *;# 匹配所有共有的內容
    private *;# 匹配所有私有的內容
    public <init>(java.lang.String);# 匹配特定引數的建構函式
    public void getCache(...);# 匹配任意長度型別引數的方法

類成員

對類名不需要keep,只需要對類下的方法進行keep操作

# 表示keep特定類下的特定引數的方法,但類名不會被keep
-keepclassmembernames class com.example.ljz.net.NetWorkCache{
    public void getCache(java.lang.String);
}

注意事項

安卓底層元件和類名不可混淆

將底層的keep住,外掛化才能準確的hook到底層元件

-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.view.View
-keep public class * extends android.preference.Preference

jni方法不可混淆

native方法要完整的包名類名方法來定義,不可修改,否則找不到

-keepclasswithmembernames class *{
    native <methods>;
}
反射用到的類名和方法不可混淆

native方法要完整的包名類名方法來定義,不可修改,否則找不到

-keep public class com.example.ljz.** {
    public void set*(***);
    public *** get*();
    public *** is*();
}
自定義View不可混淆

只要是繼承自系統元件,都要keep住

-keep public class * extend 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 class android.support.** { *; }
-keep class android.support.v4.** { *; }
-keep class android.support.v7.** { *; }
-keep class * extends android.support.v4.**
-keep class * extends android.support.v7.**
-keep class * extends android.support.annotation.**
WebView和Js互調介面不可混淆
-keepclassmembers class ** {
    @android.webkit.JavascriptInterface public *;
}
序列化的類不可混淆
-keepclassmembers class * implements android.os.Parcelable {
    static ** CREATOR;
    <fields>;
    <methods>;
}

-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();
}

enum類的特殊性

以下方法會被髮射呼叫

-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
    public static ** valueOf(int);
}

其他場景
# 指定檔案為對映檔案,包括類和類成員的混淆名稱,檔案未提及的類和類成員將生成新的名稱
-applymapping mapping.txt
# 指定一個文字檔案,其中所有有效字詞都用作混淆欄位和方法名稱
-obfuscationdictionary obfuscationdictionary.txt
# 指定一個文字檔案,其中所有有效詞都用作混淆類名
-classobfuscationdictionary obfuscationdictionary.txt

# 混淆時不生成大小寫混合的類名
-dontusemixedcaseclassnames
# 不忽略指定jars中的非public calsses
-dontskipnonpubliclibraryclasses
# 不忽略指定類庫的public類成員(變數和方法)
-dontskipnonpubliclibraryclassmembers

# 混淆過程中列印詳細資訊,如果異常終止則列印整個堆疊資訊
-verbose
# 忽略警告繼續處理
-ignorewarnings

# 不對指定的類、包中的不完整的引用發出警告
-dontwarn android.support.v4.**
-dontwarn All

# 避免混淆內部類、泛型、匿名類
-keepattributes InnerClasses,Signature,EnclosingMethod
# 丟擲異常時保留程式碼行號    
-keepattributes SourceFile,LineNumberTable
# 保留註釋成員變數,如Activity被@Override註釋的方法onCreate、onDestroy方法
-keepattributes *Annotation*
# 資源類變數需要保留
-keep public class **.R$*{
   public static final int *;
}