1. 程式人生 > >Android APP程式碼混淆proguard和加固

Android APP程式碼混淆proguard和加固

    proguard官方網址:http://proguard.sourceforge.net/index.html#/manual/examples.html

 一、在gradle中開啟:

Gradle專案(以及Android Studio)

在build.gradle中進行配置

android {
    buildTypes {
        release {  

           minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro'
            //proguardFile 'some-other-rules.txt'  配置單個檔案這樣
        }
    }
}

如上面程式碼所示,我們可以使用rminifyEnabled true開啟,並且對其配置混淆配置,可以配置多個檔案或單個檔案。

android的sdk中已經為我們提供了兩個預設的配置檔案,我們可以拿過來進行使用,proguard-android.txt和proguard-android-optimize.txt。

二、proguard主要三部分功能

   縮減程式碼、優化程式碼、混淆程式碼。三部分功能都可以在配置檔案裡配置不啟用此功能(其實還有預校驗的功能不過android官方不建議開啟)。

#Shrink Options

#不縮減程式碼
-dontshrink

#Optimization Options

#不優化程式碼
-dontoptimize

#Obfuscate Options 
#-不混淆輸入的類檔案 
-dontobfuscate 

三、用法

1.保留選項(配置不進行處理的內容)

-keep {Modifier} {class_specification} 保護指定的類檔案和類的成員
-keepclassmembers {modifier} {class_specification} 保護指定類的成員(類的屬性),如果此類名受到保護他們會保護的更好
-keepclasseswithmembers {class_specification} 保護指定的類和類的成員。
-keepnames {class_specification} 保護指定的類和類的成員的名稱(如果他們不會壓縮步驟中刪除)
-keepclassmembernames {class_specification} 保護指定的類的成員的名稱(如果他們沒在壓縮步驟中刪除)
-keepclasseswithmembernames {class_specification} 保護指定的類和類的成員的名稱,如果所有指定的類成員出席(在壓縮步驟之後)
-printseeds {filename} 列出類和類的成員-keep選項的清單,標準輸出到給定的檔案

-keep用法區別

1)保留某個類名不被混淆

-keep public classcom.ebt.app.common.bean.Customer

2)保留類及其所有成員不被混淆

-keep public classcom.ebt.app.common.bean.Customer { *;}

或者
-keepclasseswithmembers class com.ebt.app.common.bean.Customer {

    <init>;#匹配所有建構函式

    <fields>;#匹配所有成員
    <methods>;#匹配所有方法
}

3)只保留類名及其部分成員不被混淆

-keep public classcom.ebt.app.common.bean.Customer { 

    static final<fields>;

    private void get*();

}

4)#保留包路徑下所有的類及其屬性和方法
-keep class com.ebt.app.sync.** { *;}

2.壓縮

-dontshrink 不壓縮輸入的類檔案
-printusage {filename}
-whyareyoukeeping {class_specification}

3.優化

-dontoptimize 不優化輸入的類檔案
-assumenosideeffects {class_specification} 優化時假設指定的方法,沒有任何副作用
-allowaccessmodification 優化時允許訪問並修改有修飾符的類和類的成員

4.混淆

-dontobfuscate 不混淆輸入的類檔案
-obfuscationdictionary {filename} 使用給定檔案中的關鍵字作為要混淆方法的名稱
-overloadaggressively 混淆時應用侵入式過載
-useuniqueclassmembernames 確定統一的混淆類的成員名稱來增加混淆
-flattenpackagehierarchy {package_name} 重新包裝所有重新命名的包並放在給定的單一包中
-repackageclass {package_name} 重新包裝所有重新命名的類檔案中放在給定的單一包中
-dontusemixedcaseclassnames 混淆時不會產生形形色色的類名
-keepattributes {attribute_name,...} 保護給定的可選屬性,例如LineNumberTable,LocalVariableTable, SourceFile, Deprecated, Synthetic, Signature, andInnerClasses.
-renamesourcefileattribute {string} 設定原始檔中給定的字串常量

後面的檔名,類名,或者包名等可以使用佔位符代替
?表示一個字元
可以匹配多個字元,但是如果是一個類,不會匹配其前面的包名
* 可以匹配多個字元,會匹配前面的包名。

在android中在android Manifest檔案中的activity,service,provider, receviter,等都不能進行混淆。一些在xml中配置的view也不能進行混淆,android提供的預設配置中都有。

5..預設情況下,proguard 會混淆所有程式碼,但是下面幾種情況不能改變類名和方法名。
a.我們用到反射的地方。

b.我們程式碼依賴於系統的介面,比如被系統程式碼呼叫的回撥方法,這種情況最複雜。
c.在配置檔案manifest中配置的。

6.對出現問題的類的處理。遇見一個及新增。

7.常見*的用法區別(一般情況下用不到,非必須瞭解)

修飾類、介面、列舉等時

*       matchesany part of a class name not containing the package separator. For example,"mypackage.*Test*" matches "mypackage.Test" and"mypackage.YourTestApplication", but not"mypackage.mysubpackage.MyTest". Or, more generally, "mypackage.*"matches all classes in "mypackage", but not in its subpackages.

**     matchesany part of a class name, possibly containing any number of package separators.For example, "**.Test" matches all Test classes in all packagesexcept the root package. Or, "mypackage.**" matches all classes in"mypackage" and in its subpackages.

   修飾建構函式、成員變數、方法

Fields and methods are specified much likein Java, except that method argument lists don't contain argument names (justlike in other tools like javadoc and javap). The specifications can alsocontain the following catch-all wildcards:

<init>        matches any constructor.

<fields>    matches any field.

<methods>       matches any method.

*       matchesany field or method.

Note that the above wildcards don't havereturn types. Only the <init> wildcard has an argument list.

Fields and methods may also be specifiedusing regular expressions. Names can contain the following wildcards:

?       matchesany single character in a method name.

*       matchesany part of a method name.

Types in descriptors can contain thefollowing wildcards:

%      matchesany primitive type ("boolean", "int", etc, but not"void").

?       matchesany single character in a class name.

*       matchesany part of a class name not containing the package separator.

**     matchesany part of a class name, possibly containing any number of package separators.

***  matchesany type (primitive or non-primitive, array or non-array).

...     matchesany number of arguments of any type.

Note that the ?, *, and ** wildcards willnever match primitive types. Furthermore, only the *** wildcards will matcharray types of any dimension. For example, "** get*()" matches"java.lang.Object getObject()", but not "float getFloat()",nor "java.lang.Object[] getObjects()".

Constructors can also be specified usingtheir short class names (without package) or using their full class names. Asin the Java language, the constructor specification has an argument list, butno return type.

The class access modifiers and class memberaccess modifiers are typically used to restrict wildcarded classes and classmembers. They specify that the corresponding access flags have to be set forthe member to match. A preceding ! specifies that the corresponding access flagshould be unset.

Combining multiple flags is allowed (e.g.public static). It means that both access flags have to be set (e.g. public andstatic), except when they are conflicting, in which case at least one of themhas to be set (e.g. at least public or protected).

ProGuard supports the additional modifierssynthetic, bridge, and varargs, which may be set by compilers.

四、Proguard的輸出檔案及reTrace跟蹤

 混淆之後,會給我們輸出一些檔案,在gradle方式下是在<project_dir>/build/proguard/目錄下,ant是在<project_dir>/bin/proguard目錄,eclipse構建在<project_dir>/proguard目錄像。
分別有以下檔案:
+ dump.txt 描述apk檔案中所有類檔案間的內部結構。
+ mapping.txt 列出了原始的類,方法,和欄位名與混淆後代碼之間的對映。
+ seeds.txt 列出了未被混淆的類和成員
+ usage.txt 列出了從apk中刪除的程式碼

當我們釋出的release版本的程式出現bug時,可以通過以上檔案(特別時mapping.txt)檔案找到錯誤原始的位置,進行bug修改。同時,可能一開始的proguard配置有錯誤,也可以通過錯誤日誌,根據這些檔案,找到哪些檔案不應該混淆,從而修改proguard的配置。

    注意:重新release編譯後,這些檔案會被覆蓋,所以沒吃釋出程式,最好都儲存一份配置檔案。

除錯Proguard混淆後的程式

上面說了輸出的幾個檔案,我們在改bug時可以使用,通過mapping.txt,通過對映關係找到對應的類,方法,欄位等。

ProGuard 提供了命令列和 GUI 工具來還原混淆後的程式碼,可以將一個被混淆過的堆疊跟蹤資訊還原成一個可讀的資訊。
該工具位於  <android-sdk>/tools/proguard/bin/ 目錄下。
裡面的 proguardgui.bat 為 GUI 工具,

1) 執行 proguardgui.bat
2) 從左邊的選單選擇  “ReTrace”
3) 在上面的 mapping 檔案中選擇你的 mapping 檔案 ,在下面輸入框輸入要還原的程式碼
4) 點選 “ReTrace!” 按鈕

命令列:window下時retrace.bat,linux和mac是retrace.sh,在<sdk_root>/tools/proguard/資料夾下。語法為:

    retrace.bat|retrace.sh [-verbose] mapping.txt [<stacktrace_file>]

例如:

retrace.bat -verbose mapping.txt obfuscated_trace.txt

如果你沒有指定<stacktrace_file>,retrace工具會從標準輸入讀取。

五、其他關於Proguard的問題

1.開啟optimization導致的問題。有時候為了在release版本中去除log列印,配置
-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(...);
}
此時必須開啟優化,但是這樣可能會引入更大的問題:http://www.itnose.net/detail/6043297.html而在我的專案中則打包都成功不了,提示說Tencent微博SDK引用的httpclient出問題,找不到父類。結論是:要是你不是proguard高手,就關閉優化吧。
2proguarnd後反編譯程式碼,使用一些工具還能看到真身的影子,如:http://www.tuicool.com/articles/vUB3EnM
-keepattributes SourceFile,LineNumberTable
表示的是java檔案的各種檔案屬性,如果這個被keep了,果斷去掉。
3.中文的各個引數的解釋,準確性本人不能把握http://www.2cto.com/kf/201604/497739.html

六、美團Android資源混淆保護實踐

七、第三方加固

大家請百度