Java 代码混淆
0、序言
近日,产品单位反馈,Java编译得到的字节码文件,容易被反编译得到源代码,被恶意查看、复制、分析、盗用等。
对代码进行混淆,可以在项目交付后,有效预防三方对字节码文件进行反编译、进行恶意操作,保护知识产权,提高代码安全。
代码混淆工具有很多,使用中的难点为:尽可能多的将代码混淆,并正常运行。
我们常采用springboot模块化开发,在此基础上,经过调查本文选择proguard进行代码混淆,后文含注意事项,使用流程,最后附混淆案例,供各位参考。
1、ProGuard 介绍
ProGuard是一个开源的Java类文件收缩、优化、混淆、预检器。ProGuard处理后的程序或库会更小、更快,并在一定程度上提高对反编译的抵抗能力。
2、注意事项及建议
1、 被框架反射调用或者代理的类,是不能混淆的,常见的包括spring.factories相关类、spi相关类、bex相关属性、mybatis相关类、@Configuration@ConfigurationProperties@Value相关;
2、特殊的类不能混淆,包括异常、内部类、注解等;
3、pojo不能混淆,否则接口请求序列化会报错;
4、建议在@Controller、@Service、@Component、@Bean等处,设置bean名称,@PathVariable、@Param等设置参数名;
5、更多配置可在ProGuard 官方配置说明文档查询,部分配置说明:
-
-dontshrink
,关闭删除没有使用的类/成员,否则会把Controller啥的给删掉 -
-dontoptimize
,关闭字节码级别的优化,否则aop会报错 -
-adaptclassstrings
,反射相关,混淆类名之后,对使用Class.forName(‘className’)之类的地方进行相应替代 -
-keepdirectories
,保持目录结构,否则@ComponentScan会无法正常工作 -
keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
,不混淆特殊类 -
-keepclassmembers [,modifier,...] class specification
指定要保留的类成员 -
-keep [,modifier,...] class specification
指定类和类成员(字段,方法)作为入口点被保留。
6、常见JAVA library
JAVA LIB | 说明 |
---|---|
rt.jar | 运行时包 |
jsse.jar | Java 安全套接字扩展类库,用于实现加密的 Socket 连接 |
jce.jar | Java 加密扩展类库,含有很多非对称加密算法在里面,但也是可扩展的 |
charsets.jar | Java 字符集,这个类库中包含 Java 所有支持字符集的字符 |
resources.jar | 资源包(图片、properties文件) |
dnsns.jar | 与 DNS 有关 |
localedata.jar | 本地机器语言的数据,比如日期在使用中文时,显示的是“星期四”之类的 |
sunjce_provider.jar | 为JCE 提供的加密安全套件 |
sunmscapi.jar | 数字签名 |
3、使用方式1,外置proguard配置
1、在要混淆的模块pom.xml
中,添加插件
插件:
<build>
<plugins>
<plugin>
<groupId>com.github.wvengen</groupId>
<artifactId>proguard-maven-plugin</artifactId>
<version>2.5.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>proguard</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- 是否混淆 -->
<obfuscate>true</obfuscate>
<!-- 混淆配置文件 -->
<proguardInclude>${project.basedir}/proguard.cfg</proguardInclude>
<!-- 依赖的JAVA library -->
<libs>
<lib>${java.home}/lib/rt.jar</lib>
</libs>
</configuration>
</plugin>
</plugins>
</build>
2、pom.xml同级目录添加proguard.cfg
文件
文件内容:
#默认是开启的,这里关闭shrink,即不删除没有使用的类/成员,否则会把Controller啥的给删掉
-dontshrink
#默认是开启的,这里关闭字节码级别的优化,否则aop会报错
-dontoptimize
#混淆类名之后,对使用Class.forName('className')之类的地方进行相应替代
-adaptclassstrings
#不混淆所有特殊的类,否则抛出去的异常会出问题
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
#保持目录结构,解决@ComponentScan失效
-keepdirectories
#不混淆service中函数名
-keepclassmembers public class com.szkingdom.koca.config.service.** { public *; }
#不混淆Mybatis相关
-keep class com.szkingdom.koca.config.dao.** { *; }
#不混淆@Configuration,@ConfigurationProperties,@Value相关
-keepclassmembers class * {
@org.springframework.beans.factory.annotation.Value *;
}
-keep class com.szkingdom.koca.config.config.** { *; }
-keep class com.szkingdom.koca.config.server.*Configuration { *; }
#不混淆pojo
-keep class com.szkingdom.koca.config.vo.** { *; }
-keep class com.szkingdom.koca.config.model.** { *; }
-keep class com.szkingdom.koca.config.server.paramer.** { *; }
-keep class * implements java.io.Serializable
3、maven打包,得到混淆后的jar包,使用jd-gui查看混淆结果
如图:
4、使用方式2,pom.xml内置proguard配置
1、在要混淆的模块pom.xml
中,添加插件与proguard配置
<build>
<plugins>
<plugin>
<groupId>com.github.wvengen</groupId>
<artifactId>proguard-maven-plugin</artifactId>
<version>2.5.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>proguard</goal>
</goals>
</execution>
</executions>
<configuration>
<obfuscate>true</obfuscate>
<libs>
<!-- Include main JAVA library required.-->
<lib>${java.home}/lib/rt.jar</lib>
</libs>
<options>
<option>-dontshrink</option>
<option>-dontoptimize</option>
<option>-adaptclassstrings</option>
<option>-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod</option>
<option>-keepdirectories</option>
<option>-keepclassmembers public class com.szkingdom.koca.config.service.** { public *; }</option>
<option>-keep class com.szkingdom.koca.config.dao.** { *; }</option>
<option>-keepclassmembers class * { @org.springframework.beans.factory.annotation.Value *; }</option>
<option>-keep class com.szkingdom.koca.config.config.** { *; }</option>
<option>-keep class com.szkingdom.koca.config.server.*Configuration { *; }</option>
<option>-keep class com.szkingdom.koca.config.vo.** { *; }</option>
<option>-keep class com.szkingdom.koca.config.model.** { *; }</option>
<option>-keep class com.szkingdom.koca.config.server.paramer.** { *; }</option>
<option>-keep class * implements java.io.Serializable</option>
</options>
</configuration>
</plugin>
</plugins>
</build>
2、maven打包,得到混淆后的jar包,使用jd-gui查看混淆结果
如图:
5、打包生成文件说明
案例中,使用插件后打包后,会生成下述文件:
文件 | 说明 |
---|---|
koca-cloud-config-server-3.1.0-SNAPSHOT.jar | 混淆后的jar |
koca-cloud-config-server-3.1.0-SNAPSHOT_proguard_base.jar | 未混淆的jar |
proguard_map.txt | 混淆前后映射说明文件 |
proguard_seed.txt | 未混淆的内容汇总 |
6、混淆案例
代码混淆.zip (337.1 KB)
-
koca-cloud-config-server
:被混淆的模块 -
bootapp
:bootapp项目,聚合被混淆的模块
7、其他
Java代码混淆工具有很多,本文仅对proguard的使用,及出现的问题进行了研究,在开发过程中,应根据实际情况选用合适的方案。