本文已授權(quán)微信公眾號「玉剛說」獨家發(fā)布盾似。
這篇是我們「Java 混淆那些事」第五講扛施,其實通過前四篇大家已經(jīng)能夠?qū)懗稣5幕煜?guī)則了鲫咽,這一篇是簡單的介紹一下不怎么常用的一些命令缺脉,個人覺得重要的會單獨拿出來寫個例子上真。大家可以簡單看一遍用到的時候再來查或者直接去參考官方文檔肚医。
輸入輸出選項
命令 | 解釋 |
---|---|
-include filename | 指定其他配置文件绢馍,可以指定多個。例如:-include proguard1.pro |
@filename | -include filename 的縮寫肠套。例如:@proguard1.pro舰涌、@test/proguard2.pro |
-basedirectory directoryname | 配置后續(xù)出現(xiàn)相對路徑的基目錄。他默認的基目錄是配置文件的目錄你稚,如果不存在配置文件基目錄就是工作目錄瓷耙。例如:-basedirectory 'C:\test' 朱躺,可以指定多次。注:「后續(xù)」這個詞很重要 |
-injars class_path | 指定要處理的文件( jar 或 aars哺徊,war室琢,ear,zips落追,apks 或目錄)盈滴。默認情況下,非類文件不會進行更改轿钠。請注意如果目錄中有任何臨時類文件(例如由 IDE 創(chuàng)建)不想被修改巢钓,可以過濾類路徑中的條目×贫猓可以使用多個 -injars 選項指定類路徑條目症汹。 |
-outjars class_path | 指定輸出文件(jar 或 aars,wars贷腕,ear背镇,zips,apks 或目錄)的名稱泽裳。將 -injars 選項的文件處理完成過后輸入到指定的文件瞒斩。切記輸出文件不能覆蓋任何輸入文件,否則容易出錯涮总。為了更好的可讀性胸囱,可以使用多個 -outjars 選項指定類路徑條目。如果不寫 -outjars 選項瀑梗,則不會有輸出烹笔。 |
-libraryjars class_path | 指定混淆時需要依賴的類庫文件( jar 或 aars,wars抛丽,ear谤职,zips,apk s或目錄)亿鲜。這些 jar 里面的文件不會處理和輸出柬帕,可以使用多個 -libraryjars 選項指定類路徑條目。 |
-skipnonpubliclibraryclasses | 不處理 library 里面非 public 修飾的類狡门。以加快處理速度并減少 ProGuard 的內(nèi)存使用量。 |
-dontskipnonpubliclibraryclasses | 處理 library 中非 public 類锅很。從 4.5 版本開始這是默認配置其馏。 |
-dontskipnonpubliclibraryclassmembers | 處理 library 中public 的類成員。默認不處理爆安。 |
-keepdirectories [directory_filter] | 輸出文件中保留指定目錄叛复。默認情況下,目錄會被移除。這會減少輸出文件的大小褐奥。 |
-target version | 將類文件 java 版本處理為指定版本咖耘。默認情況下,類文件的版本號保持不變撬码。例如儿倒,我們給予 Java 5 寫的項目想使用在 Java 6 的環(huán)境下,就可以通過指定 -target 更改版本號并將其預(yù)先驗證呜笑,將類文件升級夫否。但是降級需謹慎可能會有一些問題。 |
-forceprocessing | 強制輸出叫胁,即使保證輸出文件每次都是最新狀態(tài)凰慈。 |
壓縮選項
命令 | 解釋 |
---|---|
-dontshrink | 關(guān)閉壓縮功能。默認情況下驼鹅,會開啟壓縮; |
-printusage [filename] | 把被壓縮的類和方法輸出到文件逸爵。主要用來驗證自己的混淆規(guī)則正確不正確。 |
-whyareyoukeeping class_specification | 打印出壓縮過程中保留了這些類文件和類成員的具體原因帜矾。例如:-whyareyoukeeping class **Manager { *; }
|
混淆選項
命令 | 解釋 |
---|---|
-dontobfuscate | 關(guān)閉混淆功能赏陵。默認情況下,開啟混淆张足。 |
-printmapping [filename] | 把重命名的類和類成員的新触创、舊名稱的映射文件輸入到指定文件。 |
-applymapping filename | 指定要重用的映射文件为牍,映射文件中沒有的類和類成員會被混淆為新的名稱哼绑。如果代碼結(jié)構(gòu)發(fā)生根本變化,ProGuard 可能會打印出應(yīng)用映射文件導致沖突的警告碉咆。您可以通過 -useuniqueclassmembernames 在兩個混淆運行中指定選項來降低此風險抖韩。只允許一個映射文件。僅在混淆時適用疫铜。 |
-obfuscationdictionary filename | 指定類茂浮、方法及字段混淆后時用的混淆字典。默認使用 ‘a(chǎn)’壳咕,’b’ 等短名稱作為混淆后的名稱席揽。 |
-classobfuscationdictionary filename | 指定類名的混淆字典。 |
-packageobfuscationdictionary filename | 指定包名的混淆字典谓厘。 |
-overloadaggressively | 開啟侵入性重載混淆幌羞。多個字段及方法允許同名,只要它們的參數(shù)及返回值類型不同竟稳。該選項可使處理后的代碼更小(及更難閱讀)属桦。只有開啟混淆時可用熊痴。注:Dalvik 不能處理重載的靜態(tài)字段。 |
-useuniqueclassmembernames | 類和成員混淆的時候聂宾,使用唯一的名字果善。 |
-dontusemixedcaseclassnames | 不使用大小寫混合類名,注意系谐,windows用戶必須為 ProGuard 指定該選項巾陕,因為 windows 非大小寫敏感,輸出文件可能將會相互覆蓋蔚鸥。 |
-keeppackagenames [package_filter] | 不混淆指定的包名惜论。有多個包名可以用逗號隔開。包名可以包含 止喷?馆类、*、** 通配符弹谁,還可以在包名前加上 ! 否定符乾巧。只有開啟混淆時可用。如果你使用了 mypackage.MyCalss.class.getResource(""); 這些代碼獲取類目錄的代碼预愤,就會出現(xiàn)問題沟于。需要使用 -keeppackagenames 保留包名。 |
-flattenpackagehierarchy [package_name] | 將所有重命名的包重新打包到給定的單一包中植康。如果沒參數(shù)或字符串為空旷太,包移動到根包下。 |
-repackageclasses [package_name] | 把所有重命名的類重新打包到給定的單一包中销睁。如果沒參數(shù)或字符串為空供璧,類的包會被完全移除。此選項會覆蓋該 -flattenpackagehierarchy 選項冻记。低版本的參數(shù)名是 -defaultpackage 睡毒。 |
-keepattributes [attribute_filter] | 保留任何可選屬性。過濾器是由逗號分隔的 JVM 及 ProGuard 支持的屬性列表冗栗。屬性名可以包含 演顾?、*隅居、** 通配符钠至,并且可以在屬性名前加上 ! 否定符。例如:處理庫文件時應(yīng)該加上 Exceptions胎源,InnerClasses棕洋,Signature 屬性。同時保留 SourceFile 及 LineNumberTable 屬性使混淆后仍能獲取準確的堆棧信息乒融。同時如果你的代碼有使用注解你可能會保留 annotations 屬性掰盘。只有開啟混淆時可用。 |
-keepparameternames | 保留方法參數(shù)名稱和保留的方法類型赞季。 |
-renamesourcefileattribute [string] | 指定一個常量字符串作為 SourceFile 屬性的值愧捕。需要被 -keepattributes 選項指定保留。只有開啟混淆時可用申钩。 |
-adaptclassstrings [class_filter] | 混淆與完整類名一致的字符串次绘。沒指定過濾器時,所有符合現(xiàn)有類的完整類名的字符串常量均會混淆撒遣。只有開啟混淆時可用邮偎。 |
-adaptresourcefilenames [file_filter] | 以混淆后的類文件作為樣本重命名指定的源文件。沒指定過濾器時义黎,所有源文件都會重命名禾进。 |
-adaptresourcefilecontents [file_filter] | 以混淆后的類文件作為樣本混淆指定的源文件中與完整類名一致的內(nèi)容。沒指定過濾器時廉涕,所有源文件中與完整類名一致的內(nèi)容均會混淆泻云。 |
優(yōu)化選項
命令 | 解釋 |
---|---|
-dontoptimize | 關(guān)閉優(yōu)化功能。默認情況下啟用優(yōu)化狐蜕。 |
-optimizations optimization_filter | 指定優(yōu)化的粒度規(guī)則宠纯,后面的參數(shù)是一個粒度過濾器,一般不做更改默認即可层释。 |
-optimizationpasses n | 表示對你的代碼進行迭代優(yōu)化的次數(shù)婆瓜。參數(shù)是整數(shù)。一般來說設(shè)置為 10 以下即可贡羔,因為優(yōu)化次數(shù)多了也不會有什么實質(zhì)性的優(yōu)化了廉白,如果你有什么特殊業(yè)務(wù)需求,按自己需求調(diào)整就好了治力。 |
-assumenosideeffects class_specification | 優(yōu)化階段刪除指定代碼蒙秒,比如: 刪除所有日志 -assumenosideeffects class com.Log { \*; }
|
-assumenoexternalsideeffects class_specification | 優(yōu)化階段刪除指定代碼,力度比 -assumenosideeffects 強宵统,因為它可以優(yōu)化參數(shù)或堆晕讲。例如,刪除日志記錄代碼時马澈,如果日志包含 String 拼接的字節(jié)碼就可以徹底刪除了瓢省。 -assumenosideeffects 是無法在字節(jié)碼層面刪除的。 |
-assumenoescapingparameters class_specification | 指定不允許其引用參數(shù)轉(zhuǎn)義到堆的方法痊班。 這些方法可以使用勤婚,修改或返回參數(shù),但不能直接或間接地將它們存儲在任何字段中涤伐。 例如馒胆,System.arrayCopy 方法不允許其引用參數(shù)轉(zhuǎn)義缨称,但方法 System.setSecurityManager 不會。 |
-assumenoexternalreturnvalues class_specification | 指定在調(diào)用時不返回已在堆上的引用值的方法祝迂。例如睦尽,ProcessBuilder#start 返回一個 Process 引用值,但它是一個在堆上并沒有使用的新實例型雳。 |
-allowaccessmodification | 優(yōu)化時允許優(yōu)化并修改類和類的成員的訪問修飾符当凡。對外提供的 SDK 包需要注意此選項。 |
-mergeinterfacesaggressively | 指定接口可以合并纠俭,即使它們的實現(xiàn)類未實現(xiàn)合并后接口的所有方法沿量。該選項可以通過減少類的總數(shù)減少輸出文件的大小。只有開啟優(yōu)化時可用冤荆。 |
保持選項
其他選項之前的文章已經(jīng)介紹過了朴则,這里只介紹之前沒說過的。
命令 | 解釋 |
---|---|
-if class_specification | 如果 if 指定類和類成員存在匙赞,隨后的keep選項(-keep佛掖,-keepclassmembers,...)才會進行匹配涌庭。 |
-printseeds [filename] | 將詳盡列出由各種 -keep 選項匹配的類和類成員列表輸出到指定文件芥被。該列表可用于驗證是否確實找到了預(yù)期的類成員,尤其是在使用通配符時坐榆。例如拴魄,您可能希望列出您保留的所有應(yīng)用程序或所有小程序。 |
預(yù)校驗選項
命令 | 解釋 |
---|---|
-dontpreverify | 關(guān)閉預(yù)校驗功能席镀。默認情況下匹中,如果類文件針對 Java ME 或 Java 6 或更高版本,則會對其進行預(yù)驗證豪诲。對于 Java ME 顶捷,需要預(yù)驗證。對于 Java 6屎篱,預(yù)驗證是可選的服赎,但從 Java 7開始,它是必需的交播。如果類文件針對 Android 時重虑,沒有必要,因此您可以將其關(guān)閉以減少處理時間秦士。 |
-microedition | 指定已處理的類文件以 Java ME 為目標缺厉。然后,預(yù)驗證程序?qū)⑻砑舆m當?shù)腟tackMap屬性,這些屬性與 Java SE 的默認 StackMapTable 屬性不同提针。例如命爬,如果要處理 midlet,則需要此選項辐脖。 |
-android | 指定已處理的類文件以Android平臺為目標遇骑。然后ProGuard確保某些功能與 Android 兼容。 |
常規(guī)選項
命令 | 解釋 |
---|---|
-verbose | 在處理期間打印更多信息揖曾。如果程序以異常終止,則此選項將打印出整個堆棧跟蹤亥啦,而不僅僅是異常消息炭剪。 |
-dontnote [class_filter] | 指定不打印有關(guān)配置中潛在錯誤或遺漏的信息,例如配置中的類名拼寫錯誤或可能缺失有用的選項翔脱。會有提示奴拦。 |
-dontwarn [class_filter] | 指定找不到引用或其他重要問題時不打印警告信息。例如届吁,在某個類的引用中找不到相關(guān)類错妖,會有警告提示。使用 dontwarn 就可以忽略提示疚沐。 |
-ignorewarnings | 打印找不到引用或其他重要問題的警告信息暂氯。 |
-printconfiguration [filename] | 將已解析的整個配置輸出到指定文件。 |
-dump [filename] | 指定將類文件的內(nèi)部結(jié)構(gòu)輸出到指定文件亮蛔。 |
-addconfigurationdebugging | 指定用調(diào)試語句對處理過的代碼進行測試痴施,這些調(diào)試語句會打印出缺少 ProGuard 配置的建議。如果處理過的代碼由于仍然缺少一些反射配置而崩潰究流,他會提示一些簡易的配置辣吃。例如,代碼可能正在使用 GSON 庫序列化類芬探,您可能需要對其進行一些配置神得。通常,您可以將控制臺中的建議 復制/粘貼 到配置文件中偷仿。注:不要在發(fā)行版本中使用此選項哩簿,因為它會將混淆信息添加到處理過的代碼中。 |
選項參數(shù)格式
上面的命令后面有很多參數(shù)格式炎疆,我們來說一說各個參數(shù)怎么寫卡骂。
首先說一下帶 [] 的參數(shù)是可選的不是必填,而不帶 [] 的參數(shù)是必填形入。
參數(shù)名 | 作用 |
---|---|
filename | 表示具體文件名全跨,可以是相對路徑,也可以是絕對路徑亿遂。比如 test/test111.txt 浓若、test111.txt
|
string | 表示隨便一段字符串渺杉,比如 "xxx"
|
class_filter | 表示類過濾器,具體用法參考上一章類名過濾器 |
class_path | 表示類文件路徑挪钓,可以是 jars, aars, wars, ears, zips, apks 或目錄是越,可以是相對路徑,也可以是絕對路徑碌上。 |
file_filter | 表示文件過濾器倚评,具體用法參考上一篇文件相關(guān)的過濾器 |
class_specification | 表示類規(guī)范是類和類成員的模板,上一篇有提到 |
directory_filter | 表示目錄過濾器馏予,比如 com/http 天梧、com/* 具體用法參考上一篇文件相關(guān)的過濾器 |
package_name | 表示包名 com.http
|
package_filter | 表示包名過濾器,比如 com.*
|
version | 表示 Java 版本號可以是 1.0霞丧,1.1呢岗,1.2,1.3蛹尝,1.4后豫,1.5,1.6突那,1.7 (7)挫酿、1.8(8)、1.9(9)或 10 陨收。 |
還有兩個指令不是一兩句話可以說明饭豹,我們單獨拿出來講。
optimization_filter
如果有多個規(guī)則务漩,可以使用通配符或 拄衰,(逗號) 隔開寫多個規(guī)則。在調(diào)整優(yōu)化粒度規(guī)則的時候饵骨,希望你能夠研究明白再使用翘悉,以免出現(xiàn)什么問題。
支持三個通配符 ? 居触、 * 妖混、! ,它們代表什么我就不多說了。
我列舉一下固定的轮洋,其他的不穩(wěn)定的我就不列舉了制市,有需要希望大家去看看幫助文檔。
規(guī)則 | 作用 |
---|---|
class/marking/final | 盡可能將類標記為 fianl 類弊予。 |
class/unboxing/enum | 盡可能將枚舉類型簡化為整數(shù)常量祥楣。 |
class/merging/vertical | 垂直合并類 ( 上下層級的類 進行合并 )。 |
class/merging/horizontal | 水平合并類 ( 同一層級的類 進行合并 )。 |
field/removal/writeonly | 移除只讀字段误褪。 |
field/marking/private | 盡可能將字段標記為私有责鳍。 |
field/propagation/value | 在方法中傳遞屬性值。 |
method/marking/private | 盡可能將方法標記為私有兽间。 |
method/marking/static | 盡可能將方法標記為靜態(tài)历葛。 |
method/marking/final | 盡可能將方法標記為 final 方法。 |
method/removal/parameter | 刪除沒有用到的方法嘀略。 |
method/propagation/parameter | 將方法參數(shù)的值從方法調(diào)用傳到調(diào)用的方法恤溶。 |
method/propagation/returnvalue | 將方法返回的值從方法傳到它們的調(diào)用處。 |
method/inlining/short | 合并比較短的方法帜羊。 |
method/inlining/unique | 合并只調(diào)用一次的方法宏娄。 |
method/inlining/tailrecursion | 簡化尾部遞歸調(diào)用。(尾遞歸轉(zhuǎn)循環(huán)) |
code/merging | 合并相同的代碼塊逮壁。 |
code/simplification/variable | 變量加載和存儲時,使用窺孔優(yōu)化(peephole optimization)技術(shù)粮宛,一種優(yōu)化技術(shù)窥淆。 |
code/simplification/arithmetic | 對算術(shù)指令進行窺孔優(yōu)化。 |
code/simplification/cast | 對類型轉(zhuǎn)換進行窺孔優(yōu)化巍杈。 |
code/simplification/field | 對屬性加載和存儲使用窺孔優(yōu)化忧饭。 |
code/simplification/branch | 對分支指令使用窺孔優(yōu)化。 |
code/simplification/string | 對常量字符串使用窺孔優(yōu)化筷畦,最好使用 code/removal/variable 刪除词裤。 |
code/simplification/advanced | 基于控制流分析和數(shù)據(jù)流分析簡化代碼。 |
code/removal/advanced | 基于控制流分析和數(shù)據(jù)流分析刪除死代碼鳖宾。 |
code/removal/simple | 基于簡單控制流分析簡化代碼吼砂。 |
code/removal/variable | 從本地變量中,刪除未使用的變量鼎文。 |
code/removal/exception | 當 try-catch 中渔肩,try塊內(nèi)為空時,刪除exceptions拇惋。 |
code/allocation/variable | 在本地變量中優(yōu)化變量分配周偎。 |
attribute_filter
類文件實質(zhì)上定義了類,它們的字段和方法撑帖。許多基本和非必要數(shù)據(jù)作為屬性附加到這些類蓉坎,字段和方法。例如胡嘿,屬性可以包含字節(jié)碼蛉艾,源文件名,行號表等。ProGuard 的混淆步驟刪除了執(zhí)行代碼通常不需要的屬性伺通。如果我們需要保留就需要使用 -keepattributes 來進行保留箍土。同樣多個使用逗號,支持三個通配符 ? 罐监、 * 吴藻、!
可選的屬性
可選項 | 解釋 |
---|---|
*Annotation* | 注解。 |
SourceFile | 從中編譯類文件的源文件的名稱弓柱。 |
SourceDir | 從中編譯類文件的源目錄的名稱沟堡。 |
InnerClasses | 類及其內(nèi)部類和外部類之間的關(guān)系。 |
EnclosingMethod | 定義類的方法矢空。 |
Deprecated | 表示不推薦使用類航罗,字段或方法。 |
Synthetic | 表示編譯器生成了類屁药,字段或方法粥血。 |
Signature | 類、字段或方法的通用簽名酿箭,代碼可以通過反射訪問此簽名复亏。 |
MethodParameters | 方法參數(shù)的名稱和訪問標志。 |
Exceptions | 指定方法可能拋出的異常缭嫡。 |
LineNumberTable | 方法的行號缔御。 |
LocalVariableTable | 方法的局部變量的名稱和類型。 |
LocalVariableTypeTable | 方法的局部變量的名稱和泛型類型妇蛀。 |
RuntimeVisibleAnnotations | 在運行時耕突,類,字段和方法可見的注釋评架。 |
RuntimeInvisibleAnnotations | 在編譯時對類眷茁,字段和方法可見的注釋。 |
RuntimeVisibleParameterAnnotations | 方法參數(shù)在運行時可見的注釋纵诞。 |
RuntimeInvisibleParameterAnnotations | 方法參數(shù)在編譯時可見的注釋蔼卡。 |
RuntimeVisibleTypeAnnotations | 在運行時可見的注釋,用于泛型類型挣磨,指令等雇逞。 |
RuntimeInvisibleTypeAnnotations | 在編譯時可見的注釋,用于泛型類型茁裙,指令等塘砸。 |
AnnotationDefault | 注釋的默認值。 |
例子
flattenpackagehierarchy
// 混淆規(guī)則
-keep class **Manager {
<fields>;
<methods>;
}
-flattenpackagehierarchy "xxx"
混淆前的結(jié)構(gòu)
混淆后的結(jié)構(gòu)
- 所有改變包名的都放到了 xxx 包下
repackageclasses
// 混淆規(guī)則
-keep class **Manager {
<fields>;
<methods>;
}
-repackageclasses "xxx"
混淆前的結(jié)構(gòu)
混淆后的結(jié)構(gòu)
- 所有改變類名的類都放到了 xxx 包下
adaptclassstrings
// 混淆規(guī)則
-keep class **Manager {
<fields>;
<methods>;
}
-keepclassmembers,allowobfuscation class **{
public java.lang.String get();
}
-adaptclassstrings
// 混淆前的代碼
public String get() {
String ss1 = "com.test.http.HttpRequest";
return "請求成功 "+ss1;
}
// 混淆后的代碼
public String a() {
return "請求成功 " + "com.test.a.a";
}
- 混淆與類名相同的字符串晤锥,用途大家可以想一想掉蔬,比如反射的時候可以用廊宪。
Class.forName("com.test.http.HttpRequest")
adaptresourcefilenames
// 混淆規(guī)則
-keep class **Manager {
<fields>;
<methods>;
}
-adaptresourcefilenames
混淆前的資源文件
混淆后的資源文件
- 混淆與類名相同的資源文件
renamesourcefileattribute
// 混淆腳本
-keepattributes SourceFile
-renamesourcefileattribute "renamesourcefileattribute Test"
// 代碼
/* compiled from: renamesourcefileattribute Test */
public final class a {
}
發(fā)現(xiàn)保留了 SourceFile 屬性,并且指定了一個字符串女轿。
adaptresourcefilecontents
// 混淆腳本
-adaptresourcefilecontents
//混淆前的資源文件
test:com.test.http.HttpRequest
//混淆后的資源文件
test:com.test.a.a
- 大家可以想想用途箭启,比如 Android 中想混淆 Activity 就需要修改清單文件類路徑,這個屬性就可以自動修改了蛉迹。
小結(jié)
這一篇內(nèi)容比較多大家過一遍就好傅寡,如果你自己覺得還有其他能用到的選項就需要自己動手去試一試效果了。