jar包防反编译+加密方案
说明
由于程序需要部署至外部机器,直接上传打包的原生jar包有代码暴露风险,为解决此问题输出本方案。本文示例的改造加密程序为可信工业资产服务网络/密钥管理系统。
改动说明
目的:程序正常运行不出现改动导致的bug
需求:核心代码混淆,jar包加密
1、新增一个proguard.cfg文件
2、修改启动类模块的pom.xml文件
3、使用xjar工具加密
- ### 编写proguard.cfg文件
在启动类模块的pom.xml同级目录下新建文件,并命名为”proguard.cfg”
只需要修改文件中标注需要改动的地方,其他配置如果对proguard的kepp规则不熟悉的不要改动
#指定Java的版本
-target 1.8
#proguard会对代码进行优化压缩,他会删除从未使用的类或者类成员变量等
-dontshrink
#是否关闭字节码级别的优化,如果不开启则设置如下配置
-dontoptimize
#混淆时不生成大小写混合的类名,默认是可以大小写混合
-dontusemixedcaseclassnames
# 对于类成员的命名的混淆采取唯一策略
-useuniqueclassmembernames
#混淆时不生成大小写混合的类名,默认是可以大小写混合
-dontusemixedcaseclassnames
#混淆类名之后,对使用Class.forName('className')之类的地方进行相应替代
-adaptclassstrings
# 保留枚举成员及方法
-keepclassmembers enum * { *; }
# 此选项将保存接口中的所有原始名称(不混淆)-->
#-keepnames interface ** { *; }
# 此选项将保存所有软件包中的所有原始接口文件(不进行混淆)
#-keep interface * extends * { *; }
# 不混淆所有类,保存原始定义的注释-
-keep class * {
@org.springframework.context.annotation.Bean *;
@org.springframework.beans.factory.annotation.Autowired *;
@org.springframework.beans.factory.annotation.Value *;
@org.springframework.stereotype.Service *;
@org.springframework.stereotype.Component *;
@org.apache.dubbo.config.annotation.DubboReference *;
@org.apache.dubbo.config.annotation.DubboService *;
@javax.annotation.Resource *;
}
#忽略warn消息
-ignorewarnings
#忽略note消息
-dontnote **
#打印配置信息
-printconfiguration
#保持目录结构
-keepdirectories
#保持序列化的类成员
-keepclassmembers class * implements java.io.Serializable {*;}
#不混淆方法参数名、包名
-keepattributes MethodParameters , Packagenames
#对异常、注解信息予以保留
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
###############################以上配置不需要修改####################################
#### ####
#### proguard混淆配置文件 ####
#### ####
###############################根据实际情况修改下方配置###############################
#不混淆该类内的所有名字,一般指包含切点的切面对象,项目中没有用到可以注释
-keepnames class com.plktech.gyhlw.component.LogAspect {*;}
#不混淆dao层的jpa接口,这个需要根据项目实际路径修改,要混淆的模块不包含的话可以注释
-keepnames interface com.plktech.gyhlw.dao.* { *; }
#不混淆mapper层的映射接口,这个需要根据项目实际路径修改,要混淆的模块不包含的话可以注释
-keepnames interface com.plktech.gyhlw.mapper.* { *; }
#不混淆启动类,根据实际情况修改路径例如:com.plktech.gyhlw.GyhlwEnterpriseApplication
-keep public class com.plktech.gyhlw.SecretKeyApplication {*;}
- ### 修改启动类模块的pom.xml
主要修改
- 单模块:service层和启动类在同一个模块中
未说明的配置项一般不需要修改,有说明解释的可根据项目实际情况修改,启动类路径一定要修改
<build>
<finalName>{project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>com.github.wvengen</groupId>
<artifactId>proguard-maven-plugin</artifactId>
<version>2.6.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>proguard</goal>
</goals>
</execution>
</executions>
<configuration>
<putLibraryJarsInTempDir>true</putLibraryJarsInTempDir>
<injar>{project.build.finalName}.jar</injar>
<outjar>{project.build.finalName}.jar</outjar>
<obfuscate>true</obfuscate>
<!-- 配置一个文件,通常叫做proguard.cfg,放在pom同级目录-->
<proguardInclude>{basedir}/proguard.cfg</proguardInclude>
<libs>
<lib>{java.home}/lib/rt.jar</lib>
<lib>{java.home}/lib/jce.jar</lib>
<lib>{java.home}/lib/jsse.jar</lib>
</libs>
<inLibsFilter>!META-INF/**,!META-INF/versions/9/**.class</inLibsFilter>
<outputDirectory>{project.basedir}/target</outputDirectory>
<options>
</options>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
<configuration>
<!--启动类路径,改成项目的启动类路径(全限定性类名)-->
<mainClass>com.plktech.gyhlw.SecretKeyApplication</mainClass>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
- 多模块:启动类所在模块需要依赖service层所在模块
正常来说service层会打包成一个jar包在启动类模块的lib下,混淆的话我们需要直接将service层的class文件直接打包进启动类的模块里面,所以pom.xml的配置跟单模块有区别,此处以企业平台为例
<build>
<finalName>{project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>com.github.wvengen</groupId>
<artifactId>proguard-maven-plugin</artifactId>
<version>2.6.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>proguard</goal>
</goals>
</execution>
</executions>
<configuration>
<putLibraryJarsInTempDir>true</putLibraryJarsInTempDir>
<injar>{project.build.finalName}.jar</injar>
<outjar>{project.build.finalName}.jar</outjar>
<obfuscate>true</obfuscate>
<!-- 配置一个文件,通常叫做proguard.cfg,放在pom同级目录-->
<proguardInclude>{basedir}/proguard.cfg</proguardInclude>
<injarNotExistsSkip>true</injarNotExistsSkip>
<!-- 此处与单模块不同,需要将server层模块的坐标配置进来-->
<assembly>
<inclusions>
<inclusion>
<groupId>com.plktech</groupId>
<artifactId>enterprise</artifactId>
</inclusion>
</inclusions>
</assembly>
<options>
</options>
<libs>
<lib>{java.home}/lib/rt.jar</lib>
<lib>{java.home}/lib/jce.jar</lib>
</libs>
</configuration>
<dependencies>
<dependency>
<groupId>com.guardsquare</groupId>
<artifactId>proguard-base</artifactId>
<version>7.0.0</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
<!-- 启动类所在路径,(全限定性类名) -->
<mainClass>com.plktech.gyhlw.GyhlwEnterpriseApplication</mainClass>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
<!--需要修改,此处与单模块不同,上面将哪个jar包混淆了,这里就排除哪个-->
<excludeGroupIds>
com.plktech.gyhlw.enterprise
</excludeGroupIds>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
混淆后的方法名和变量名与编写时不同,可增加代码阅读难度
- 加密jar包
- 工具包下载到本地后,建议放在打包好的jar同级目录
- 在资源路径上输入cmd回车或者键盘win+r打开命令窗口cd到jar包路径
- 运行加密工具 java -jar xjar-demo.jar
- 选择要加密的jar包以及加密后保存的路径,输入密码加密
- 加密成功后得到三个文件加密后的jar包encrypt-server-enterprise-execute.jar,两个go源文件xjar.go、xjar_agentable.go。
加密后的jar包,代码已不可见
由于我们的程序需要在liunx上运行,所以需要在liunx上编译加密后的jar,得到一个可执行脚本xjar,将上述得到的三个文件上传至liunx服务器,以(192.168.2.188)为例,服务器需要安装go运行环境
- 编译go源文件
cd 到jar包所在目录
执行 go build xjar.go 执行完得到一个 xjar的可执行脚本
- 运行程序 ./xjar java -jar encrypt-server-enterprise-execute.jar
如果是 sudo 命令需要加上java的绝对路径
sudo ./xjar /usr/local/java/bin/java -jar encrypt-server-enterprise-execute.jar
程序启动成功
- 上传至服务器运行,只需要上传 xjar脚本以及加密的jar包即可,且运行的服务器不需要安装go环境
运行命令同上
参考文章
proguard官方文档
https://www.guardsquare.com/manual/home
插件文档
https://wvengen.github.io/proguard-maven-plugin/
xjar加密
https://blog.csdn.net/seashouwang/article/details/115728095?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-1-115728095-blog-129407415.235