Android混淆解析
此文章轉載來源https://www.jianshu.com/p/84114b7feb38點擊打開鏈接
Android混淆解析
?
一、混淆的目的
??????? 一款發布到市場的軟件原則上都應該做代碼混淆。
??????? 通過代碼混淆可以將項目中的類、方法、變量等信息進行重命名,變成一些無意義的簡短名字,同時也可以移除未被使用的類、方法、變量等。所以直觀的看,通過混淆可以提高程序的安全性,增加逆向工程的難度,同時也有效縮減了apk的體積。一起來get這個技能吧!
?
二、開啟混淆
??????? 在基于Android Studio項目的app module的build.gradle中有如下默認代碼片段:
buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'signingConfig signingConfigs.release} }??????? 代表要發布的release包的混淆配置,默認不開啟混淆,要開啟混淆首先做如下修改:
minifyEnabled true??????? 開啟混淆后還可以添加shrinkResourcestrue配置,代表開啟資源文件壓縮。
??????? 這樣就在release模式下開啟了混淆。一般在debug模式下不開啟混淆,因為混淆會導致編譯時間變長、無法debug問題,畢竟也是內部測試嘛,沒必要!
??????? 開啟混淆后,接下來就是用混淆配置文件來設置混淆規則:
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'·????????proguard-android.txt代表系統默認的混淆規則配置文件,該文件在<AndroidSDK目錄>/tools/proguard下,一般不要更改該配置文件,因為也會作用于其它項目,除非你能確保所做的更改不影響其它項目的混淆。
·????????proguard-rules.pro代碼表當前project的混淆配置文件,在app module下,可以通過修改該文件來添加適用當前項目的混淆規則。
?
三、編寫混淆配置文件
??????? 為了更好的編寫proguard-rules.pro,先學習下系統的proguard-android.txt
# This is a configuration file for ProGuard. # http://proguard.sourceforge.net/index.html#manual/usage.html # 混淆時不使用大小寫混合類名 -dontusemixedcaseclassnames # 不跳過library中的非public的類 -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 # 不混淆包含native方法的類的類名以及native方法名 -keepclasseswithmembernames class * { ??? native <methods>; } # keep setters in Views so that animations can still work. # see http://proguard.sourceforge.net/manual/examples.html#beans # 不混淆View中的setXxx()和getXxx()方法,以保證屬性動畫正常工作 -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 # 不混淆Activity中參數是View的方法,例如,一個控件通過android:onClick="clickMethodName"綁定點擊事件,混淆后會導致點擊事件失效 -keepclassmembers class * extends android.app.Activity { ?? public void *(android.view.View); } # For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations # 不混淆枚舉類中的values()和valueOf()方法 -keepclassmembers enum * { ??? public static **[] values();public static ** valueOf(java.lang.String); } # 不混淆Parcelable實現類中的CREATOR字段,以保證Parcelable機制正常工作 -keepclassmembers class * implements android.os.Parcelable { ? public static final android.os.Parcelable$Creator CREATOR; } # 不混淆R文件中的所有靜態字段,以保證正確找到每個資源的id -keepclassmembers class **.R$* { ??? public static <fields>; } # The support library contains references to newer platform versions. # Don't warn about those in case this app is linking against an older # platform version.? We know about them, and they are safe. # 不對android.support包下的代碼警告(如果我們打包的版本低于support包下某些類的使用版本,會出現警告的問題) -dontwarn android.support.** # Understand the @Keep support annotation. # 不混淆Keep類 -keep class android.support.annotation.Keep # 不混淆使用了注解的類及類成員 -keep @android.support.annotation.Keep class * {*;} # 如果類中有使用了注解的方法,則不混淆類和類成員 -keepclasseswithmembers class * { ??? @android.support.annotation.Keep <methods>; } # 如果類中有使用了注解的字段,則不混淆類和類成員 -keepclasseswithmembers class * { ??? @android.support.annotation.Keep <fields>; } # 如果類中有使用了注解的構造函數,則不混淆類和類成員 -keepclasseswithmembers class * { ??? @android.support.annotation.Keep <init>(...); }?
??????? 可以看出proguard-android.txt主要作用是防止指定內容被混淆,其中使用了以-開頭,結合keep類關鍵字,*、<>等通配符的語法,先get這些語法吧!
·????????首先看keep類關鍵字:
| 關鍵字? | 含義 |
| keep | 保留類和類成員,防止被混淆或移除 |
| Keepnames | 保留類和類成員,防止被混淆,但沒有被引用的類成員會被移除 |
| keepclassmembers | 只保留類成員,防止被混淆或移除 |
| keepclassmembernames? | 只保留類成員,防止被混淆,但沒有被引用的成員會被移除 |
| keepclasseswithmembers | 保留類和類成員,防止被混淆或移除,如果指定的類成員不存在還是會被混淆 |
| keepclasseswithmembernames | 保留類和類成員,防止被混淆,如果指定的類成員不存在還是會被混淆,沒有被引用的類成員會被移除 |
?
?
·????????相關通配符:
| 通配符 | ?含義 |
| * | 匹配任意長度字符,但不含包名分隔符.。例如一個類的全包名路徑是com.othershe.test.Person,使用com.othershe.test.*、com.othershe.test.*都是可以匹配的,但com.othershe.*就不能匹配 |
| **? | 匹配任意長度字符,并包含包名分隔符.。例如要匹配com.othershe.test.**包下的所有內容 |
| *** | ?匹配任意參數類型。例如*** getName(***)可匹配String getName(String) |
| ...? | 匹配任意長度的任意類型參數。例如void setName(...)可匹配void setName(String firstName, String secondName) |
| <fileds> | 匹配類、接口中所有字段 |
| <methods> | 匹配類、接口中所有方法 |
| <init> | 匹配類中所有構造函數 |
??????? 到這里對混淆已經有了基本的了解,系統的proguard-android.txt已經為我們完成了大部分基礎的混淆配置工作,至于編寫當前appmodule下的proguard-rules.pro,只需要針對當前項目添加一些特有的配置,避免某些重要的東西被混淆掉導致錯誤,我們主要考慮以下幾點:
· ? ? ? ?①、在AndroidManifest.xml中注冊的繼承四大組件的子類的類名以及重寫的方法名都不會被混淆。如果希望項目中android.support.v4.app.Fragment子類的類名和重寫父類的方法名不被混淆可以添加如下配置:
# 不混淆Fragment的子類類名以及onCreate()、onCreateView()方法名 -keep public class * extends android.support.v4.app.Fragment { ??? public void onCreate(android.os.Bundle);public android.view.View onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle); }· ? ? ? ?②、不混淆某個特定的類和類中所有成員
-keep class com.othershe.test.utils.CommonUtil { *; }· ? ? ? ?③、不混淆某個目錄下的文件,例如使用Gson時,數據bean不能被混淆,需要如下配置:
# com.othershe.test.model代表數據bean所在的全包名目錄 -keep class com.othershe.test.model.** { *; }· ? ? ? ?④、上一條的具體原因是因為Gson用到了反射。如果我們自己使用了反射,例如
Field field = service.getField("BASE_URL");注:BASE_URL是service所屬類的一個字段名,則該字段不能被混淆。
· ? ? ? ?⑤、保留泛型
-keepattributes Signature· ? ? ? ?⑥、保留用于調試堆棧跟蹤的行號信息(為了后期調試方便,建議配置)
-keepattributes SourceFile,LineNumberTable· ? ? ? ?⑦、如果使用了上一行配置,還需要添加如下配置將源文件重命名為SourceFile,以便通過鼠標點擊直達源文件:
-renamesourcefileattribute SourceFile· ? ? ? ⑧、 WebView中使用了JS調用,需要添加如下配置:
-keepclassmembers class fqcn.of.javascript.interface.for.webview { ?? public *; }· ? ? ? ?⑨、項目中使用的第三方library混淆規則,列舉了幾個常用的:
# okhttp -dontwarn okhttp3.** -dontwarn okio.** -dontwarn javax.annotation.** -keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase# Retrofit -dontwarn okio.** -dontwarn javax.annotation.** -dontnote retrofit2.Platform -dontwarn retrofit2.Platform$Java8 -keepattributes Signature -keepattributes Exceptions# RxJava RxAndroid -dontwarn sun.misc.** -keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* { ??? long producerIndex;long consumerIndex; } -keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef { ??? rx.internal.util.atomic.LinkedQueueNode producerNode; } -keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef { ??? rx.internal.util.atomic.LinkedQueueNode consumerNode; }# Gson -keep class com.google.gson.stream.** { *; } -keepattributes EnclosingMethod # xxx代表model類的全包名路徑 -keep class xxx.** { *; }# butterknie -keep class butterknife.** { *; } -dontwarn butterknife.internal.** -keep class **$$ViewBinder { *; } -keepclasseswithmembernames class * { ??? @butterknife.* <fields>; } -keepclasseswithmembernames class * { ??? @butterknife.* <methods>; }# eventbus -keepattributes *Annotation* -keepclassmembers class ** { ??? @org.greenrobot.eventbus.Subscribe <methods>; } -keep enum org.greenrobot.eventbus.ThreadMode { *; } # Only required if you use AsyncExecutor -keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent { ??? <init>(java.lang.Throwable); }以上這些可以按需添加到proguard-rules.pro!
?
四、查看混淆結果
?
??????? 混淆后打包,會在appmodule/build/outputs/mapping/release目錄下生成如下文件(動不動就幾萬行,是在沒法看):
·????????dump.txt:描述apk文件中所有類的內部結構
·????????mapping.txt:混淆前后的類、類成員、方法的對照關系(重要,追溯Crash堆棧信息要用到)
·????????resources.txt:資源文件的壓縮信息
·????????seeds.txt:未被混淆的類和成員
·????????usage.txt:被移除的代碼
混淆后的apk包,需要系統的測試,防止混淆導致的潛在bug。
?
我們還是有必要看一下混淆后的代碼結構,驗證混淆是否成功。一個簡單的辦法,Android Studio的Build菜單下有一個Analyze APK選項,只需要先選擇要分析的apk包,在之后的界面點擊classes.dex即可看到混淆后的代碼結構:
但是這樣只能看到一個類的成員變量和方法的結構,如果要看一個類的具體內容,就需要反編譯apk包了,具體可參考Android apk反編譯及重新打包流程,希望一切順利!
?
五、 追溯Crash堆棧信息
代碼混淆后,也會導致Crash堆棧信息被混淆,難以閱讀,增加定位問題位置的難度,一個混淆后的Crash堆棧信息類似這樣,核心的信息都沒了:
為了解決這個問題,可以使用<SDK目錄>\tools\proguard\bin下的proguardgui.bat腳本將Crash堆棧信息還原到混淆前的狀態。步驟如下:
1.?雙擊打開腳本,選擇左邊的ReTrace選項
2.?選擇Mappingfile文件,也就是混淆后打包后在appmodule/build/outputs/mapping/release下生成的mapping.txt
3.?拷貝混淆后的堆棧信息
4.?點擊右下角的ReTrace!按鈕,完成Crash堆棧信息的追溯
?
如下圖中間部分就是追溯到的原Crash堆棧信息:
代碼混淆常用的內容就這些了,重點還是要理解混淆的相關語法,靈活運用!混淆一定程度增加逆向工程的難度,但還是能被破解的,如果你的代碼有價值,也難免被有心的人利用!除了混淆之外,一些廠商也提供了apk加固的服務來保證軟件的安全性,但也是可以被脫殼的!有興趣的可自行了解!
總結
以上是生活随笔為你收集整理的Android混淆解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android vector标签 Pat
- 下一篇: Android Studio - HPR