Android混淆

代碼混淆(Obfuscated code)亦稱花指令,是將計(jì)算機(jī)程序的代碼,轉(zhuǎn)換成一種功能上等價,但是難于閱讀和理解的形式的行為。

為什么要加代碼混淆
--------------------不想開源應(yīng)用,為了加大反編譯的成本,但是并不能徹底防止反編譯

開啟混淆

  • 通常我們需要找到項(xiàng)目路徑下app目錄下的build.gradle文件
  • 找到minifyEnabled這個配置,然后設(shè)置為true即可.

如下:

 release{
            minifyEnabled true//是否啟動混淆 ture:打開   false:關(guān)閉
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }

proguard-rules.pro文件的作用

  • 只要在工程應(yīng)用目錄的gradle文件中設(shè)置minifyEnabled:true即可。然后我們就可以到proguard-rules.pro文件中加入我們的混淆規(guī)則了

proguard是什么

  • Proguard是一個集文件壓縮,優(yōu)化,混淆和校驗(yàn)等功能的工具
  • 它檢測并刪除無用的類,變量,方法和屬性
  • 它優(yōu)化字節(jié)碼并刪除無用的指令.
  • 它通過將類名,變量名和方法名重命名為無意義的名稱實(shí)現(xiàn)混淆效果.
  • 最后它還校驗(yàn)處理后的代碼

混淆的常見配置

  • Proguard關(guān)鍵字
Proguard關(guān)鍵字 描述
dontwarn dontwarn是一個和keep可以說是形影不離,尤其是處理引入的library時.
keep 保留類和類中的成員,防止被混淆或移除
keepnames 保留類和類中的成員,防止被混淆,成員沒有被引用會被移除
keepclassmembers 只保留類中的成員,防止被混淆或移除
keepclassmembernames 只保留類中的成員,防止被混淆,成員沒有引用會被移除
keepclasseswithmembers 保留類和類中的成員,防止被混淆或移除,保留指明的成員
keepclasseswithmembernames 保留類和類中的成員,防止被混淆,保留指明的成員,成員沒有引用會被移除

如:
(1)保留某個包下面的類以及子包

-keep public class com.droidyue.com.widget.**

(2)保留所有類中使用otto的public方法

# Otto
-keepclassmembers class ** {
    @com.squareup.otto.Subscribe public *;
    @com.squareup.otto.Produce public *;
}

(3)保留Contants類的BOOK_NAME屬性

-keepclassmembers class com.example.admin.proguardsample.Constants {
     public static java.lang.String BOOK_NAME;
}

(4)dontwarn:
引入的library可能存在一些無法找到的引用和其他問題,在build時可能會發(fā)出警告,如果我們不進(jìn)行處理,通常會導(dǎo)致build中止.因此為了保證build繼續(xù),我們需要使用dontwarn處理這些我們無法解決的library的警告.

#比如關(guān)閉Twitter sdk的警告,我們可以這樣做
-dontwarn com.twitter.sdk.**
  • Proguard通配符
Proguard通配符 描述
<field> 匹配類中的所有字段
<method> 匹配類中所有的方法
<init> 匹配類中所有的構(gòu)造函數(shù)
* 匹配任意長度字符,不包含包名分隔符(.)
** 匹配任意長度字符,包含包名分隔符(.)
*** 匹配任意參數(shù)類型
... ...
  • 基本規(guī)則
//不混淆某個類
-keep public class name.huihui.example.Test { *; }
//不混淆某個類的子類
-keep public class * extends name.huihui.example.Test { *; }
//不混淆所有類名中包含了“model”的類及其成員
-keep public class **.*model*.** {*;}
//不混淆某個接口的實(shí)現(xiàn)
-keep class * implements name.huihui.example.TestInterface { *; }
//不混淆某個類的構(gòu)造方法
-keepclassmembers class name.huihui.example.Test { 
    public <init>(); 
}
//不混淆某個類的特定的方法
-keepclassmembers class name.huihui.example.Test { 
    public void test(java.lang.String); 
}
//不混淆某個類的內(nèi)部類
-keep class name.huihui.example.Test$* {
        *;
 }
//兩個常用的混淆命令,注意:
//一顆星表示只是保持該包下的類名,而子包下的類名還是會被混淆;
//兩顆星表示把本包和所含子包下的類名都保持;
-keep class com.suchengkeji.android.ui.**
-keep class com.suchengkeji.android.ui.*
//用以上方法保持類后,你會發(fā)現(xiàn)類名雖然未混淆,但里面的具體方法和變量命名還是變了,
//如果既想保持類名,又想保持里面的內(nèi)容不被混淆,我們就需要以下方法了

//不混淆某個包所有的類
-keep class com.suchengkeji.android.bean.** { *; }
//在此基礎(chǔ)上,我們也可以使用Java的基本規(guī)則來保護(hù)特定類不被混淆,比如我們可以用extend,implement等這些Java規(guī)則。如下
# 保留我們使用的四大組件,自定義的Application等等這些類不被混淆
# 因?yàn)檫@些子類都有可能被外部調(diào)用
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Appliction
-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 * extends android.view.View
-keep public class com.android.vending.licensing.ILicensingService

哪些不應(yīng)該混淆

  • 使用了自定義控件那么要保證它們不參與混淆
  • 使用了枚舉要保證枚舉不被混淆
  • 對第三方庫中的類不進(jìn)行混淆
  • 運(yùn)用了反射的類也不進(jìn)行混淆
  • 使用了 Gson 之類的工具要使 JavaBean 類即實(shí)體類不被混淆
  • 在引用第三方庫的時候,一般會標(biāo)明庫的混淆規(guī)則的,建議在使用的時候就把混淆規(guī)則添加上去,免得到最后才去找
  • 有用到 WebView 的 JS 調(diào)用也需要保證寫的接口方法不混淆,原因和第一條一樣
  • Parcelable 的子類和 Creator 靜態(tài)成員變量不混淆,否則會產(chǎn)生 Android.os.BadParcelableException 異常
  • 使用的四大組件,自定義的Application* 實(shí)體類
  • JNI中調(diào)用的類
  • Layout布局使用的View構(gòu)造函數(shù)(自定義控件)、android:onClick等。

來一個傻瓜式混淆模板


#
#-------------------------------------------基本不用動區(qū)域----------------------------------------------
#
#
# -----------------------------基本 -----------------------------
#

# 指定代碼的壓縮級別 0 - 7(指定代碼進(jìn)行迭代優(yōu)化的次數(shù),在Android里面默認(rèn)是5,這條指令也只有在可以優(yōu)化時起作用。)
-optimizationpasses 5
# 混淆時不會產(chǎn)生形形色色的類名(混淆時不使用大小寫混合類名)
-dontusemixedcaseclassnames
# 指定不去忽略非公共的庫類(不跳過library中的非public的類)
-dontskipnonpubliclibraryclasses
# 指定不去忽略包可見的庫類的成員
-dontskipnonpubliclibraryclassmembers
#不進(jìn)行優(yōu)化,建議使用此選項(xiàng),
-dontoptimize
 # 不進(jìn)行預(yù)校驗(yàn),Android不需要,可加快混淆速度。
-dontpreverify
# 屏蔽警告
-ignorewarnings
# 指定混淆是采用的算法,后面的參數(shù)是一個過濾器
# 這個過濾器是谷歌推薦的算法,一般不做更改
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
# 保護(hù)代碼中的Annotation不被混淆
-keepattributes *Annotation*
# 避免混淆泛型, 這在JSON實(shí)體映射時非常重要
-keepattributes Signature
# 拋出異常時保留代碼行號
-keepattributes SourceFile,LineNumberTable
 #優(yōu)化時允許訪問并修改有修飾符的類和類的成員,這可以提高優(yōu)化步驟的結(jié)果。
# 比如,當(dāng)內(nèi)聯(lián)一個公共的getter方法時,這也可能需要外地公共訪問。
# 雖然java二進(jìn)制規(guī)范不需要這個,要不然有的虛擬機(jī)處理這些代碼會有問題。當(dāng)有優(yōu)化和使用-repackageclasses時才適用。
#指示語:不能用這個指令處理庫中的代碼,因?yàn)橛械念惡皖惓蓡T沒有設(shè)計(jì)成public ,而在api中可能變成public
-allowaccessmodification
#當(dāng)有優(yōu)化和使用-repackageclasses時才適用。
-repackageclasses ''
 # 混淆時記錄日志(打印混淆的詳細(xì)信息)
 # 這句話能夠使我們的項(xiàng)目混淆后產(chǎn)生映射文件
 # 包含有類名->混淆后類名的映射關(guān)系
-verbose

#
# ----------------------------- 默認(rèn)保留 -----------------------------
#
#----------------------------------------------------
# 保持哪些類不被混淆
#繼承activity,application,service,broadcastReceiver,contentprovider....不進(jìn)行混淆
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.support.multidex.MultiDexApplication
-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 * extends android.view.View
-keep class android.support.** {*;}## 保留support下的所有類及其內(nèi)部類

-keep public class com.google.vending.licensing.ILicensingService
-keep public class com.android.vending.licensing.ILicensingService
#表示不混淆上面聲明的類,最后這兩個類我們基本也用不上,是接入Google原生的一些服務(wù)時使用的。
#----------------------------------------------------

# 保留繼承的
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v7.**
-keep public class * extends android.support.annotation.**


#表示不混淆任何包含native方法的類的類名以及native方法名,這個和我們剛才驗(yàn)證的結(jié)果是一致
-keepclasseswithmembernames class * {
    native <methods>;
}


#這個主要是在layout 中寫的onclick方法android:onclick="onClick",不進(jìn)行混淆
#表示不混淆Activity中參數(shù)是View的方法,因?yàn)橛羞@樣一種用法,在XML中配置android:onClick=”buttonClick”屬性,
#當(dāng)用戶點(diǎn)擊該按鈕時就會調(diào)用Activity中的buttonClick(View 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);
}

#表示不混淆任何一個View中的setXxx()和getXxx()方法,
#因?yàn)閷傩詣赢嬓枰邢鄳?yīng)的setter和getter的方法實(shí)現(xiàn),混淆了就無法工作了。
-keep public class * extends android.view.View{
    *** get*();
    void set*(***);
    public <init>(android.content.Context);
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
}

#表示不混淆Parcelable實(shí)現(xiàn)類中的CREATOR字段,
#毫無疑問,CREATOR字段是絕對不能改變的,包括大小寫都不能變,不然整個Parcelable工作機(jī)制都會失敗。
-keep class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator *;
}
# 這指定了繼承Serizalizable的類的如下成員不被移除混淆
-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}
# 保留R下面的資源
#-keep class **.R$* {
# *;
#}
#不混淆資源類下static的
-keepclassmembers class **.R$* {
    public static <fields>;
}

# 對于帶有回調(diào)函數(shù)的onXXEvent、**On*Listener的,不能被混淆
-keepclassmembers class * {
    void *(**On*Event);
    void *(**On*Listener);
}

# 保留我們自定義控件(繼承自View)不被混淆
-keep public class * extends android.view.View{
    *** get*();
    void set*(***);
    public <init>(android.content.Context);
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
}

#
#----------------------------- WebView(項(xiàng)目中沒有可以忽略) -----------------------------
#
#webView需要進(jìn)行特殊處理
-keepclassmembers class fqcn.of.javascript.interface.for.Webview {
   public *;
}
-keepclassmembers class * extends android.webkit.WebViewClient {
    public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
    public boolean *(android.webkit.WebView, java.lang.String);
}
-keepclassmembers class * extends android.webkit.WebViewClient {
    public void *(android.webkit.WebView, jav.lang.String);
}
#在app中與HTML5的JavaScript的交互進(jìn)行特殊處理
#我們需要確保這些js要調(diào)用的原生方法不能夠被混淆,于是我們需要做如下處理:
-keepclassmembers class com.ljd.example.JSInterface {
    <methods>;
}

#
#---------------------------------實(shí)體類---------------------------------
#--------(實(shí)體Model不能混淆,否則找不到對應(yīng)的屬性獲取不到值)-----
#
-dontwarn com.suchengkeji.android.confusiondemo.md.**
#對含有反射類的處理
-keep class com.suchengkeji.android.confusiondemo.md.** { *; }
#
# ----------------------------- 其他的 -----------------------------
#
# 刪除代碼中Log相關(guān)的代碼
-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(...);
}

# 保持測試相關(guān)的代碼
-dontnote junit.framework.**
-dontnote junit.runner.**
-dontwarn android.test.**
-dontwarn android.support.test.**
-dontwarn org.junit.**


#
# ----------------------------- 第三方 -----------------------------
#
-dontwarn com.orhanobut.logger.**
-keep class com.orhanobut.logger.**{*;}
-keep interface com.orhanobut.logger.**{*;}

-dontwarn com.google.gson.**
-keep class com.google.gson.**{*;}
-keep interface com.google.gson.**{*;}
#        。。。。。。
下面來看看混淆和不混淆的區(qū)別(以本demo為例)

先看下我項(xiàng)目中的目錄:

項(xiàng)目中的目錄.png

上圖中的目錄很清楚,bean(md)中共兩個實(shí)體類只用Person一個Activity和一個ListView的Adapter:ListAdapter
在看看沒有混淆反編譯后的目錄:
未混淆的目錄.png

上圖可以清楚地看到,為混淆的代碼,可以清楚明確的看到代碼中的結(jié)構(gòu)、方法,反編譯后容易被拿到源碼
在看看混淆后的目錄:
混淆后目錄.png

可以從混淆后的目錄看到,代碼明顯暈未混淆的不同,屬性方法基本都用啊,b,c...表示了,更不容易看懂代碼結(jié)果和方法,這就減少了源碼的外泄等

注意:
有人可能想問為什么我的項(xiàng)目中的md(bean)文件中有一個Datas實(shí)體類,混淆后為什么目錄沒見到,因?yàn)樵诨煜渲弥虚_啟了移除無用的resource文件所以在沒引用到該資源的情況下在打包時會自動刪除該資源
應(yīng)用添加混淆就是不想開源應(yīng)用,為了加大反編譯的成本,但是并不能徹底防止反編譯

構(gòu)建時Proguard都會輸出:dump.txt(說明APK中所有類文件的內(nèi)部結(jié)構(gòu))、mapping.txt(提供原始與混淆過的類、方法和字段名稱之間的轉(zhuǎn)換)、seeds.txt(列出未進(jìn)行混淆的類和成員)、usage.txt(列出從APK移除的代碼),輸出路徑為:F:\...\ConfusionDemo\app\build\outputs\mapping

更多關(guān)于Proguard混淆,直戳去官網(wǎng)

2021-04-01 補(bǔ)充帶 throws 的異常拋出方法混淆

最近開發(fā)中在打包生產(chǎn)一個.jar文件的時候,方法本事是有異常拋出,但是打包后沒有異常拋出,經(jīng)過查找就是一句代碼的問題,如下,在混淆中這樣添加

-keepattributes Exceptions
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 代碼混淆(Obfuscated code)亦稱花指令,是將計(jì)算機(jī)程序的代碼,轉(zhuǎn)換成一種功能上等價,但是難于閱讀和理...
    程序猿TODO閱讀 99評論 0 0
  • 我們都希望自己的代碼足夠"安全",即使別人反編譯了我們的應(yīng)用,他們也很難從反編譯的代碼中找出漏洞。這時候我們就依賴...
    東方未曦閱讀 2,045評論 1 4
  • 一、前言: 代碼混淆(Obfuscated code):是將程序中的代碼以某種規(guī)則轉(zhuǎn)換為難以閱讀和理解的代碼的一種...
    因?yàn)槲业男?/span>閱讀 1,427評論 0 0
  • 在了解混淆之前,先來了解一下反編譯。 反編譯 Android程序打完包之后得到的是一個APK文件,這個文件是可以直...
    聽媽媽的話閱讀 644評論 0 0
  • 簡介作為Android開發(fā)者,如果你不想開源你的應(yīng)用,那么在應(yīng)用發(fā)布前,就需要對代碼進(jìn)行混淆處理,從而讓我們代碼即...
    嚶嚶嚶999閱讀 854評論 0 5

友情鏈接更多精彩內(nèi)容