android安全——混淆技術小摘

轉載請標明出處:
http://blog.csdn.net/sinat_15877283/article/details/50960690
本文出自: 【溫利東的博客】

本篇文章中介紹的混淆技術都是基於Android Studio的,Eclipse的用法也基本類似,但是就不再爲Eclipse專門做講解了。

混淆APK

在Android Studio當中混淆APK實在是太簡單了,藉助SDK中自帶的Proguard工具,只需要修改build.gradle中的一行配置即可。可以看到,現在build.gradle中minifyEnabled的值是false,這裏我們只需要把值改成true,打出來的APK包就會是混淆過的了。如下所示:

release {
    minifyEnabled true  //是否啓用混淆
    proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'    //用於選定混淆配置文件
}

其中minifyEnabled用於設置是否啓用混淆,proguardFiles用於選定混淆配置文件。注意這裏是在release閉包內進行配置的,因此只有打出正式版的APK纔會進行混淆,Debug版的APK是不會混淆的。

混淆規則

默認混淆配置

其實就是剛纔在build.gradle的release閉包下配置的proguard-android.txt文件,這個文件存放於< Android SDK>/tools/proguard目錄下,我們打開來看一下:

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

-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-verbose

# Optimization is turned off by default. Dex does not like code run
# through the ProGuard optimize and preverify steps (and performs some
# of these optimizations on its own).
-dontoptimize
-dontpreverify
# 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.

-keepattributes *Annotation*
-keep public class com.google.vending.licensing.ILicensingService
-keep public class com.android.vending.licensing.ILicensingService

# For native methods, see http://proguard.sourceforge.net/manual/examples.html#native
-keepclasseswithmembernames class * {
    native <methods>;
}

# keep setters in Views so that animations can still work.
# see http://proguard.sourceforge.net/manual/examples.html#beans
-keepclassmembers public class * extends android.view.View {
   void set*(***);
   *** get*();
}

# We want to keep methods in Activity that could be used in the XML attribute onClick
-keepclassmembers class * extends android.app.Activity {
   public void *(android.view.View);
}

# For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

-keepclassmembers class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator CREATOR;
}

-keepclassmembers class **.R$* {
    public static <fields>;
}

# The support library contains references to newer platform versions.
# Dont warn about those in case this app is linking against an older
# platform version.  We know about them, and they are safe.
-dontwarn android.support.**

這個就是默認的混淆配置文件了,我們來一起逐行閱讀一下。

*-dontusemixedcaseclassnames* 表示混淆時不使用大小寫混合類名。
*-dontskipnonpubliclibraryclasses* 表示不跳過library中的非public的類。
*-verbose* 表示打印混淆的詳細信息。
*-dontoptimize* 表示不進行優化,建議使用此選項,因爲根據proguard-android-optimize.txt中的描述,優化可能會造成一些潛在風險,不能保證在所有版本的Dalvik上都正常運行。
*-dontpreverify* 表示不進行預校驗。這個預校驗是作用在Java平臺上的,Android平臺上不需要這項功能,去掉之後還可以加快混淆速度。
*-keepattributes *Annotation** 表示對註解中的參數進行保留。

-keep public class com.google.vending.licensing.ILicensingService
-keep public class com.android.vending.licensing.ILicensingService

表示不混淆上述聲明的兩個類,這兩個類我們基本也用不上,是接入Google原生的一些服務時使用的。

-keepclasseswithmembernames class * {
    native <methods>;
}

表示不混淆任何包含native方法的類的類名以及native方法名。

-keepclassmembers public class * extends android.view.View {
   void set*(***);
   *** get*();
}

表示不混淆任何一個View中的setXxx()和getXxx()方法,因爲屬性動畫需要有相應的setter和getter的方法實現,混淆了就無法工作了。

-keepclassmembers class * extends android.app.Activity {
   public void *(android.view.View);
}

表示不混淆Activity中參數是View的方法,因爲有這樣一種用法,在XML中配置android:onClick=”buttonClick”屬性,當用戶點擊該按鈕時就會調用Activity中的buttonClick(View view)方法,如果這個方法被混淆的話就找不到了。

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

表示不混淆枚舉中的values()和valueOf()方法,枚舉我用的非常少,這個就不評論了。

-keepclassmembers class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator CREATOR;
}

表示不混淆Parcelable實現類中的CREATOR字段,毫無疑問,CREATOR字段是絕對不能改變的,包括大小寫都不能變,不然整個Parcelable工作機制都會失敗。

-keepclassmembers class **.R$* {
    public static <fields>;
}

表示不混淆R文件中的所有靜態字段,我們都知道R文件是通過字段來記錄每個資源的id的,字段名要是被混淆了,id也就找不着了。
*-dontwarn android.support.*** 表示對android.support包下的代碼不警告,因爲support包中有很多代碼都是在高版本中使用的,如果我們的項目指定的版本比較低在打包時就會給予警告。不過support包中所有的代碼都在版本兼容性上做足了判斷,因此不用擔心代碼會出問題,所以直接忽略警告就可以了。

好了,這就是proguard-android.txt文件中所有默認的配置,而我們混淆代碼也是按照這些配置的規則來進行混淆的。經過我上面的講解之後,相信大家對這些配置的內容基本都能理解了。不過proguard語法中還真有幾處非常難理解的地方,我自己也是研究了好久才搞明白,下面和大家分享一下這些難懂的語法部分。

混淆規則定義

proguard中一共有三組六個keep關鍵字,很多人搞不清楚它們的區別,這裏我們通過一個表格來直觀地看下:

關鍵字 描述
keep 保留類和類中的成員,防止它們被混淆或移除。
keepnames 保留類和類中的成員,防止它們被混淆,但當成員沒有被引用時會被移除。
keepclassmembers 只保留類中的成員,防止它們被混淆或移除。
keepclassmembernames 只保留類中的成員,防止它們被混淆,但當成員沒有被引用時會被移除。
keepclasseswithmembers 保留類和類中的成員,防止它們被混淆或移除,前提是指名的類中的成員必須存在,如果不存在則還是會混淆。
keepclasseswithmembernames 保留類和類中的成員,防止它們被混淆,但當成員沒有被引用時會被移除,前提是指名的類中的成員必須存在,如果不存在則還是會混淆。

除此之外,proguard中的通配符也比較讓人難懂,proguard-android.txt中就使用到了很多通配符,我們來看一下它們之間的區別:

通配符 描述
< field > 匹配類中的所有字段
< method> 匹配類中的所有方法
< init> 匹配類中的所有構造函數
* 匹配任意長度字符,但不含包名分隔符(.)。比如說我們的完整類名是com.example.test.MyActivity,使用com.,或者com.exmaple.* 都是無法匹配的,因爲* 無法匹配包名中的分隔符,正確的匹配方式是com.exmaple.* .* ,或者com.exmaple.test.* ,這些都是可以的。但如果你不寫任何其它內容,只有一個*,那就表示匹配所有的東西。
** 匹配任意長度字符,並且包含包名分隔符(.)。比如proguard-android.txt中使用的-dontwarn android.support.**就可以匹配android.support包下的所有內容,包括任意長度的子包。
.* ** 匹配任意參數類型。比如void set*(* * * )就能匹配任意傳入的參數類型,* * * get*()就能匹配任意返回值的類型。
匹配任意長度的任意類型參數。比如void test(…)就能匹配任意void test(String a)或者是void test(int a, String b)這些方法。

雖說上面表格已經解釋的很詳細了,但是很多人對於keep和keepclasseswithmembers這兩個關鍵字的區別還是搞不懂。確實,它們之間用法有點太像了,我做了很多次試驗它們的結果都是相同的。其實唯一的區別就在於類中聲明的成員存不存在,我們還是通過一個例子來直接地看一下,先看keepclasseswithmember關鍵字:

-keepclasseswithmember class * {
    native <methods>;
}

這段代碼的意思其實很明顯,就是保留所有含有native方法的類的類名和native方法名,而如果某個類中沒有含有native方法,那就還是會被混淆。
但是如果改成keep關鍵字,結果會完全不一樣:

-keep class * {
    native <methods>;
}

使用keep關鍵字後,你會發現代碼中所有類的類名都不會被混淆了,因爲keep關鍵字看到class *就認爲應該將所有類名進行保留,而不會關心該類中是否含有native方法。當然這樣寫只會保證類名不會被混淆,類中的成員還是會被混淆的。
比較難懂的用法大概就這些吧,掌握了這些內容之後我們就能繼續前進了。

混淆的規則都是按照proguard-android.txt中默認的規則來的,當然我們也可以修改proguard-android.txt中的規則,但是直接在proguard-android.txt中修改會對我們本機上所有項目的混淆規則都生效,那麼有沒有什麼辦法只針對當前項目的混淆規則做修改呢?當然是有辦法的了,你會發現任何一個Android Studio項目在app模塊目錄下都有一個proguard-rules.pro文件,這個文件就是用於讓我們編寫只適用於當前項目的混淆規則的。

提示:

  • proguard-rules.pro文件名可以任意,只要在配置文件中指明即可。比如,從其它項目中複製一個proguard.cfg混淆規則文件,只需將上面的代碼改成
    proguardFiles getDefaultProguardFile('proguard-android.txt'),
    'proguard.cfg'
    即可,這句話表示使用項目中根目錄下的proguard.cfg文件作爲本項目的混淆規則文件。
  • 打包項目注意記得在Build Type:選項下選擇release,否則只打包不會混淆。如下圖:
    這裏寫圖片描述

推薦:《Android代碼混淆技巧》Android安全攻防戰,反編譯與混淆技術完全解析Proguard簡要語法手冊
https://segmentfault.com/a/1190000004461614

發佈了38 篇原創文章 · 獲贊 9 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章