Java代码保密技术之(一)Proguard配置选项说明

ProGuard是一个开源的Java类文件(.class)处理工具,它同时提供了命令行和图形界面。

ProGuard能够:

  1. 压缩(Shrunk ):检测未使用的类、字段、方法、属性,并移除
  2. 优化(Optimization):分析并优化方法的字节码,可以进行多步骤的优化
  3. 混淆(Obfuscation ):重命名类、字段、方法,使用更短且无意义的名字
  4. 预校验(Preverification ):为字节码添加预校验信息,预校验信息对Java 6+是需要的

上述功能可以单独使用,也可以在一次调用中按照下面的步骤一次性完成:

参数选项说明:

 选项

说明 

-injars classpath

指定输入的压缩包或者目录

-outjars classpath

指定输出的压缩包或者目录

-libraryjars classpath

指定输入所依赖的库。

需要注意的是,程序使用的运行时库需要明确指定(例如rt.jar)

-skipnonpubliclibraryclasses

是否跳过依赖库中非public类,默认不跳过,跳过可以提升性能,因为库的非公共类一般与程序无关

-dontskipnonpubliclibraryclasses

不跳过依赖库中的非public类

-dontskipnonpubliclibraryclassmembers

不跳过依赖库中的非public类的成员,包括字段、方法

-keepdirectories filter

指定要保留的目录。

默认情况下所有目录都被移除

-target version

指定输出class的版本,默认保持和输入版本一致。

保留选项说明

选项

说明

-keepclassmembers

-keepclassmembers [,modifier,...] class_spec  指定要保留的类成员,如果它们所属的类被保留的话

-keepclasseswithmembers

-keepclasseswithmembers [,modifier,...] class_spec 指定需要保留的类及其成员,包括方法和变量

-keepnames class_spec

指定需要保留的类和类成员,如果在压缩阶段这些类没有被删除的话。该选项仅用于混淆阶段

-keepclassmembernames

指定名称要保留的类成员,如果在压缩阶段这些类没有被删除的话。该选项仅用于混淆阶段

-keepclasseswithmembernames

指定要保留的类和类成员,如果所有指定的类成员在经历了压缩阶段还存在

-printseeds [filename]

打印所有匹配-keep的类和类成员,默认打印到标准输出

支持通过配置文件提供选项,配置文件中的注释以#开始。选项中,文件名具有空格的,必须使用引号包含。 

注意选项的命名规律:-keep*用于防止目标被移除或者重命名、-keep*names则仅仅用于防止重命名。

压缩选项

选项 

说明 

-dontshrink 

不压缩,默认压缩输入文件:除了匹配-keep的、以及它们直接、间接依赖的所有类、类成员,都被移除。压缩阶段可能随着优化阶段运行

-dontobfuscate

是否进行混淆,默认是。除了匹配-keep系列选项的类、类成员的名字将被随机的改为短名。为了方便调试而保留的内部属性,例如源代码名称、变量名、行号,都将被移除

-printmapping [filename]

打印混淆前后类名、类成员名的对照

-applymapping filename

指定一个先前生成的混淆名对照表,本次依照该对照继续混淆,不在表中的成员生成新的名字

-obfuscationdictionary filename

指定存放有效混淆后变量名的文件

-overloadaggressively

混淆时支持激进的重载,允许多个字段、方法使用重复的名字,只要参数和返回值不同

-useuniqueclassmembernames

让不同名的类成员具有不同的混淆后的名称,让同名的类成员混淆后的名称依旧相同

-dontusemixedcaseclassnames

混淆后,不使用混合大小写的类名

-keeppackagenames [pkg_filter]

指定不混淆的包的过滤器,过滤器支持* **和前导的!

-flattenpackagehierarchy [pkg_name]

对所有被重命名的包进行重新打包,如果不指定参数值,则打包到根目录

-repackageclasses [pkg_name]

对所有被重命名的类进行重新打包,如果不指定参数值,则打包到根目录

-keepattributes [attr_filter]

指定需要保留的所有可选属性,参数值是逗号分隔的,在处理库的时候,至少应该保留Exceptions, InnerClasses, Signature属性,如果程序依赖于注解,则应该保留

-keepparameternames

保留方法参数的名称和类型。

注意,方法局部变量的名称依旧会混淆

-renamesourcefileattribute [string]

设置SourceFile、SourceDir 属性为指定的常量值

-adaptclassstrings [class_filter]

代表了类名的字符串常量值,是否也被混淆(与目标类的名字保持一致)。如果不指定参数值,所有代表类名的字符串常量都被混淆

-adaptresourcefilenames [file_filter]

是否重命名资源文件,如果其文件名反映了一个被混淆的类的名字

-adaptresourcefilecontents [file_filter]

是否修改资源文件中的类名,如果对应的类的名字已经被混淆。ProGuard使用平台默认字符集读取文件,如果需要改变这一行为,需要设置LANG环境变量或者JVM系统属性file.encoding

优化选项

选项

说明

-dontoptimize

不进行优化。默认情况下优化启用,所有方法都在字节码级别进行优化

-optimizations opt_filter

在更细粒度上控制进行哪些优化

-optimizationpasses n

优化的步骤数,默认1步,如果发现没有可优化的,后续步骤自动省略

-assumenosideeffects class_spec

指定不具有副作用(不改变任何状态信息)的方法规格,如果这些方法的返回值没有被使用,那么这样的调用会清除

-allowaccessmodification

是否允许放宽类、类成员的访问限定符。这可能有利于优化,例如对getter()进行内联,需要相应字段成为public的

-mergeinterfacesaggressively

允许接口合并,甚至在实现类没有实现所有接口方法的情况下

混淆选项

选项

说明 

-verbose

在处理时打印冗长的信息

-dontnote [class_filter]

不打印配置选项中,与正则式匹配的类相关的错误或者疏忽

-dontwarn [class_filter]

不打印配置选项中,与正则式匹配的类相关的重要错误,例如unresolved references 

-ignorewarnings

忽略所有警告,强制进行处理。这可能很危险

-printconfiguration [filename]

打印解析后的配置信息到目标文件

-dump [filename]

打印处理后的类文件的内部结构

预校验选项

选项

说明 

-dontpreverify

指定不进行字节码预校验,对于Java6+默认开启

-microedition

只是目标类文件将在JME平台上运行

一般选项

类路径和过滤器

ProGuard支持通过Classpath指定输入文件、输出文件。Classpath的条目使用传统的分隔符(Unix:,Windows;),条目的顺序决定优先级,如果出现重复类,前面的生效。

每个输入条目可以是 :类/资源文件、apk、jar、war、aar、zip、目录;每个输出条目可以是apk、jar、war、aar、zip、目录。各种压缩包类型支持嵌套,每个输入条目输出到最接近它的输出条目中。

ProGuard支持对Classpath条目的内容进行过滤,下面是几个例子:

  1. rt.jar(java/**.class,javax/**.class) 匹配rt.jar中所有java/javax开头的包中的类
  2. input.jar(!**.gif,images/**)匹配input.jar中images/目录中所有文件,除了GIF
  3. input.war(lib/**.jar,support/**.jar;**.class,**.gif)  匹配input.war的lib、support目录下所有jar,以及所有类文件和GIF文件

?匹配文件名中的单个字符;通配符*匹配文件名中的多个字符;**匹配路径中的任意字符(包括多级目录层次);!表示取反。这种过滤器语法适用于配置选项的多个方面,例如文件、目录、类、包、属性、优化,等等。

类规格(class_spec)

类规格用于指定类、类成员的匹配规则,语法如下:

# [] 表示其中的内容是可选的

# ... 表示前面列表中的项的任意组合是支持的

# | 用于分割两个备选项

# class/interface/enum用于引用相应的Java类型

# classname为全限定的类名,内部类使用$界定,例如java.lang.Thread$State。类名支持* ** ?通配符

# extends/implements的作用引用继承或者实现的Java类型

# @用于限定类、类成员被指定的类型所注解,annotationtype的格式和class一致

# <init> <fields> <methods> *分别匹配任意构造器、任意字段、任意方法和任意类成员

# 字段名、方法名支持通配符?、*

# argumenttype fieldtype returntype等支持以下通配符:

# %匹配任意基本类型;?匹配类名的单个字符;*匹配类全名中的多个字符,单不能跨越包分隔符 **匹配类全名中任意多个字符

# ***匹配任意类型;...匹配任意类型的任意数量的参数

#保留main函数为入口点

-keep public class mypackage.MyMain {

    public static void main(java.lang.String[]);

}

压缩、优化并混淆一个库的典型配置:

-injars       in.jar

-outjars      out.jar

-libraryjars  <java.home>/lib/rt.jar

-printmapping out.map

#保留本地变量表(LocalVariableTable)、本地变量类型表(LocalVariableTypeTable)

-keepparameternames

-renamesourcefileattribute SourceFile

#保留异常表,以便编译器知道哪些异常可能被抛出

#保留InnerClasses,否则外部无法引用内部类

#保留Signature,否则无法访问泛型

-keepattributes Exceptions,InnerClasses,Signature,Deprecated,

                SourceFile,LineNumberTable,*Annotation*,EnclosingMethod

#保留所有公共类的公共/保护方法,这是库暴露的接口部分

-keep public class * {

    public protected *;

}

#保留native方法的规格,以便能与native库链接

-keepclasseswithmembernames,includedescriptorclasses class * {

    native <methods>;

}

 #保留枚举类

-keepclassmembers,allowoptimization enum * {

    public static **[] values();

    public static ** valueOf(java.lang.String);

}

#保留必要的类成员,以便串行化机制可用

-keepclassmembers class * implements java.io.Serializable {

    static final long serialVersionUID;

    private static final java.io.ObjectStreamField[] serialPersistentFields;

    private void writeObject(java.io.ObjectOutputStream);

    private void readObject(java.io.ObjectInputStream);

    java.lang.Object writeReplace();

    java.lang.Object readResolve();

}

通过指定日志方法没有副作用,可以移除代码中的日志记录调用:

-assumenosideeffects interface org.slf4j.Logger {

    public void trace(...);

    public void debug(...);

    public void info(...);

    public void warn(...);

    public void error(...);

}

-injars      in.jar

-outjars     out.jar

-libraryjars <java.home>/lib/rt.jar

-dontshrink

-dontoptimize

-dontobfuscate

-target 1.8

保留所有类、类成员上的所有注解设置:

1

-keepattributes *Annotation*

保留数据库驱动:

#数据库驱动往往是动态加载的

-keep class * implements java.sql.Driver

使用依赖注入的应用中,防止私有类成员被移除:

-keepclassmembers class * {

    @javax.annotation.Resource *;

}

-keepclassmembers class * {

    @javax.inject.Inject *;

}

-keepclassmembers class * {

    @org.springframework.beans.factory.annotation.Autowired *;

}

当程序被混淆后,适配资源文件名、资源文件内容:

1

2

-adaptresourcefilenames    **.properties,**.gif,**.jpg

-adaptresourcefilecontents **.properties,META-INF/MANIFEST.MF

也可以通过Maven插件proguard-maven-plugin进行集成

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值