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