ProGuard使用文档
介绍
是一个对于Java字节码的免费的压缩器,优化器,混淆器和审核器;
l 它检测并删除未使用的类,字段,方法和属性。
l 它优化字节码并删除未使用的指令。
l 它重命名其余类、字段和方法使用短毫无意义的名字。
官方文档
使用文档
https://www.guardsquare.com/en/products/proguard/manual/usage
常见问题文档:
https://www.guardsquare.com/en/products/proguard/manual/troubleshooting
了解通配符:
指定类时,可以使用如下通配符
- class 关键字表示任意的类或接口
- interface 关键字只表示接口
- enum 关键字表示枚举类
- interface 和 enum 关键字可以加上 !表示除...之外
- ?匹配任意字符,不包括包分隔符
- 匹配任意多个字符,不包括包分隔符
- ** 匹配任意多个字符,包括包分隔符
- 为了向后兼容,* 也可以表示任意的类,包括包分隔符
- extends 和 implements 关键字是等效的,表示继承或实现 A 的类,但不包括 A 本身
- @ 关键字用于表示使用指定注解修饰的类和类成员
指定类的成员时,可以指定如下通配符
- <init> 匹配任意的构造器
- <fileds> 匹配任意的成员变量
- <methods> 匹配任意的方法
匹配任意的成员变量或方法
- 上述通配符不含返回类型,只有<init>有参数列表
- 除了使用上述全能通配符以外,同样可以使用常用表达式,此时可以使用 ? 和 * 通配符
- 指定修饰符的类型时,可以使用如下通配符
- % 匹配基本类型
- ? 匹配任一字符
- 匹配任意多个字符,不含包分隔符
- ** 匹配任意多个字符,包含包分隔符
- *** 匹配任意类型(基本或非基本,数组或非数组)
- ... 匹配任意数量、任意类型的参数
- ? * 和 ** 不会匹配基本类型
- 可以使用权限控制符帮助匹配(例如 public static)
参考来源:
https://www.guardsquare.com/en/products/proguard/manual/usage#filename
使用 ProGuard GUI
输入输出部分
需要确保目录结构为jar目录结构:
错误的目录结构:
如果目录结构是下面这种类web目录结构,混淆器无法正确混淆,process会提示大量警告 … unexpectedly contains class …
或者根据官方文档上的解决方法,将打包的jar包放入lib目录,执行混淆(这个没有试验)
为了得到这种目录结构,可将项目由eclipse打开,仅对src/main/java项目下的源代码文件导出为jar文件
将该jar包作为输入,add Input
依赖库需要添加jre目录下的所有jar和 项目所有的依赖项 lib目录下的jar包
输出名字自定义
依赖库除了jre下的jar包,其他依赖根据项目使用情况加入,圈起来的两个是关键jar包
点击Next
----------------------------------------------------------------------------------------------------------------
压缩部分
不勾选,表示不压缩
Keep 输入框
保留某些类,成员不被混淆,(不明白它这个为什么放在压缩部分)
在配置文件中的形式:
-keep public class cn.xxx.xxx.controller.* { <fields>; <methods>; }
#我的model目录结构为 model/po , model/vo ,所以为 model.*.*
-keep public class cn.xxx.xxx.model.*.* { <fields>; <methods>; }
主启动类:
-keep class cn.xxx.xxx.XXXApplication { *** main(...); }
该部分功能: 删除没有使用的的类或成员
注意:保留启动类
点击next
------------------------------------------------------------------------------------------------------------------
混淆部分
该部分功能: 对代码进行模糊处理,混淆类名、方法名和变量名(使用单字母a,b,c,d,e,f,g…)
介绍一下勾选所代表的意思:
Obfuscate :启用混淆功能
Use unique class member name: 使用统一的类名称
Keep package names:保留包名
Keep attarbute:保留的属性、异常、注解等
Keep paremeter name:保留方法参数名
Keep native: 保留本地方法
-----------------------------------------------------------------------------------------------------------------------------
优化部分
不勾选,表示不优化
Allow access modification: 允许修改
该部分功能:它内联并合并类和类成员,并在字节码级别优化所有方法。
---------------------------------------------------------------------------
信息部分
Prevify:验证
Target: 更据JDK版本选择
Note: 提示
Warn: 警告
Skip non-public library classes: 指定在读取库jar时跳过非公共类,以加快处理速度并减少ProGuard的内存使用量
Skip non-public library class members: 指定跳过包可见的库类成员(字段和方法)
如果实在有警告,解决不了,可以勾选忽略警告
配置文件全部内容
-injars target.jar -outjars result.jar -libraryjars 'D:\Program Files\Java\jdk1.8.0_241\jre\lib\charsets.jar' -libraryjars 'D:\Program Files\Java\jdk1.8.0_241\jre\lib\deploy.jar' -libraryjars 'D:\Program Files\Java\jdk1.8.0_241\jre\lib\javaws.jar' -libraryjars 'D:\Program Files\Java\jdk1.8.0_241\jre\lib\jce.jar' -libraryjars 'D:\Program Files\Java\jdk1.8.0_241\jre\lib\jfr.jar' -libraryjars 'D:\Program Files\Java\jdk1.8.0_241\jre\lib\jfxswt.jar' -libraryjars 'D:\Program Files\Java\jdk1.8.0_241\jre\lib\jsse.jar' -libraryjars 'D:\Program Files\Java\jdk1.8.0_241\jre\lib\management-agent.jar' -libraryjars 'D:\Program Files\Java\jdk1.8.0_241\jre\lib\plugin.jar' -libraryjars 'D:\Program Files\Java\jdk1.8.0_241\jre\lib\resources.jar' -libraryjars 'D:\Program Files\Java\jdk1.8.0_241\jre\lib\rt.jar' -libraryjars lib\HikariCP-3.4.1.jar -libraryjars lib\byte-buddy-1.10.2.jar -libraryjars lib\classmate-1.5.1.jar -libraryjars lib\commons-codec-1.13.jar -libraryjars lib\commons-lang3-3.4.jar -libraryjars lib\druid-1.1.9.jar -libraryjars lib\druid-spring-boot-starter-1.1.9.jar -libraryjars lib\guava-20.0.jar -libraryjars lib\hibernate-validator-6.0.18.Final.jar -libraryjars lib\jackson-annotations-2.10.0.jar -libraryjars lib\jackson-core-2.10.0.jar -libraryjars lib\jackson-databind-2.10.0.jar -libraryjars lib\jackson-datatype-jdk8-2.10.0.jar -libraryjars lib\jackson-datatype-joda-2.10.0.jar -libraryjars lib\jackson-datatype-jsr310-2.10.0.jar -libraryjars lib\jackson-module-parameter-names-2.10.0.jar -libraryjars lib\jakarta.annotation-api-1.3.5.jar -libraryjars lib\jakarta.validation-api-2.0.1.jar -libraryjars lib\java-jwt-3.4.0.jar -libraryjars lib\jboss-logging-3.4.1.Final.jar -libraryjars lib\joda-time-2.10.5.jar -libraryjars lib\jsqlparser-1.0.jar -libraryjars lib\jul-to-slf4j-1.7.29.jar -libraryjars lib\log4j-api-2.12.1.jar -libraryjars lib\log4j-to-slf4j-2.12.1.jar -libraryjars lib\logback-classic-1.2.3.jar -libraryjars lib\logback-core-1.2.3.jar -libraryjars lib\lombok-1.18.10.jar -libraryjars lib\mapstruct-1.2.0.Final.jar -libraryjars lib\mybatis-3.4.6.jar -libraryjars lib\mybatis-spring-1.3.2.jar -libraryjars lib\mybatis-spring-boot-autoconfigure-1.3.2.jar -libraryjars lib\mybatis-spring-boot-starter-1.3.2.jar -libraryjars lib\ojdbc8-19.3.0.0.jar -libraryjars lib\ons-19.3.0.0.jar -libraryjars lib\oraclepki-19.3.0.0.jar -libraryjars lib\orai18n-12.1.0.2.0.jar -libraryjars lib\osdt_cert-19.3.0.0.jar -libraryjars lib\osdt_core-19.3.0.0.jar -libraryjars lib\pagehelper-5.1.4.jar -libraryjars lib\pagehelper-spring-boot-autoconfigure-1.2.5.jar -libraryjars lib\pagehelper-spring-boot-starter-1.2.5.jar -libraryjars lib\simplefan-19.3.0.0.jar -libraryjars lib\slf4j-api-1.7.29.jar -libraryjars lib\snakeyaml-1.25.jar -libraryjars lib\spring-aop-5.2.1.RELEASE.jar -libraryjars lib\spring-beans-5.2.1.RELEASE.jar -libraryjars lib\spring-boot-2.2.1.RELEASE.jar -libraryjars lib\spring-boot-autoconfigure-2.2.1.RELEASE.jar -libraryjars lib\spring-boot-starter-2.2.1.RELEASE.jar -libraryjars lib\spring-boot-starter-jdbc-2.2.1.RELEASE.jar -libraryjars lib\spring-boot-starter-json-2.2.1.RELEASE.jar -libraryjars lib\spring-boot-starter-logging-2.2.1.RELEASE.jar -libraryjars lib\spring-boot-starter-tomcat-2.2.1.RELEASE.jar -libraryjars lib\spring-boot-starter-validation-2.2.1.RELEASE.jar -libraryjars lib\spring-boot-starter-web-2.2.1.RELEASE.jar -libraryjars lib\spring-context-5.2.1.RELEASE.jar -libraryjars lib\spring-core-5.2.1.RELEASE.jar -libraryjars lib\spring-expression-5.2.1.RELEASE.jar -libraryjars lib\spring-jcl-5.2.1.RELEASE.jar -libraryjars lib\spring-jdbc-5.2.1.RELEASE.jar -libraryjars lib\spring-plugin-core-1.2.0.RELEASE.jar -libraryjars lib\spring-plugin-metadata-1.2.0.RELEASE.jar -libraryjars lib\spring-tx-5.2.1.RELEASE.jar -libraryjars lib\spring-web-5.2.1.RELEASE.jar -libraryjars lib\spring-webmvc-5.2.1.RELEASE.jar -libraryjars lib\springfox-core-2.9.2.jar -libraryjars lib\springfox-schema-2.9.2.jar -libraryjars lib\springfox-spi-2.9.2.jar -libraryjars lib\springfox-spring-web-2.9.2.jar -libraryjars lib\springfox-swagger-common-2.9.2.jar -libraryjars lib\springfox-swagger-ui-2.9.2.jar -libraryjars lib\springfox-swagger2-2.9.2.jar -libraryjars lib\swagger-annotations-1.5.20.jar -libraryjars lib\swagger-models-1.5.20.jar -libraryjars lib\tomcat-embed-core-9.0.27.jar -libraryjars lib\tomcat-embed-el-9.0.27.jar -libraryjars lib\tomcat-embed-websocket-9.0.27.jar -libraryjars lib\ucp-19.3.0.0.jar -skipnonpubliclibraryclasses -target 1.8 -dontshrink -dontoptimize -allowaccessmodification -printmapping map.txt -useuniqueclassmembernames -dontusemixedcaseclassnames -keeppackagenames -keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,LocalVariable*Table,*Annotation*,Synthetic,EnclosingMethod -keep public class cn.xxx.xxx.controller.* { } -keep public class cn.xxx.xxx.model.*.* { <fields>; <methods>; } -keep class cn.xxx.xxx.XXXApplication { *** main(...); } -keep class cn.xxx.xxx.mapper.* { <methods>; } # Keep - Native method names. Keep all native class/method names. -keepclasseswithmembers,includedescriptorclasses,allowshrinking class * { native <methods>; }
混淆效果:
类名被混淆:
未保留类名称被混淆
方法名被更改:
变量名被混淆:
混淆验证
将混淆后的jar包解压后的class文件替换原来项目编译后的可执行文件,idea中一般是 target/classes 目录下。
替换完成,运行项目,项目正常启动运行,接口正常访问,则说明混淆没有问题。
混淆成功后但运行失败常见的问题:
Bean名冲突:
l 启动报错BeanDefinitionStoreException,
如果使用@MapperScan()、@Configuration,@Component、@Service等注解没有为bean命名时,bean会以类名作为bean名称注入spring容器,由于混淆器的命名规则是对包下的类按原名进行排序,然后分配a,b,c,d…等名称,会导致不同包下有类获得相同的名称注入到bean容器,造成bean冲突
解决:
如果使用默认的命名规则,在勾选了use mix-case class names (使用混合大写命名规则),包中超过26个类时情况下,默认命名为A.class,B.class,C.class…在某些操作系统(windows)下,会因为不区分class文件名称的大小写,会导致错误.
解决:取消勾选use mix-case class names
接口访问失败:
l如果是mybatis映射架构,访问接口失败,可查看编译后的接口文件类名,接口名称已经被更改,而对应得xml文件,xml中得sql语句无法与相应得接口名进行绑定,报绑定异常BindingException
解决:所以mapper层类名、方法名都不可更改
所以mapper层需要保留类名和方法名不被混淆
-keep class cn.hulingfeng.ylzdemo.mapper.* {
<methods>;
}
额外内容
打印混淆的映射关系,会清楚的告诉你混淆的映射关系
apply mapping:
则是根据自己自定义的规则去做混淆映射,比如将上一次的混淆映射应用在这一次,增量混淆可以用到
混淆字典
上面三个分别是:
Obfuscation dictory:根据自定义的混淆字典对方法和字段名称进行命名
Class Obfuscation dictory: 根据自定义的混淆字典对类名称进行命名
Package obfuscation dictory: 根据自定义的混淆字典对包名称进行命名
字典示例:
混淆结果:
总结
Proguard作为一款混淆器,混淆能力比较有限,且配置比较繁琐,需要注意的问题比较多,尽量降低混淆对象在主程序中的耦合度,才能进一步提升混淆覆盖率