原創(chuàng)地址:http://blog.csdn.net/tl792814781/article/details/51447255
原創(chuàng)作者:迷途開發(fā)者的博客
APK的混淆分為資源混淆與代碼混淆.一般大部分都使用兩者結(jié)合.尤其是目前主流的應(yīng)用.
其中的優(yōu)點(diǎn):
- 防止被惡意破解逆向分析
- 減少apk體積,也是瘦身的方法
- 代碼可閱讀性降低
其中的缺點(diǎn):
- 調(diào)試不方便(可以配置mapping變得方便)
- 測試不充分,可能導(dǎo)致部分功能不能使用(比如注解相關(guān)等)
混淆前(這兒偷個(gè)懶直接用工具反編譯看):
混淆后:
如何使用代碼混淆:
1.直接在build.gradle文件中配置即可.如圖:
圖片有了,文件也找到了,接下來了呢?
buildTypes {
debug {
// 如果沒有提供混淆規(guī)則文件讼庇,則設(shè)置默認(rèn)的混淆規(guī)則文件(SDK/tools/proguard/proguard-android.txt)
pseudoLocalesEnabled true
// 顯示Log
buildConfigField "boolean", "LOG_DEBUG", "true"
//混淆
minifyEnabled false
//Zipalign優(yōu)化
zipAlignEnabled true
// 移除無用的resource文件
shrinkResources true
//加載默認(rèn)混淆配置文件
proguardFiles getDefaultProguardFile('proguard-Android.txt'), 'proguard-rules.pro'
//簽名
signingConfig signingConfigs.debug
}
release {
// 如果沒有提供混淆規(guī)則文件钙勃,則設(shè)置默認(rèn)的混淆規(guī)則文件(SDK/tools/proguard/proguard-android.txt)
pseudoLocalesEnabled true
// 不顯示Log
buildConfigField "boolean", "LOG_DEBUG", "false"
//混淆
minifyEnabled true
//Zipalign優(yōu)化
zipAlignEnabled true
// 移除無用的resource文件
shrinkResources true
//加載默認(rèn)混淆配置文件
proguardFiles getDefaultProguardFile('proguard-Android.txt'), 'proguard-rules.pro'
//簽名
signingConfig signingConfigs.relealse
}
}
經(jīng)過這樣的配置過后呢,可以發(fā)現(xiàn)gradle是加載了一個(gè)混淆的配置文件(proguard-Android.txt,這個(gè)文件的位置和build.gradle同級(jí)),根據(jù)混淆配置文件的規(guī)則進(jìn)行混淆的.為什么要混淆配置呢?因?yàn)橛行〇|西是不能混淆的,比如jni調(diào)用,本身就是根據(jù)包名去調(diào)用的,如果混淆了就會(huì)NotFoundMethod了.所以這個(gè)規(guī)則就是自定義的了.
如何自定義:
-libraryjars class_path //應(yīng)用的依賴包眉踱,如Android-support-v4
-keep [,modifier,...] class_specification //這里的keep就是保持的意思袄简,意味著不混淆某些類
-keepclassmembers [,modifier,...] class_specification //同樣的保持豺谈,不混淆類的成員
-keepclasseswithmembers [,modifier,...] class_specification //不混淆類及其成員
-keepnames class_specification //不混淆類及其成員名
-keepclassmembernames class_specification //不混淆類的成員名
-keepclasseswithmembernames class_specification //不混淆類及其成員名
-assumenosideeffects class_specification //假設(shè)調(diào)用不產(chǎn)生任何影響,在proguard代碼優(yōu)化時(shí)會(huì)將該調(diào)用remove掉茬末。如system.out.println和Log.v等等
-dontwarn [class_filter] //不提示warnning
接下來看了語法可能有點(diǎn)蒙了,這些只是了解就可以了,一般有通用的.
比如:
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in D:\Android\sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-verbose
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
# 系統(tǒng)類不需要混淆
-keepattributes *Annotation*
-keep class * extends java.lang.annotation.Annotation { *; }
-keepattributes Signature
-keep public class * extends android.app.Fragment
-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
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v7.**
-dontwarn com.alipay.android.phone.mrpc.core**
-keep class com.alipay.android.phone.mrpc.core.**{*;}
-dontwarn com.alipay.apmobilesecuritysdk.face**
-keep class com.alipay.apmobilesecuritysdk.face.**{*;}
# 百度導(dǎo)航的不需要混淆
#-dontwarn com.baidu.navisdk.comapi.tts.ttsplayer**
#-keep class com.baidu.navisdk.**{*;}
# Jpush不需要混淆
-dontwarn cn.jpush**
-keep class cn.jpush.** { *; }#Jpush
# XUtils工具不需要混淆
-dontwarn com.lidroid**
-keep class com.lidroid.**{*;}#ViewInject
# 自定義控件不需要混淆
-keep class com.cheweishi.android.widget.** {*;}#CustomView
-dontwarn com.sinovoice**
-keep class com.sinovoice.** { *; }
# 百度地圖相關(guān)不需要混淆
-dontwarn com.baidu**
-keep class com.baidu.** { *; }
-keep class vi.com.gdi.bgl.android.**{*;}
#-dontwarn demo.Pinyin4jAppletDemo**
#-keep class demo.Pinyin4jAppletDemo{*;}
# volley工具不需要混淆
-dontwarn com.android.volley.toolbox**
-keep class com.android.volley.toolbox{*;}
# gson工具不需要混淆
-dontwarn com.google.gson**
-keep class com.google.gson.**{*;}
#-dontwarn com.nineoldandroids.**
#-keep class com.nineoldandroids.**{*;}
-dontwarn org.apache.http**
-keep class org.apache.http.**{*;}
-dontwarn com.handmark.pulltorefresh**
-keep class com.handmark.pulltorefresh.**{*;}
-dontwarn com.squareup.picasso**
-keep class com.squareup.picasso.**{*;}
-dontwarn com.cheweishi.android.entity**
-keep class com.cheweishi.android.entity.**{*;}
-keep class com.cheweishi.android.response.BaseResponse
-keep public class com.android.vending.licensing.ILicensingService
-printmapping mapping.txt #混淆后文件映射
#-keep public class com.cheweishi.android.R$*{
# public static final int *;
#}
-keepclasseswithmembernames class * {
native <methods>;
}
-keepclasseswithmembernames class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembernames class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
當(dāng)你混淆后你會(huì)發(fā)現(xiàn)一些錯(cuò)誤日志全是a.b.c.d()等,根本不知道具體錯(cuò)誤在哪兒,這就是混淆后調(diào)試的確定,竟然提供了混淆肯定就可以還原啦,google早就考慮到了.那我要怎么還原呢?
1.cmd進(jìn)入sdk/tools/proguard/bin目錄。
2.將混淆后的日志和上文提到的mapping文件放入此目錄中。
3.執(zhí)行命令:retrace.bat mapping.txt XXX.txt
未還原前:
還原后:
這下有沒有覺得比較好調(diào)試了,這下你比較關(guān)心如何線上的產(chǎn)品如何查看呢?一般(友盟)提供了mapping文件管理的,所以混淆規(guī)則的文件(proguard-Android.txt)的生成是非常有必要的.
資源混淆:
資源混淆是可以解決apk瘦身,主要就是壓縮了資源文件及修改了文件名字及映射關(guān)系.看看效果吧.
資源混淆前:
資源混淆后:
關(guān)于資源混淆有很多種解決方案,首先我們可以看看最早美團(tuán)提出來的(美團(tuán)資源保護(hù)實(shí)戰(zhàn),這里就不做具體的分析):
- 1.首先介紹了打包的過程,是通過appt對(duì)資源進(jìn)行記錄.
- 2.了解原理后,可以通過修改源碼在資源文件映射的時(shí)候修改文件名字及映射路徑
- 3.美團(tuán)僅僅是提供了修改的思路,并未將混淆的函數(shù)公開
其實(shí)通過這樣修改aapt,然后再Linux編譯出來的aapt(可以編譯分為Linux或者windows,以windows為例)替換置SDK目錄下/build-tools/aapt.exe,然后使用對(duì)應(yīng)版本編譯即可.當(dāng)然這樣的做法雖然可以實(shí)現(xiàn),但是非常麻煩(依賴編譯過程,依賴編譯源碼…),比如aapt升級(jí)等
再看看微信開源的git(AndResGuard),大致原理將資源文件通過7zip進(jìn)行壓縮后重新映射然后打包成apk并對(duì)其簽名.
對(duì)比:
如果你還需要對(duì)apk瘦身,你可以將編譯前無用資源給刪除.具體可使用gradle提供的Lint.
如何使用:
然后build后會(huì)在projectName\app\build\outputs\lint-results.xml,該Lint可以檢測語法以及無用資源,然后寫一個(gè)工具就可以刪除了.這里也可以推薦大家使用:lintAutoCleaner,該工具選擇對(duì)應(yīng)的lint-results.xml文件就可以自動(dòng)刪除并備份了,非常人性化.