日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android 混淆详解

發(fā)布時間:2024/9/30 Android 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android 混淆详解 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

轉(zhuǎn)載請標(biāo)明出處:http://blog.csdn.net/zhaoyanjun6/article/details/69388246
本文出自【趙彥軍的博客】

文章目錄

  • 混淆的基本概念
  • 開啟混淆
  • 混淆規(guī)則理解
    • 1、有一些固定的混淆規(guī)則不需要更改:
    • 2、理解通配符
    • 3、保證指定包名下的所有類及子包中所有的類不被混淆
    • 4、保證指定的類不被混淆
    • 5、不混淆指定類的子類
    • 6、指定接口不混淆
    • 7、指定接口的實現(xiàn)類不混淆
    • 8、指定類的內(nèi)部類不混淆
    • 9、構(gòu)造函數(shù)不混淆
    • 10、指定類的屬性和方法不被混淆
    • 11、不混淆類中所有的 public 方法
    • 12、不混淆類中所有的 public 字段
    • 13、不混淆構(gòu)造函數(shù)
    • 13、不混淆 bean 對象里面的 set 、get 方法
  • 常見不混淆的類和屬性
  • 混淆后的項目目錄資源
  • 實戰(zhàn)1
  • aar自動混淆
  • 參考資料

混淆的基本概念

  • 什么是混淆?

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

  • 混淆的目的

1、混淆的目的是為了加大反編譯的成本,但是并不能徹底防止反編譯.

2、壓縮apk 資源文件

開啟混淆

一般我們做項目的時候,都是分為 release 和 debug 版本,release 版本混淆,debug 版本不混淆。設(shè)置如下:

buildTypes {release {minifyEnabled trueproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'}debug {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'}}

混淆規(guī)則理解

1、有一些固定的混淆規(guī)則不需要更改:

#指定代碼的壓縮級別 -optimizationpasses 5#包明不混合大小寫 -dontusemixedcaseclassnames#不去忽略非公共的庫類 -dontskipnonpubliclibraryclasses#優(yōu)化 不優(yōu)化輸入的類文件 -dontoptimize#預(yù)校驗 -dontpreverify#混淆時是否記錄日志 -verbose# 混淆時所采用的算法 -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*#保護(hù)注解 -keepattributes *Annotation*

2、理解通配符

-keep class cn.hadcn.test.** -keep class cn.hadcn.test.*

很多同學(xué)都搞不懂下面兩個的區(qū)別,一顆星表示只是保持該包下的類名,而子包下的類名還是會被混淆;兩顆星表示把本包和所含子包下的類名都保持;用以上方法保持類后,你會發(fā)現(xiàn)類名雖然未混淆,但里面的具體方法和變量命名還是變了,這時如果既想保持類名,又想保持里面的內(nèi)容不被混淆,我們就需要以下方法了:

-keep class cn.hadcn.test.* {*;}

3、保證指定包名下的所有類及子包中所有的類不被混淆

  • 例子1:com.lib.manager 包下面的類不混淆
-keep class com.lib.manager.**{*;}

  • 例子2:v4包下面的所有類不混淆
-keep class android.support.v4.** { *; }

4、保證指定的類不被混淆

  • 例子1:YiBaWiFiActivity 類不被混淆, YiBaWiFiActivity 完整包名:com.yiba.wifi.sdk.lib.activity.YiBaWiFiActivity
-keep class com.yiba.wifi.sdk.lib.activity.YiBaWiFiActivity{*;}
  • 例子2:v4 包下面的 ActivityCompat 類不被混淆
-keep class android.support.v4.app.ActivityCompat{*;}

5、不混淆指定類的子類

-keep class * extends pp.lib.User { *; }

User 類的子類不混淆

6、指定接口不混淆

Callback 是一個接口,完整包名為:com.lib.impl.Callback

-keep interface com.lib.impl.Callback{ * ; }

7、指定接口的實現(xiàn)類不混淆

Callback 是一個接口,完整包名為:com.lib.impl.Callback . 所有的實現(xiàn)類都不會混淆。

-keep class * implements com.lib.impl.Callback { *; }

8、指定類的內(nèi)部類不混淆

PhoneUtil 的源碼如下:

package com.lib.manager; import android.content.Context; import android.os.AsyncTask;/*** Created by yiba_zyj on 2017/4/5.*/public class PhoneUtil {public final static int APPID = 100 ;public PhoneUtil( Context context ){}class MyTask extends AsyncTask {@Overrideprotected Object doInBackground(Object[] params) {return null;}} }

PhoneUtil 有一個常量、一個構(gòu)造函數(shù)、一個內(nèi)部類.

混淆規(guī)則:

-keep class com.lib.manager.PhoneUtil$* {* ; }

混淆后的結(jié)果如下:

可以看到混淆后的 PhoneUtil ,常量和 構(gòu)造函數(shù) 都被移除了,只留下了 內(nèi)部類 MyTask 。

9、構(gòu)造函數(shù)不混淆

PhoneUtil 的源碼如所示:

package com.lib;/*** Created by yiba_zyj on 2017/4/7.*/public class PhoneUtil {public static final String aa = "1222" ;public void run(){}}

混淆規(guī)則:PhoneUtil 的無參構(gòu)造函數(shù)不混淆 。PhoneUtil 里面沒有用到的 屬性和方法將會被移除。

-keep class com.lib.PhoneUtil {public <init>(); }

那么有參的構(gòu)造函數(shù)的混淆規(guī)則是怎么樣的?

混淆規(guī)則:PhoneUtil 的 參數(shù)為 Context 的構(gòu)造函數(shù)不混淆

-keep class com.lib.PhoneUtil { public <init>( android.content.Context ); }

10、指定類的屬性和方法不被混淆

  • 原始類 PhoneUtil 代碼如下,完整的包名為:com.lib.manager.PhoneUtil
package com.lib.manager;import android.content.Context; import android.util.DisplayMetrics; import android.view.WindowManager;/*** Created by yiba_zyj on 2017/4/5.*/public class PhoneUtil {public static final int AppID = 100 ;/*** 獲得屏幕高度* @param context* @return*/public static int getScreenWidth(Context context) {WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);DisplayMetrics outMetrics = new DisplayMetrics();wm.getDefaultDisplay().getMetrics(outMetrics);return outMetrics.widthPixels;}/*** 獲得屏幕寬度* @param context* @return*/public static int getScreenHeight(Context context) {WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);DisplayMetrics outMetrics = new DisplayMetrics();wm.getDefaultDisplay().getMetrics(outMetrics);return outMetrics.heightPixels;}}

PhoneUtil 類中包含1個常量及2個方法.

  • 類中的變量不被混淆:
-keep class com.lib.manager.PhoneUtil{ public static final int AppID ; }
  • 混淆后的效果如下:
package com.lib.manager;public class PhoneUtil {public static final int AppID = 100;public PhoneUtil() {} }

可以看到混淆后的類中,AppID 常量被保存下來了,getScreenWidth 、 getScreenHeight 這兩個方法被移除了。 為什么會有方法被移除? 因為在混淆時,Android 會默認(rèn)移除沒有使用的的方法和資源,保證apk 合理的被壓縮。

  • 保留類中的方法不被混淆
-keep class com.lib.manager.PhoneUtil{public static int getScreenWidth(android.content.Context);}
  • 混淆后的方法如下:
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) //package com.lib.manager;import android.content.Context; import android.util.DisplayMetrics; import android.view.WindowManager;public class PhoneUtil {public PhoneUtil() {}public static int getScreenWidth(Context var0) {WindowManager var1 = (WindowManager)var0.getSystemService("window");DisplayMetrics var2 = new DisplayMetrics();var1.getDefaultDisplay().getMetrics(var2);return var2.widthPixels;} }

11、不混淆類中所有的 public 方法

# <methods> 匹配所有的方法-keep class cn.hadcn.test.One {public <methods>; }

表示One類下的所有public方法都不會被混淆

12、不混淆類中所有的 public 字段

-keep class pp.lib.PhoneUtil{public <fields> ; }

表示 PhoneUtil 類中所有的 public 屬性將保留,其他類型的字段

13、不混淆構(gòu)造函數(shù)

-keep class pp.lib.PhoneUtil{<init>(***) ;<init>(*** , *** ) ; }

不混淆 PhoneUtil 類中所有 一個參數(shù) 和 兩個參數(shù)的 的構(gòu)造函數(shù)。

13、不混淆 bean 對象里面的 set 、get 方法

User 對象如下圖所示:

package pp.lib;/*** Created by ${zhaoyanjun} on 2017/4/10.*/public class User {private String name ;private String age ;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getAge() {return age;}public void setAge(String age) {this.age = age;} }

混淆規(guī)則:不混淆 User 類中所有的 set 和 get 方法,*** 代表 通配符

-keep class pp.lib.User{void set*( *** ) ;*** get*() ; }

常見不混淆的類和屬性

  • 不混淆四大組件 和 Application

因為四大組件和 Application 需要在 AndroidManifest.xml 中注冊,不能混淆,否則就會報類找不到異常。

-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

特殊情況:

如果 BroadcastReceiver 是動態(tài)注冊的,則是可以加入混淆的。

  • 不混淆任何包含native方法的類的類名以及native方法名
-keepclasseswithmembernames class * {native <methods>; }
  • 不混淆任何一個View中的setXxx()和getXxx()方法,因為屬性動畫需要有相應(yīng)的setter和getter的方法實現(xiàn),混淆了就無法工作了。
-keepclassmembers public class * extends android.view.View {void set*(***);*** get*(); }
  • 不混淆Activity中參數(shù)是View的方法,因為有這樣一種用法,在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); }
  • 不混淆Parcelable實現(xiàn)類中的CREATOR字段,毫無疑問,CREATOR字段是絕對不能改變的,包括大小寫都不能變,不然整個Parcelable工作機(jī)制都會失敗。
-keepclassmembers class * implements android.os.Parcelable {public static final android.os.Parcelable$Creator CREATOR; }
  • 不混淆R文件中的所有靜態(tài)字段,我們都知道R文件是通過字段來記錄每個資源的id的,字段名要是被混淆了,id也就找不著了。
-keepclassmembers class **.R$* {public static <fields>; }

混淆后的項目目錄資源

混淆完以后會在 build/outputs/mapping/release 目錄下生成4個文件。如下圖所示:

  • mapping.txt :代表源碼的 包名/類名/變量名/方法名 和混淆后 的轉(zhuǎn)換關(guān)系。

混淆規(guī)則

-keep class com.lib.manager.PhoneUtil{public static int getScreenWidth(android.content.Context);}

混淆后的 mapping 文件如下圖所示:

從上面的 mapping 文件可以看出:

PhoneUtil 轉(zhuǎn)換為 PhoneUtil , 名字沒有發(fā)生變化,相當(dāng)于沒有混淆。

getScreenWidth 轉(zhuǎn)換為 getScreenWidth , 名字沒有發(fā)生變換,相當(dāng)于沒有混淆。

getScreenHeight 轉(zhuǎn)換位 a , 名字已經(jīng)變換了,增加了反編譯的難度。

混淆后 PhontUtil 源碼如下圖所示:

  • usage.txt : 代表本次混淆過程中被移除的類或者方法。

舉例說明

從上圖中可以看出,本次混淆過程中 , 移除了很多沒用的類。

com.lib.BuildConfig //移除了 com.lib 包下的 BuildConfig 類 com.lib.activity.A //移除了 com.lib.activity 包下的 A 類 com.lib.manager.PhoneUtil:public static final int AppID //移除了 com.lib.manager 包下的 PhoneUtil 類 中的 AppID 常量 com.lib.manager 包下的 PhoneUtil 類 中的 getScreenHeight 方法 。 com.lib.manager.SS //移除了 com.lib.manager 包下的 SS 類 com.lib.manager.Util //移除了 com.lib.manager 包下的 Util 類 com.lib.manager.hj.PP //移除了 com.lib.manager.hj 包下的 PP 類 com.lib.manager.hj.PP$1

實戰(zhàn)1

User 類源碼:

package pp.lib;/*** Created by ${zhaoyanjun} on 2017/4/10.*/public class User {private String name ;private String age ;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getAge() {return age;}public void setAge(String age) {this.age = age;} }

User1 類源碼:

package pp.lib;/*** Created by ${zhaoyanjun} on 2017/4/10.*/public class User1 extends User {private String id ;public void run(){}}

混淆規(guī)則:

-keep class * extends pp.lib.User { *; }

混淆結(jié)果: User 類的 類名已經(jīng)被混淆了,字段沒有混淆

User1 類,類名和字段都沒有混淆

aar自動混淆

解決第三方SDK的混淆配置管理問題.

盡管有些SDK提供方非??孔V的給了混淆規(guī)則, 但是畢竟要添加到自己項目的proguard配置里, 以后如果混淆規(guī)則改了, 配置還得同步改, 對于那些用maven倉庫管理的SDK, 非常不友好.

也許有人注意到了, Android歸檔文件, 也就是俗稱的aar文件里可以攜帶一個proguard.txt文件, 這似乎表明aar文件可以自帶混淆配置.

事實也是如此, aar在構(gòu)建時, 可以通過consumerProguardFiles屬性指定一個proguard配置, 這個配置會被打入aar, 它和proguardFiles屬性指定的proguard配置不同, proguardFiles是用于構(gòu)建aar的混淆規(guī)則, consumerProguardFiles則是aar的接入方在構(gòu)建時會使用的混淆規(guī)則.

第一步定義兩個 .pro 文件 proguard-rules.pro, consumer-rules.pro

proguard-rules.pro : 輸出aar 時需要的混淆規(guī)則,一般是 keep 暴露給接入方的類、方法、接口

consumer-rules.pro:接入方輸出 apk 時需要的混淆規(guī)則,一般是 keep 一些不能混淆的 bean 對象。

最后一步:在 aar 的 build.gradle 中添加 consumerProguardFiles 屬性

android {defaultConfig {...consumerProguardFiles 'consumer-rules.pro'}buildTypes {release {minifyEnabled trueproguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'}} }

最后輸出的 aar 包會帶有 consumer-rules.pro 文件,最后會作用于構(gòu)建 apk 的混淆過程中。

參考資料

  • 騰訊 Bugly Android 混淆那些事兒

  • 常用的反編譯工具 http://git.oschina.net/zyj1609/AndroidReverseProject)

  • Android安全攻防戰(zhàn),反編譯與混淆技術(shù)完全解析(上)

  • Android安全攻防戰(zhàn),反編譯與混淆技術(shù)完全解析(下)

  • 知乎:關(guān)于混淆的思考

總結(jié)

以上是生活随笔為你收集整理的Android 混淆详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。