作者:wuchao2877更新於 07月19日訪問(727)評論(0)
什麼是代碼混淆
Java 是一種跨平臺的、解釋型語言,Java 源代碼編譯成中間”字節碼”存儲於 class 文件中。由於跨平臺的需要,Java 字節碼中包括了很多源代碼信息,如變量名、方法名,並且通過這些名稱來訪問變量和方法,這些符號帶有許多語義信息,很容易被反編譯成 Java 源代碼。爲了防止這種現象,我們可以使用 Java 混淆器對 Java 字節碼進行混淆。
混淆就是對發佈出去的程序進行重新組織和處理,使得處理後的代碼與處理前代碼完成相同的功能,而混淆後的代碼很難被反編譯,即使反編譯成功也很難得出程序的真正語義。被混淆過的程序代碼,仍然遵照原來的檔案格式和指令集,執行結果也與混淆前一樣,只是混淆器將代碼中的所有變量、函數、類的名稱變爲簡短的英文字母代號,在缺乏相應的函數名和程序註釋的況下,即使被反編譯,也將難以閱讀。同時混淆是不可逆的,在混淆的過程中一些不影響正常運行的信息將永久丟失,這些信息的丟失使程序變得更加難以理解。
混淆器的作用不僅僅是保護代碼,它也有精簡編譯後程序大小的作用。由於以上介紹的縮短變量和函數名以及丟失部分信息的原因, 編譯後 jar 文件體積大約能減少25% ,這對當前費用較貴的無線網絡傳輸是有一定意義的。
混淆文件 proguard.cfg 參數詳解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
-optimizationpasses 5 # 指定代碼的壓縮級別
-dontusemixedcaseclassnames # 是否使用大小寫混合
-dontskipnonpubliclibraryclasses # 是否混淆第三方jar
-dontpreverify # 混淆時是否做預校驗
-verbose # 混淆時是否記錄日誌
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/* # 混淆時所採用的算法
-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.app.backup.BackupAgentHelper # 保持哪些類不被混淆
-keep public class * extends android.preference.Preference # 保持哪些類不被混淆
-keep public class com.android.vending.licensing.ILicensingService # 保持哪些類不被混淆
-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; # 保持自己定義的類不被混淆
複製代碼
|
代碼混淆的方法
根據 SDK 的版本不同有 2 中不同的代碼混淆方式,以上的 proguard.cfg 參數詳解中所涉及到的信息是在較低版本 SDK 下的混淆腳本,事實上在高版本的 SDK 下混淆的原理和參數也與低版本的相差無幾,只是在不同 SDK 版本的環境下引入混淆腳本的方式有所不同。具體方法如下:
低版本 SDK 下,項目中同時包含 proguard.cfg 和 project.properties 文件,則只需在 project.properties 文件末尾添加 proguard.config=proguard.cfg 再將項目 Export 即可。
高版本 SDK 下,項目中同時包含 proguard-project.txt 和 project.properties 文件,這時需要在 proguard-project.txt 文件中進行如下信息的配置,然後再將項目 Export 即可。下面以真實的文件進行演示說明。
複製代碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# To enable ProGuard in your project, edit project.properties
# to define the proguard.config property as described in that file.
#
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in ${sdk.dir}/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the ProGuard
# include property in project.properties.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
sdk.dir=D:/Android-SDK/android-sdk
proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
|
複製代碼
以上的配置信息即是 proguard-project.txt 文件中內容,藍色文字爲我們在代碼混淆過程中需要添加的配置信息,其中:sdk.dir 爲你在當前機器上 SDK 的安裝路徑,第二句配置的意思實際上是將 SDK 中代碼混淆配置文件 proguard-android.txt (感興趣的朋友可以將這個文件和上面的 proguard.cfg 文件進行對比)映射到 proguard-project.txt 作爲 proguard.config 混淆設置。