Android混淆(Proguard)詳解

目錄:

一、混淆的做用及好處
二、混淆的原理
三、混淆的具體使用
--- 3.一、混淆的基本語法
--- 3.二、去除日誌信息
四、更詳細的語法及demojava

一、混淆的做用及好處

混淆屬於整個應用程序開發生命週期偏後期階段的技術了,因此要考慮應用的安全性及性能的問題,混淆就是爲了這種需求產生的一種技術,簡單說,混淆就是將關鍵字和關鍵類名,修改成無心義的字符以起到迷惑試圖反編譯去查看源碼的人。在必定程度上能過濾掉起碼95%以上的反編譯者,混淆是保障Android程序源碼安全的第一道門檻,這是個人我的理解。
以上談了下混淆的做用,而混淆的好處除了能保證源碼安全性以外就大概是經過修改關鍵字爲無心義字符串,或者剔除某些輔助類,好比Log,從而減小文件大小。android

二、混淆的原理

以上混淆均指的是Proguard,Proguard是混淆代碼的一個開源項目(proguard官網)算法

Java 是一種跨平臺的、解釋型語言,Java 源代碼編譯成中間」字節碼」存儲於 class 文件中。因爲跨平臺的須要,Java 字節碼中包括了不少源代碼信息,如變量名、方法名,而且經過這些名稱來訪問變量和方法,這些符號帶有許多語義信息,很容易被反編譯成 Java 源代碼。爲了防止這種現象,咱們可使用 Java 混淆器對 Java 字節碼進行混淆。
混淆就是對發佈出去的程序進行從新組織和處理,使得處理後的代碼與處理前代碼完成相同的功能,而混淆後的代碼很難被反編譯,即便反編譯成功也很可貴出程序的真正語義。被混淆過的程序代碼,仍然遵守原來的檔案格式和指令集,執行結果也與混淆前同樣,只是混淆器將代碼中的全部變量、函數、類的名稱變爲簡短的英文字母代號,在缺少相應的函數名和程序註釋的況下,即便被反編譯,也將難以閱讀。同時混淆是不可逆的,在混淆的過程當中一些不影響正常運行的信息將永久丟失,這些信息的丟失使程序變得更加難以理解。
混淆器的做用不只僅是保護代碼,它也有精簡編譯後程序大小的做用。因爲以上介紹的縮短變量和函數名以及丟失部分信息的緣由, 編譯後 jar 文件體積大約能減小25%,這對當前費用較貴的無線網絡傳輸是有必定意義的。sql

反編譯以後獲得的類名

三、混淆的具體使用

3.一、模塊(Module)下的build.gradle的配置
android{
  buildTypes{
    release { 
       // 是否進行混淆 
       minifyEnabled false  
       // 混淆文件的位置,其中'proguard-android.txt'爲sdk默認的混淆配置,
       //'proguard-rules.pro' 是該模塊下的混淆配置
       proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'  
    } 
  }
}
複製代碼

以上是proguard在模塊下build.gradle文件中的配置信息,其中proguard-android.txt爲sdk默認的混淆配置,proguard-rules.pro是在默認配置的基礎上針對本模塊作出的針對性混淆處理。安全

  • 注:proguard-android.txt的位置位於android-sdk/tools/proguard/proguard-android.txt
3.一、混淆的基本語法

這個語法的做用是定義出不須要混淆的源代碼,那麼編譯時會自動將未定義的部分全都混淆。至於爲何要保留類名或方法名,主要有三個緣由:網絡

  • 讓C/C++程序能夠經過jni使用對應的java方法。
  • 四大組件在AndroidManifest.xml裏面註冊了,因此要保留。
  • R文件混淆會致使引用錯誤。

一、保留類名 二、保留方法名 三、保留類名和方法名app

#保留位於View類中的get和set方法
-keepclassmembers public class * extends android.view.View{
    void set*(***);
    *** get*();
}
#保留在Activity中以View爲參數的方法不變
-keepclassmembers class * extends android.app.Activity{
    public void *(android.view.View);
}
#保留實現了Parcelable的類名不變,
-keep class * implements android.os.Parcelable{ 
    public static final android.os.Parcelable$Creator *;
}
 #保留R$*類中靜態成員的變量名
-keepclassmembers class **.R$*{
    public static <fields>;
}
複製代碼
3.2 去除日誌信息

經過配置proguard,將android.util.Log置爲無效代碼,則能夠去除apk中打印日誌的代碼。 一、將build.gradle添加'proguard-android-optimize.txt'文件,該文件中默認打開了優化開關。ide

android{
  buildTypes{
    release { 
       // 是否進行混淆 
       minifyEnabled false  
       // 混淆文件的位置,其中'proguard-android-optimize.txt'爲sdk默認的混淆配置,
       //'proguard-rules.pro' 是該模塊下的混淆配置
       proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'  
    } 
  }
}
複製代碼

二、配置語法函數

-assumenosideeffects class android.util.Log{
   public static boolean isLoggable(java.lang.String,int);
   public static int v(...);
   public static int i(...);
   public static int w(...);
   public static int d(...);
   public static int e(...);
}
-assumenosideeffects class com.example.Log.Logger{
   public static int v(...);
   public static int i(...);
   public static int w(...);
   public static int d(...);
   public static int e(...);
}
複製代碼

四、更詳細的語法

-include {filename}    從給定的文件中讀取配置參數   
-basedirectory {directoryname}    指定基礎目錄爲之後相對的檔案名稱   
-injars {class_path}    指定要處理的應用程序jar,war,ear和目錄   
-outjars {class_path}    指定處理完後要輸出的jar,war,ear和目錄的名稱   
-libraryjars {classpath}    指定要處理的應用程序jar,war,ear和目錄所須要的程序庫文件   
-dontskipnonpubliclibraryclasses    指定不去忽略非公共的庫類。   
-dontskipnonpubliclibraryclassmembers    指定不去忽略包可見的庫類的成員。  
  
保留選項   
-keep {Modifier} {class_specification}    保護指定的類文件和類的成員   
-keepclassmembers {modifier} {class_specification}    保護指定類的成員,若是此類受到保護他們會保護的更好  
-keepclasseswithmembers {class_specification}    保護指定的類和類的成員,但條件是全部指定的類和類成員是要存在。   
-keepnames {class_specification}    保護指定的類和類的成員的名稱(若是他們不會壓縮步驟中刪除)   
-keepclassmembernames {class_specification}    保護指定的類的成員的名稱(若是他們不會壓縮步驟中刪除)   
-keepclasseswithmembernames {class_specification}    保護指定的類和類的成員的名稱,若是全部指定的類成員出席(在壓縮步驟以後)   
-printseeds {filename}    列出類和類的成員-keep選項的清單,標準輸出到給定的文件   
  
壓縮   
-dontshrink    不壓縮輸入的類文件   
-printusage {filename}   
-whyareyoukeeping {class_specification}       
  
優化   
-dontoptimize    不優化輸入的類文件   
-assumenosideeffects {class_specification}    優化時假設指定的方法,沒有任何反作用   
-allowaccessmodification    優化時容許訪問並修改有修飾符的類和類的成員   
  
混淆   
-dontobfuscate    不混淆輸入的類文件   
-printmapping {filename}   
-applymapping {filename}    重用映射增長混淆   
-obfuscationdictionary {filename}    使用給定文件中的關鍵字做爲要混淆方法的名稱   
-overloadaggressively    混淆時應用侵入式重載   
-useuniqueclassmembernames    肯定統一的混淆類的成員名稱來增長混淆   
-flattenpackagehierarchy {package_name}    從新包裝全部重命名的包並放在給定的單一包中   
-repackageclass {package_name}    從新包裝全部重命名的類文件中放在給定的單一包中   
-dontusemixedcaseclassnames    混淆時不會產生形形色色的類名   
-keepattributes {attribute_name,...}    保護給定的可選屬性,例如LineNumberTable, LocalVariableTable, SourceFile, Deprecated, Synthetic, Signature, and   
  
InnerClasses.   
-renamesourcefileattribute {string}    設置源文件中給定的字符串常量  
複製代碼

demo性能

-ignorewarnings                     # 忽略警告,避免打包時某些警告出現  
-optimizationpasses 5               # 指定代碼的壓縮級別  
-dontusemixedcaseclassnames         # 是否使用大小寫混合  
-dontskipnonpubliclibraryclasses    # 是否混淆第三方jar  
-dontpreverify                      # 混淆時是否作預校驗  
-verbose                            # 混淆時是否記錄日誌  
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*        # 混淆時所採用的算法  
  
-libraryjars   libs/treecore.jar  
  
-dontwarn android.support.v4.**     #缺省proguard 會檢查每個引用是否正確,可是第三方庫裏面每每有些不會用到的類,沒有正確引用。若是不配置的話,系統就會報錯。  
-dontwarn android.os.**  
-keep class android.support.v4.** { *; }        # 保持哪些類不被混淆  
-keep class com.baidu.** { *; }    
-keep class vi.com.gdi.bgl.android.**{*;}  
-keep class android.os.**{*;}  
  
-keep interface android.support.v4.app.** { *; }    
-keep public class * extends android.support.v4.**    
-keep public class * extends android.app.Fragment  
  
-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.BroadcastReceiver  
-keep public class * extends android.content.ContentProvider  
-keep public class * extends android.support.v4.widget  
-keep public class * extends com.sqlcrypt.database  
-keep public class * extends com.sqlcrypt.database.sqlite  
-keep public class * extends com.treecore.**  
-keep public class * extends de.greenrobot.dao.**  
  
  
-keepclasseswithmembernames class * {       # 保持 native 方法不被混淆  
    native <methods>;  
}  
  
-keepclasseswithmembers class * {            # 保持自定義控件類不被混淆  
    public <init>(android.content.Context, android.util.AttributeSet);  
}  
  
-keepclasseswithmembers class * {            # 保持自定義控件類不被混淆  
    public <init>(android.content.Context, android.util.AttributeSet, int);  
}  
  
-keepclassmembers class * extends android.app.Activity { //保持類成員  
   public void *(android.view.View);  
}  
  
-keepclassmembers enum * {                  # 保持枚舉 enum 類不被混淆  
    public static **[] values();  
    public static ** valueOf(java.lang.String);  
}  
  
-keep class * implements android.os.Parcelable {    # 保持 Parcelable 不被混淆  
  public static final android.os.Parcelable$Creator *;  
}  
  
-keep class MyClass;                              # 保持本身定義的類不被混淆  
複製代碼

參考

一、MOOC-Android代碼混淆與加固技術
二、CSDN-Android proguard 詳解
三、簡書-ProGuard 最全混淆規則說明

相關文章
相關標籤/搜索