Android 代碼混淆零基礎入門

內(nèi)容提要

本篇文章主要有三個部分茉帅,讓讀者讀完后能自己寫規(guī)則混淆項目

  • 對Android代碼怎么開啟混淆做一個簡單的介紹瞒斩。
  • 對混淆規(guī)則做一個簡單介紹;
  • 在混淆過后Crash日志反推代碼工具retrace.bat、可視化反推工具GUI說明苍鲜。

Proguard 混淆規(guī)則說明請參考《ProGuard 最全混淆規(guī)則說明》

對混淆的一個簡單介紹:

Android SDK 自帶了混淆工具Proguard。它位于SDK根目錄\tools\proguard下面玷犹。如果開啟了混淆混滔,Proguard默認情況下會對所有代碼,包括第三方包都進行混淆歹颓,可是有些代碼或者第三方包是不能混淆的坯屿,這就需要我們手動編寫混淆規(guī)則來保持不能被混淆的部分。
混淆有幾個作用:

  • 【優(yōu)化】它能優(yōu)化java的字節(jié)碼晴股,使程序運行更快愿伴;
  • 【壓縮】最直觀的就是減少App大小,在混淆過程中它會找出未被使用過的類和類成員并刪除他們电湘;
  • 【混淆】這個功能使我們的java代碼中的類隔节、函數(shù)、變量名隨機變成無意義的代號形如:a,b,c...之類的寂呛,即使我們的APP即使被反編譯怎诫,也不容易理解了。

上面這幾個功能都是默認打開的贷痪,要關閉他們只需配置規(guī)則:
-dontshrink :關閉壓縮幻妓;
-dontoptimize:關閉優(yōu)化;
-dontobfuscate:關閉混淆劫拢。

寫在開始之前:
本編使用Android Studio工具作為開發(fā)環(huán)境肉津,Eclipse類似强胰;
Android Studio新建項目時會在項目根目錄下自動生成一個混淆配置文件:
proguard-rules.pro;【Eclipse 下面的文件名為:proguard.cfg或者proguard.txt】里面的內(nèi)容規(guī)則都是一樣的;

1.現(xiàn)在開始混淆:

第一步:開啟混淆妹沙,編輯項目配置文件build.gradle(Module: app)

*** minifyEnabled true偶洋;這個選項的意思為開啟混淆
*** proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'距糖;//配置文件
**

'proguard-android.txt' 是AndroidStudio默認自動導入的規(guī)則玄窝,這個文件位于Android SDK根目錄\tools\proguard\proguard-android.txt。這里面是一些比較常規(guī)的不能被混淆的代碼規(guī)則悍引。
??
'proguard-rules.pro'
是針對我們自己的項目需要特別定義混淆規(guī)則恩脂,它位于項目根目錄下面,里面的內(nèi)容需要我們自己編寫

zipAlignEnabled true 這個在打包時需要設置為true趣斤,能優(yōu)化我們的java字節(jié)碼俩块,提高運行效率;

build.gradle編輯完成后如下圖所示:(表示發(fā)布的release包唬渗,會按照指定規(guī)則來進行混淆)

android {
    compileSdkVersion 23
    buildToolsVersion "24.0.1"
    defaultConfig {
    }
    buildTypes {
        release { //主要看這部分:
            zipAlignEnabled true
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
 ....
} 
第二步:現(xiàn)在就可以開始編輯自己的規(guī)則了

下面是一個比較簡單的proguard-rules.pro文件內(nèi)容典阵,做完這些就可以打包發(fā)布版本了

1.png

將混淆過的APK反編譯,你會發(fā)現(xiàn)里面的代碼變成了a镊逝、b壮啊、c之類的沒有意義的代號了蚣常,而且APK也變小了世吨。

2.重點來了【規(guī)則介紹】

現(xiàn)在對混淆規(guī)則做一個介紹:

先來看一看Android studio 默認包含的規(guī)則文件(proguard-android.txt 文件)里面的類容水援,我們選出幾個重點說明:

#混淆時不生成大小寫混合的類名
-dontusemixedcaseclassnames
#不忽略非公共的類庫
-dontskipnonpubliclibraryclasses
#混淆過程中打印詳細信息
-verbose

#關閉優(yōu)化
-dontoptimize
#不預校驗
-dontpreverify

# Annotation注釋不能混淆
-keepattributes *Annotation*
#對于NDK開發(fā) 本地的native方法不能被混淆
-keepclasseswithmembernames class * {
    native <methods>;
}
#保持View的子類里面的set妻顶、get方法不被混淆(*代替任意字符)
-keepclassmembers public class * extends android.view.View {
   void set*(***);
   *** get*();
}

#保持Activity子類里面的參數(shù)類型為View的方法不被混淆棚愤,如被XML里面應用的onClick方法
# 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);
}

#保持枚舉類型values()抖韩、以及valueOf(java.lang.String)成員不被混淆
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

#保持實現(xiàn)Parcelable接口的類里面的Creator成員不被混淆
-keepclassmembers class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator CREATOR;
}

#保持R類靜態(tài)成員不被混淆
-keepclassmembers class **.R$* {
    public static <fields>;
}

#不警告support包中不使用的引用
-dontwarn android.support.**
-keep class android.support.annotation.Keep
-keep @android.support.annotation.Keep class * {*;}
#保持使用了Keep注解的方法以及類不被混淆
-keepclasseswithmembers class * {
    @android.support.annotation.Keep <methods>;
}
#保持使用了Keep注解的成員域以及類不被混淆
-keepclasseswithmembers class * {
    @android.support.annotation.Keep <fields>;
}
-keepclasseswithmembers class * {
    @android.support.annotation.Keep <init>(...);
}
上面默認的規(guī)則中指示了些需要保持不能別混淆的代碼缤弦,包括:
  1. 繼承至Android組件(Activity, Service...)的類谢鹊。
  2. 自定義控件浴滴,繼承至View的類(被xml文件引用到的拓萌,名字已經(jīng)固定了的)
  3. enum 枚舉
  4. 實現(xiàn)了 android.os.Parcelable 接口的
  5. Android R文件
  6. 數(shù)據(jù)庫驅(qū)動...
  7. Android support 包等
  8. Android 的注釋不能混淆
    -keepattributes *Annotation*
  9. 對于NDK開發(fā) 本地的native方法不能被混淆
    -keepclasseswithmembernames class * { native <methods>; }
對于特定的項目還有很多不能被混淆的,需要我們自己寫規(guī)則來指示升略,將在下面來說明:
  • 對一些符號做一些說明

現(xiàn)在來看一下需要我們自己編寫的proguard-rules.pro:

#壓縮級別0-7微王,Android一般為5(對代碼迭代優(yōu)化的次數(shù))
-optimizationpasses 5 

#不使用大小寫混合類名
-dontusemixedcaseclassnames 

 #混淆時記錄日志
-verbose

#不警告org.greenrobot.greendao.database包及其子包里面未應用的應用
-dontwarn org.greenrobot.greendao.database.**
-dontwarn rx.**
-dontwarn org.codehaus.jackson.**
......
#保持jackson包以及其子包的類和類成員不被混淆
-keep class org.codehaus.jackson.** {*;}
#--------重要說明-------
#-keep class 類名 {*;}
#-keepclassmembers class 類名{*;}
#一個*表示保持了該包下的類名不被混淆;
# -keep class org.codehaus.jackson.*
#二個**表示保持該包以及它包含的所有子包下的類名不被混淆
# -keep class org.codehaus.jackson.** 
#------------------------
#保持類名品嚣、類里面的方法和變量不被混淆
-keep class org.codehaus.jackson.** {*;}
#不混淆類ClassTwoOne的類名以及類里面的public成員和方法
#public 可以換成其他java屬性如private炕倘、public static 、final等
#還可以使<init>表示構造方法翰撑、<methods>表示方法罩旋、<fields>表示成員,
#這些前面也可以加public等java屬性限定
-keep class com.dev.demo.two.ClassTwoOne {
    public *;
}
#不混淆類名,以及里面的構造函數(shù)
-keep class com.dev.demo.ClassOne {
    public <init>();
}
#不混淆類名涨醋,以及參數(shù)為int 的構造函數(shù)
-keep class com.dev.demo.two.ClassTwoTwo {
    public <init>(int);
}
#不混淆類的public修飾的方法瓜饥,和private修飾的變量
-keepclassmembers class com.dev.demo.two.ClassTwoThree {
    public <methods>;
    private <fields>;
}
#不混淆內(nèi)部類,需要用$修飾
#不混淆內(nèi)部類ClassTwoTwoInner以及里面的全部成員
-keep class com.dev.demo.two.ClassTwoTwo$ClassTwoTwoInner{*;}
......
對一些規(guī)則的解釋:

-keepattributes {name}??保護給定的屬性不被混淆浴骂,
??如:-keepattributes *Annotation*


-dontwarn {name}??不要警告指定庫中找不到的引用压固。混淆在默認情況下會檢查每個庫的引用是否正確靠闭,但是有些第三方庫里面會有用不到的類,有些沒有正確引用坎炼,所以需要對第三方庫取消警告 否則會報錯愧膀,而且有可能混淆時間會很長。
??如:-dontwarn org.codehaus.jackson.**


-keep {Modifier} {class_specification}??保留指定的類名谣光、類成員不被混淆


-keepclassmembers {modifier} {class_specification} ??保留指定的類成員不被混淆


-keepclasseswithmembers {class_specification} ??保留指定的類名檩淋、類成員不被混淆


-keepnames {class_specification} ??保留指定的類名、類成員的名稱不被混淆


-keepclasseswithmembernames {class_specification} ??保留指定的類名萄金、類成員名稱不被混淆(如果存在的話)


3.混淆后根據(jù)Crash崩潰日志反推代碼

成功打包后會在目錄*** app\build\outputs\mapping\release ***下生成幾個文件:

2.png

說明:
dump.txt 混淆后類的內(nèi)部結(jié)構說明;
mapping.txt 混淆前與混淆后名稱對應關系;
seeds.txt 經(jīng)過了一系列keep語句的保持蟀悦,沒有被混淆的類,成員的名稱列表文件氧敢。
usage.txt 經(jīng)過壓縮后被刪除的沒有使用的代碼日戈,方法...等的名稱的列表文件

retrace工具:
混淆反推工具為retrace.sh(Mac平臺)或者retrace.bat(Windows平臺)
該工具在sdk根目錄\tools\proguard\bin\retrace.sh
(Windows平臺類似);
命令格式:
*** ./retrace.sh [mapping.txt目錄] [崩潰日歷目錄]
(Windows平臺:retrace.bat [mapping.txt目錄] [崩潰日歷目錄]) ***

  • 第一步:保存Crash日志如下:截取日志保存為txt文件如:bug.txt孙乖。
03-21 03:09:32.389: E/AndroidRuntime(3582): FATAL EXCEPTION: main
03-21 03:09:32.389: E/AndroidRuntime(3582): Process: com.dev.demo, PID: 3582
03-21 03:09:32.389: E/AndroidRuntime(3582): java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.String.equals(java.lang.Object)' on a null object reference
03-21 03:09:32.389: E/AndroidRuntime(3582):     at com.dev.demo.two.b.b(Unknown Source)
03-21 03:09:32.389: E/AndroidRuntime(3582):     at com.dev.demo.a.a.printTest(Unknown Source)
03-21 03:09:32.389: E/AndroidRuntime(3582):     at com.dev.demo.MainActivity.i(Unknown Source)
03-21 03:09:32.389: E/AndroidRuntime(3582):     at com.dev.demo.MainActivity.a(Unknown Source)
03-21 03:09:32.389: E/AndroidRuntime(3582):     at com.dev.demo.MainActivity$1.onClick(Unknown Source)
  • 第二步:刪掉Crash日志中03-21 03:09:32.389: E/AndroidRuntime(3582):部分浙炼,否則無法反推還原。刪除后如下:
FATAL EXCEPTION: main
Process: com.dev.demo, PID: 3582
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.String.equals(java.lang.Object)' on a null object reference
at com.dev.demo.two.b.b(Unknown Source)
at com.dev.demo.a.a.printTest(Unknown Source)
at com.dev.demo.MainActivity.i(Unknown Source)
at com.dev.demo.MainActivity.a(Unknown Source)
at com.dev.demo.MainActivity$1.onClick(Unknown Source)
  • 第三步:打開命令窗口輸入命令:如:*** ./retrace.sh mapping.txt bug.txt ***
    如下:
3.png

按確認后得到結(jié)果如下:

FATAL EXCEPTION: main
Process: com.dev.demo, PID: 3582
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.String.equals(java.lang.Object)' on a null object reference
at com.dev.demo.two.ClassTwoThree.void test()(Unknown Source)
at com.dev.demo.one.ClassOneOne.void printTest()(Unknown Source)
at com.dev.demo.MainActivity.void printWifi()(Unknown Source)
at com.dev.demo.MainActivity.void access$000(com.dev.demo.MainActivity)(Unknown Source)
at com.dev.demo.MainActivity$1.void onClick(android.view.View)(Unknown Source) ```

除了有retrace.sh工具外還有可視化工具唯袄,和retrace.sh同目錄下proguardgui.sh弯屈,這是一塊Progurad的可視化工具:
(Windows平臺類似)
![4.png](http://upload-images.jianshu.io/upload_images/3589324-f0d492d9da432138.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

>有時為了Crash日志更容易定位可以在規(guī)則里面添加:

-keepattributes SourceFile, LineNumberTable

**這樣Crash日志里面就能保留類名稱 和行號了**

**好了,所有終于完了恋拷,希望能幫助到你资厉!謝謝!**
***
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蔬顾,一起剝皮案震驚了整個濱河市宴偿,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌阎抒,老刑警劉巖酪我,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異且叁,居然都是意外死亡都哭,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來欺矫,“玉大人纱新,你說我怎么就攤上這事∧屡浚” “怎么了脸爱?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長未妹。 經(jīng)常有香客問我簿废,道長,這世上最難降的妖魔是什么络它? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任族檬,我火速辦了婚禮,結(jié)果婚禮上化戳,老公的妹妹穿的比我還像新娘单料。我一直安慰自己,他們只是感情好点楼,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布扫尖。 她就那樣靜靜地躺著,像睡著了一般掠廓。 火紅的嫁衣襯著肌膚如雪换怖。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天蟀瞧,我揣著相機與錄音狰域,去河邊找鬼。 笑死黄橘,一個胖子當著我的面吹牛兆览,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播塞关,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼抬探,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了帆赢?” 一聲冷哼從身側(cè)響起小压,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎椰于,沒想到半個月后怠益,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡瘾婿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年蜻牢,在試婚紗的時候發(fā)現(xiàn)自己被綠了烤咧。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡抢呆,死狀恐怖煮嫌,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情抱虐,我是刑警寧澤昌阿,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站恳邀,受9級特大地震影響懦冰,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜谣沸,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一儿奶、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧鳄抒,春花似錦、人聲如沸椰弊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽秉版。三九已至贤重,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間清焕,已是汗流浹背并蝗。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留秸妥,地道東北人滚停。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像粥惧,于是被迫代替她去往敵國和親键畴。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,504評論 25 707
  • Android 開發(fā)中為了代碼安全一般都會使用 ProGuard 進行代碼混淆突雪,它可以把類名起惕、屬性名和方法名變?yōu)楹?..
    JohnnyShieh閱讀 4,211評論 2 13
  • 聲明 這篇文章更多的是做一個整理,內(nèi)容來自于ProGuard官方文檔以及各種博客等咏删,相關文章的鏈接在參考目錄里惹想,感...
    夷陵小祖閱讀 3,675評論 0 23
  • 概述 混淆是Android Apk打包過程中的一個重要步驟,默認情況下督函,打包都是需要混淆過程的嘀粱。?Android ...
    androidjp閱讀 2,590評論 1 13
  • 懷孕期間激挪,曾斷斷續(xù)續(xù)寫下數(shù)十篇日記。還留存了好多照片草穆,不時翻看灌灾,美好至極。趁產(chǎn)假時間充裕悲柱,整理記錄在此锋喜,留作紀念!...
    夜光罩著你閱讀 323評論 0 0