參考文章:
QuincySx:java混淆那些事系列文章:目錄
QuincySx:java混淆那些事系列文章:keep語法
QuincySx:java混淆那些事系列文章:keep 通配符
java proguard混淆通配符
QuincySx:java混淆那些事系列文章:混淆中常用命令
- 混淆的功能
- 壓縮 (Shrinker):刪除無效的類、字段、方法等。
- 優(yōu)化 (Optimizer):優(yōu)化字節(jié)碼,合并方法,刪除無用字段等。
- 混淆 (Obfuscator):將類名、屬性名、方法名以及字段名混淆為難以讀懂的字母,比如a, b, c等。
- 預(yù)校驗(yàn) (Preverifier):對 class 文件進(jìn)行預(yù)檢驗(yàn),確保虛擬機(jī)加載的 class 文件是安全并且可以執(zhí)行的。
-
混淆的功能流程圖:
串行執(zhí)行
- 混淆的常見命令
| 命令 | 解釋 |
|---|---|
| -dontshrink | 關(guān)閉壓縮功能 |
| -dontoptimize | 關(guān)閉混淆功能 |
| -dontusemixedcaseclassnames | 不使用大小寫混合類名,注意,windows用戶必須為 ProGuard 指定該選項(xiàng),因?yàn)?windows 非大小寫敏感,輸出文件可能將會(huì)相互覆蓋 |
| -dontskipnonpubliclibraryclasses | 處理 library 中非 public 類。從 4.5 版本開始這是默認(rèn)配置 |
| -verbose | 打印log信息盡可能詳細(xì) |
| -useuniqueclassmembernames | 把混淆類中的方法名也混淆了 |
| -renamesourcefileattribute SourceFile | 將文件來源重命名為“SourceFile”字符串 ,指定一個(gè)常量字符串作為 SourceFile 屬性的值。需要被 -keepattributes 選項(xiàng)指定保留。只有開啟混淆時(shí)可用 |
| -obfuscationdictionary filename | 指定類、方法及字段混淆后時(shí)用的混淆字典。默認(rèn)使用 ‘a(chǎn)’,’b’ 等短名稱作為混淆后的名稱 |
| -classobfuscationdictionary filename | 指定類名的混淆字典。 |
| -packageobfuscationdictionary filename | 指定包名的混淆字典。 |
| -keeppackagenames [package_filter] | 不混淆指定的包名。有多個(gè)包名可以用逗號(hào)隔開。包名可以包含 ?、、* 通配符,還可以在包名前加上 ! 否定符。只有開啟混淆時(shí)可用。如果你使用了 mypackage.MyCalss.class.getResource(""); 這些代碼獲取類目錄的代碼,就會(huì)出現(xiàn)問題。需要使用 -keeppackagenames 保留包名。 |
| -keepattributes [attribute_filter] | 保留任何可選屬性。過濾器是由逗號(hào)分隔的 JVM 及 ProGuard 支持的屬性列表。屬性名可以包含 ?、、* 通配符,并且可以在屬性名前加上 ! 否定符。例如:處理庫文件時(shí)應(yīng)該加上 Exceptions,InnerClasses,Signature 屬性。同時(shí)保留 SourceFile 及 LineNumberTable 屬性使混淆后仍能獲取準(zhǔn)確的堆棧信息。同時(shí)如果你的代碼有使用注解你可能會(huì)保留 annotations 屬性。只有開啟混淆時(shí)可用。 |
| -keepparameternames | 保留方法參數(shù)名稱和保留的方法類型。 |
| -dontoptimize | 關(guān)閉優(yōu)化功能 |
| -optimizationpasses n | 針對代碼優(yōu)化迭代次數(shù),通常小于10 |
| -assumenosideeffects class_specification | 優(yōu)化階段刪除指定代碼,比如: 刪除所有日志 -assumenosideeffects class com.Log { *; } |
| -assumenoexternalsideeffects class_specification | 優(yōu)化階段刪除指定代碼,力度比 -assumenosideeffects 強(qiáng),因?yàn)樗梢詢?yōu)化參數(shù)或堆。例如,刪除日志記錄代碼時(shí),如果日志包含 String 拼接的字節(jié)碼就可以徹底刪除了。 -assumenosideeffects 是無法在字節(jié)碼層面刪除的。 |
| -dontpreverify | 關(guān)閉預(yù)校驗(yàn)功能 |
| -dontwarn [class_filter] | 指定找不到引用或其他重要問題時(shí)不打印警告信息。例如,在某個(gè)類的引用中找不到相關(guān)類,會(huì)有警告提示。使用 dontwarn 就可以忽略提示。 |
| -ignorewarnings | 打印找不到引用或其他重要問題的警告信息。 |
備注:其余一些命令可以參考參考文章中的混淆中的常用命令
- 混淆的keep語法
| 命令 | 解釋 |
|---|---|
| -keep [,modifier,…] class_specification | 匹配類名以及指定的方法或字段,為代碼入口點(diǎn)。可以單獨(dú)匹配類或者類和類成員。匹配到的類不會(huì)被混淆和刪除,匹配到的類成員不會(huì)被混淆和刪除,方法被當(dāng)作代碼入口點(diǎn) |
| -keepclassmembers [,modifier,…] class_specification | 匹配類名以及規(guī)則指定的方法或字段,為代碼入口點(diǎn)。但是有個(gè)前提:就是必須在壓縮階段被保留的類才可以。 |
| -keepclasseswithmembers [,modifier,…] class_specification | 它和 -keep 的作用基本一致,但是規(guī)則必須完全匹配類名以及類成員才能匹配成功,寫錯(cuò)類成員名稱或?qū)懖淮嬖陬惓蓡T名稱都會(huì)導(dǎo)致整條規(guī)則失效。 |
備注:
- 第二條和第一條相比區(qū)別是:持有的類和方法參與混淆的刪除清理功能,若過了刪除清理功能則不參與后續(xù)的混淆
- 第三條和第二條相比區(qū)別是:第三條絕對匹配即和跟定的類規(guī)則完全匹配才不參與對應(yīng)的混淆,通常情況下此條不經(jīng)常使用。
- 混淆的通配符規(guī)則
- 類過濾器:
| 符號(hào) | 功能 |
|---|---|
| ? | 可以匹配任意一個(gè)字符,但是 package 的分隔符(.)除外,例如:com.example.T?st,可以匹配 com.example.Test,com.example.T2st,但是 com.example.T12st 、com.example.Tst 和 com.example.T.st 不可以。 |
| * | 可以匹配任意一部分連續(xù)的字符,但是 package 的分隔符(.)除外,例如 com.example.Test,可以匹配 com.example.Test,com.example.AnyTest,但是 com.example.xxx.Test 不可以,還有一個(gè)特例 com.example. 只能匹配當(dāng)前包下的類,com.example.xxx.Test 就匹配不到。 |
| ** | 可以匹配任意一部分連續(xù)的字符,例如 com**,可以匹配 com.Test,com.example.Test,com.example.java.Test |
| <num> | 在同一匹配規(guī)則中匹配和第 n 個(gè)通配符一致的內(nèi)容。例如:*Any<1>,可以匹配到 TestAnyTest ,TestAnytest 不可以。即后面的內(nèi)容和數(shù)字指定的通配符當(dāng)前的內(nèi)容一致才匹配 |
備注:* 和 ** 的區(qū)別是:* 通常只能匹配當(dāng)前文件夾,*則可以當(dāng)前和子文件夾,即 不能匹配文件夾的分隔符.。
<num>:則是代表當(dāng)前第num個(gè)通配符指向的字符,匹配的時(shí)候先去看第num個(gè)通配符指向字符,此時(shí)占位的字符和其相同則匹配。
- 字段和方法名過濾器:
| 符號(hào) | 功能 |
|---|---|
| <init> | 匹配所有構(gòu)造方法 |
| <fields> | 匹配所有字段 |
| <methods> | 匹配所有方法 |
| ? | 匹配單個(gè)字符,包名分隔符(.)除外 |
| * | 匹配除(.)外的任意字符 |
| <num> | 在同一匹配規(guī)則中匹配和第 n 個(gè)通配符一致的內(nèi)容。 |
- 類型通配符:
| 符號(hào) | 功能 |
|---|---|
| [] | []表示內(nèi)部內(nèi)容是可選的 |
| % | 匹配所有基本類型:int,boolean等 |
| ? | 匹配類名中的任何單個(gè)字符 |
| * | 匹配不包含包分隔符的類名的任何部分。 |
| ** | 匹配類名的任何部分,可能包含任意數(shù)量的包分隔符 |
| *** | 匹配所有任何類型 |
| ... | 匹配任何類型任何數(shù)量的參數(shù) |
| <num> | 在同一匹配規(guī)則中匹配和第 n 個(gè)通配符一致的內(nèi)容 |