Android ProGuard代碼混淆解析

1、代碼混淆配置

如下圖,默認情況下,混淆是關閉的,我們隻需要將minifyEnabled置為true就可以開啟混淆瞭。

這裡寫圖片描述

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

其中:
minifyEnabled表示是否開啟混淆
proguardFiles用於選定混淆配置文件,getDefaultProguardFile(‘proguard-android.txt’) 方法可從 Android SDK tools/proguard/ 文件夾獲取默認的 ProGuard 設置,proguard-rules.pro 文件用於添加自定義 ProGuard 規則。默認情況下,該文件位於模塊根目錄(build.gradle 文件旁)。

需要註意的是,上面加載瞭兩個混淆配置文件,一個是默認的,一個是自定義的,所以這裡告訴我們我們可以同時指定多個混淆配置文件,另外我們還可以分開來寫,如下:

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

為啥進行瞭上述的配置就可以進行代碼的混淆呢?

在$android-sdk-linux/tools/proguard/lib/目錄下面有一個proguard.jar,我們代碼混淆的工作其實就是這個jar完成的。

Linux或者Mac平臺下,在android-sdk-linux/tools/proguard/bin/文件夾中有兩個腳本文件,他們就是運行這個jar文件的腳本,proguard.sh是使用命令行操作的混淆腳本,proguardgui.sh是帶有可視化操作界面的混淆腳本,背後實質運行的都是這個proguard.jar工具。

所以我們如果想單獨對某一個jar文件進行混淆,其實也是可以的,我們直接運行這個工具就可以操作瞭。

2、混淆規則

在Android SDK tools/proguard/ 文件夾下默認有三個文件:

(1)、proguard-android.txt 默認的Proguard配置文件(未優化)
(2)、proguard-android-optimize.txt 默認的Proguard配置文件(已優化)
(3)、proguard-project.txt 默認的用戶定制Proguard配置文件。

下面我們來查看下proguard-android.txt中的默認配置規則

# This is a configuration file for ProGuard.
# http://proguard.sourceforge.net/index.html#manual/usage.html

#表示混淆時不使用大小寫混合類名 
-dontusemixedcaseclassnames
#表示不跳過library中的非public的類
-dontskipnonpubliclibraryclasses
#表示打印混淆的詳細信息
-verbose

# 表示不進行優化
-dontoptimize
表示不進行預校驗
-dontpreverify
# 表示對註解中的參數進行保留
-keepattributes *Annotation*
#表示不混淆類ILicensingService
-keep public class com.google.vending.licensing.ILicensingService
-keep public class com.android.vending.licensing.ILicensingService

#表示不混淆任何包含native方法的類的類名以及native方法名
-keepclasseswithmembernames class * {
    native ;
}

#表示不混淆任何一個View中的setXxx()和getXxx()方法
-keepclassmembers public class * extends android.view.View {
   void set*(***);
   *** get*();
}

# 表示不混淆Activity中參數是View的方法
-keepclassmembers class * extends android.app.Activity {
   public void *(android.view.View);
}

# 表示不混淆枚舉中的values()和valueOf()方法
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

#表示不混淆Parcelable實現類中的CREATOR字段
-keepclassmembers class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator CREATOR;
}

#表示不混淆R文件中的所有靜態字段
-keepclassmembers class **.R$* {
    public static ;
}

#表示對android.support包下的代碼不警告
-dontwarn android.support.**

#不混淆Keep註解類
-keep class android.support.annotation.Keep

#不混淆帶有Keep註解的類
-keep @android.support.annotation.Keep class * {*;}

#不混淆帶有Keep註解的成員方法以及類名
-keepclasseswithmembers class * {
    @android.support.annotation.Keep ;
}

#不混淆帶有Keep註解的成員變量以及類名
-keepclasseswithmembers class * {
    @android.support.annotation.Keep ;
}

#不混淆帶有Keep註解的構造方法以及類名
-keepclasseswithmembers class * {
    @android.support.annotation.Keep (...);
}

上面可以看到,對於Keep註解的類、成員變量、成員方法是不會被混淆的,因此我們可以使用@Keep註解來防止混淆

例如:

//防止混淆類
@Keep
public class Person {}

//防止混淆變量
@Keep
public String name;

//防止混淆方法
@Keep
public int getAge(){}

下面對關鍵詞和通配符進行一個總結

這裡寫圖片描述

這裡寫圖片描述

關於優化的幾個規則

-dontoptimize 
關閉優化項,如果沒有這項默認優化項是開啟的

-optimizations optimization_filter 
根據optimization_filter指定要優化的文件

-optimizationpasses n  
優化數量 n 

-assumenosideeffects class_specification 
在優化階段,ProGuard會將指定的class_specification代碼移除。這裡可以用做Log代碼的移除

-assumenosideeffects class android.util.Log {
    public static *** e(...);
    public static *** d(...);
    public static *** w(...);
    public static *** v(...);
    public static *** i(...);
}



-allowaccessmodification
優化時允許訪問並修改類和類的成員的訪問修飾符,可能作用域會變大。

-mergeinterfacesaggressively
合並接口,即使它們的實現類未實現合並後接口的所有方法。

理解瞭上面優化項之後,我們就可以看看proguard-android-optimize.txt和proguard-android.txt到底有什麼區別,他們的區別其實就是在優化項上,對比下他們裡面的內容,我們發現proguard-android.txt包含下面內容:

# Optimization is turned off by default. Dex does not like code run
# through the ProGuard optimize

-dontoptimize

# Note that if you want to enable optimization, you cannot just
# include optimization flags in your own project configuration file;
# instead you will need to point to the
# "proguard-android-optimize.txt" file instead of this one from your
# project.properties file.

上面註釋翻譯如下:關閉優化功能,不會進行優化,另外,如果你想開啟優化功能,建議使用proguard-android-optimize.txt配置文件

可以看到在proguard-android.txt明確將優化項關閉瞭。

下面來看看proguard-android-optimize.txt文件

# Optimizations: If you don't want to optimize, use the
# proguard-android.txt configuration file instead of this one, which
# turns off the optimization flags.  Adding optimization introduces
# certain risks, since for example not all optimizations performed by
# ProGuard works on all versions of Dalvik.  The following flags turn
# off various optimizations known to have issues, but the list may not
# be complete or up to date. (The "arithmetic" optimization can be
# used if you are only targeting Android 2.0 or later.)  Make sure you
# test thoroughly if you go this route.
-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*
-optimizationpasses 5
-allowaccessmodification

# The remainder of this file is identical to the non-optimized version
# of the Proguard configuration file (except that the other file has
# flags to turn off optimization).

上面註解大致意思為:如果不想進行優化,建議使用proguard-android.txt配置文件,另外,優化會存在風險,不能保證在所有版本的Dalvik上都正常運行。

另外,上面沒有-dontoptimize項,也就是說它默認開啟優化項,並且上面明確指明瞭優化相關的配置信息。

3、混淆結果

每次構建時 ProGuard 都會輸出下列文件:
dump.txt 說明 APK 中所有類文件的內部結構。
mapping.txt 提供原始與混淆過的類、方法和字段名稱之間的轉換。
seeds.txt 列出未進行混淆的類和成員。
usage.txt 列出從 APK 移除的代碼。

這些文件保存在 /build/outputs/mapping/release/中。

4、解出混淆棧

混淆後的類、方法名等等難以閱讀,拿到 crash 的堆棧信息後會發現很難定位,這時需要將混淆反解。

/tools/proguard/bin路徑下有附帶的的反解工具,,Mac 或 Linux 系統為 proguardgui.sh,運行腳本

點擊 ReTrace,選擇該混淆包對應的 mapping 文件(混淆後在 /build/outputs/mapping/release/ 路徑下會生成 mapping.txt 文件,它的作用是提供混淆前後類、方法、類成員等的對照表),再將 crash 的 stack trace 黏貼進輸入框中,點擊右下角的 ReTrace ,混淆後的堆棧信息就顯示出來瞭。
這裡寫圖片描述
以上使用 GUI 程序進行操作,另一種方式是利用該路徑下的 retrace 工具通過命令行進行反解,命令是

retrace.sh [-verbose] mapping.txt []

You May Also Like