java项目一般是打包成jar运行或者作为依赖给第三方使用的,有的时候,可能不想被别人反编译,于是就对关键部分进行混淆,让代码变得普通人看不懂的地步,很多关键字和变量都是用单个字母表示,达到一种类似加密的效果。
java中混淆框架proguard,准确来说是一个插件,不需要对他进行编码,只需要进行配置即可。代码混淆,并不是把所有代码进行混淆,这样反而会出错,比如枚举类型如果也进行混淆,那么在使用反射创建实例,并给实例赋值的时候,枚举类型会反序列化失败。
proguard提供了可以对哪些包,类,方法等不进行混淆的配置,我们可以将枚举配置在这里。
因为springboot提供了打包插件spring-boot-maven-plugin,所以我们的混淆需要在springboot打包的插件之前,就是我们要对混淆之后的代码通过spring-boot-maven-plugin进行打包。
下面是一个配置示例proguard.cfg:
# 指定不警告尚未解决的引用和其他问题
-dontwarn
# JDK目标版本1.8
-target 1.8
# 不做收缩(删除注释、未被引用代码)
-dontshrink
# 不做优化(变更代码实现逻辑)
-dontoptimize
# 混淆时不使用大小写混合,混淆后的类名为小写
-dontusemixedcaseclassnames
# 不去忽略非公共的库类
-dontskipnonpubliclibraryclasses
# 指定不跳过包可见的库类成员(字段和方法)。
# 默认情况下,proguard在解析库类时会跳过包可见的库类成员。当我们确实引用了包可见的类成员时,需要设置此项
-dontskipnonpubliclibraryclassmembers
# 确定统一的混淆类的成员名称来增加混淆
-useuniqueclassmembernames
# 优化时允许访问并修改有修饰符的类和类的成员
-allowaccessmodification
# 不混淆所有包名
#-keeppackagenames
# 需要保持的属性:异常,注解等
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,LocalVariable*Table,*Annotation*,Synthetic,EnclosingMethod
# spring 相关的注解,不要混淆
-keepclassmembers class * {@org.springframework.** *;@javax.annotation.PostConstruct *;@javax.annotation.PreDestroy *;
}
# spring 相关的注解,不要混淆
-keepclassmembers class * {@org.springframework.beans.factory.annotation.Autowired ;@org.springframework.beans.factory.annotation.Autowired ;
}#混淆时是否记录日志
#-verbose# 不混淆所有的set/get方法
-keepclassmembers public class * {void set*(***);*** get*();}
# 不混淆本工程中的部分特殊类
-keep class com.xxx.hello.Hello {*;}
-keep class com.xxx.hello.domain.BookStatus {*;}# 不混淆所有包含Component等注解的类
-keep @org.springframework.stereotype.Component class * {*;}
-keep @org.springframework.stereotype.Service class * {*;}
-keep @org.springframework.web.bind.annotation.RestController class * {*;}
-keep @org.springframework.context.annotation.Configuration class * {*;}
pom.xml
org.springframework.boot spring-boot-starter-parent 2.7.8 org.springframework.boot spring-boot-starter-web com.alibaba fastjson 2.0.20 com.github.wvengen proguard-maven-plugin 2.0.14 package proguard 6.1.0 true proguard.cfg ${project.build.finalName}.jar ${project.build.finalName}.jar ${project.build.directory} ${java.home}/lib/rt.jar ${java.home}/lib/jce.jar net.sf.proguard proguard-base 6.1.0 org.springframework.boot spring-boot-maven-plugin com.xxx.hello.Hello exec ZIP repackage
java项目在最后给出来,大致意思是,启动springboot web项目,提供两个接口add,get,一个是用来添加一个book对象,一个用来读取这个book对象。
打包之后的文件:
可以看到hello-1.0-SNAPSHOT_proguard_base.jar要早于另外两个jar,因为它要先混淆。
我们可以通过反编译软件jd-gui查看打包后的jar文件:
这里面对spring相关的都进行过过滤,所以剩下的都是和spring无关的类, 除了BookStatus这个枚举类型之外,都进行了混淆,类名称都直接缩写成了小写字母a,b,c....
测试写入:
测试读取:
都是没问题的,如果我们把BookStatus枚举也进行混淆,那么进行写入的时候,报错:
意思是反序列化失败, 因为没有BookStatus的枚举常量。
代码地址:https://gitee.com/buejee/javaproguardexample