基于Maven的SpringBoot⼯程中,如何使⽤proguard进⾏Java代码混淆?
前⾔
代码混淆,是将计算机程序的代码转换成⼀种功能上等价,但是难于阅读和理解的形式的⾏为。代码混淆可以⽤于程序源代码,也可以⽤于程序编译⽽成的中间代码。执⾏代码混淆的程序被称作代码混淆器。
为什么要做代码混淆?
代码混淆的主要⽬的是为了保护源代码,阻⽌反向⼯程。反向⼯程会带来许多问题,诸如知识产权泄露,程序弱点暴露易受攻击等。使⽤即时编译技术的语⾔,如Java、C#所编写的程序更容易受到反向⼯程的威胁。但是代码混淆并不能真正阻⽌反向⼯程,只能增⼤其难度。因此,对于对安全性要求很⾼的场合,仅仅使⽤代码混淆并不能保证源代码的安全。 还可以通过代码虚拟化,代码加密,压缩等多种⽅式来提⾼代码安全性。
代码混淆有哪些⽅式?
将代码中的各种元素,如变量,函数,类的名字改写成⽆意义的名字。⽐如改写成单个字母,或是简短的⽆意义字母组合,甚⾄改写成“__”这样的符号,使得阅读的⼈⽆法根据名字猜测其⽤途。
重写代码中的部分逻辑,将其变成功能上等价但是更难理解的形式。⽐如将for循环改写成while循环,将循环改写成递归,精简中间变量,等等。
打乱代码的格式。⽐如删除空格,将多⾏代码挤到⼀⾏中,或者将⼀⾏代码断成多⾏等等。
如何对 JAVA 代码进⾏混淆?
1. 在⽣成class⽂件的过程中(即编译过程),通过修改编译器的代码⽣成过程,对编译器⽣成的中间代码进⾏混淆,最后⽣成class⽂
件。典型的是jocky,但⽬前最新的jocky为1.0.3版本,不⽀持jdk1.6。
2. 在⽣成class⽂件后,对class⽂件进⾏混淆。典型的是proguard、retroguard。但由于并不是所有的class⽂件都需要混淆,所以将
⾯临复杂的配置⼯作(配置哪些类需要混淆,哪些类需要混淆),并且程序⼀旦修改,配置⼯作⼜要重新进⾏。
如何使⽤proguard进⾏代码混淆?
主要使⽤proguard-maven-plugin插件对springboot代码进⾏混淆。插件配置如下:
<build>
<plugins>
<!-- ProGuard混淆插件-->
<plugin>
<groupId>com.github.wvengen</groupId>
<artifactId>proguard-maven-plugin</artifactId>
<version>2.3.1</version>
<executions>
<execution>
<!-- 混淆时刻,这⾥是打包的时候混淆-->
<phase>package</phase>
<goals>
<!-- 使⽤插件的混淆功能 -->
<goal>proguard</goal>
</goals>
</execution>
</executions>
<configuration>
<proguardVersion>6.2.2</proguardVersion>
<!-- 对classes进⾏加载 -->
<injar>classes</injar>
<outjar>${project.build.finalName}.jar</outjar>
<!-- 输出⽬录-->
<outputDirectory>${project.build.directory}</outputDirectory>                <libs>
<lib>${java.home}/lib/rt.jar</lib>
<lib>${java.home}/lib/jce.jar</lib>
</libs>
<!--混淆-->
<obfuscate>true</obfuscate>
<!--是否将⽣成的PG⽂件安装部署-->
<!--<attach>true</attach>-->
<!--指定⽣成⽂件分类-->
<!--<attachArtifactClassifier>pg</attachArtifactClassifier>-->                <!--保留pom⽂件等-->
<addMavenDescriptor>false</addMavenDescriptor>
<!--外部配置⽂件-->
<proguardInclude>../proguard.cfg</proguardInclude>
</configuration>
<dependencies>
<dependency>
<groupId>net.sf.proguard</groupId>
<artifactId>proguard-base</artifactId>
<version>6.2.2</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
其中外部配置⽂件proguard.cfg内容如下:
# -keep {Modifier} {class_specification} 防⽌类和成员被移除或者被重命名
# -keepclassmembers {modifier} {class_specification} 防⽌成员被移除或者被重命名
# -keepclasseswithmembers {class_specification} 防⽌拥有该成员的类和成员被移除或者被重命名
# -keepnames {class_specification} 防⽌成员被重命名
# -keepclasseswithmembernames {class_specification} 防⽌拥有该成员的类和成员被重命名
# -keepclasseswithmembers
# -basedirectory directoryname  在配置⽂件中出现的相对路径均是相对于该路径
# 忽略所有警告,否则有警告的时候混淆会停⽌
-ignorewarnings
# JDK⽬标版本1.8
-target 1.8
# 不做收缩(删除注释、未被引⽤代码)
-dontshrink
# 不做优化(变更代码实现逻辑)
-dontoptimize
# 不路过⾮公⽤类⽂件及成员
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
# 优化时允许访问并修改有修饰符的类和类的成员
-allowaccessmodification
# 确定统⼀的混淆类的成员名称来增加混淆
-useuniqueclassmembernames
# 不混淆所有包名,本⼈测试混淆后WEB项⽬问题实在太多,毕竟Spring配置中有⼤量固定写法的包名
-keeppackagenames
# 不混淆局部变量名
-keepparameternames
# 不混淆所有特殊的类 LocalVariable*Table,
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,Synthetic,EnclosingMethod
# 不混淆包下的所有类名
-keep class weg.base.** { <methods>; }
-keep class weg.service.** { <methods>; }
-keep class weg.dao.** { <methods>; }
-keep class weg.util.** { <methods>; }
# 不混淆quartz包下的所有类名,且类中的⽅法也不混淆
-keep class weg.quartz.** { <methods>; }
# 不混淆model包中的所有类以及类的属性及⽅法,实体包,混淆了会导致ORM框架及前端⽆法识别
-keep del.** {*;}
# 不混淆所有的set/get⽅法,毕竟项⽬中使⽤的部分第三⽅框架(例如Shiro)会⽤到⼤量的set/get映射
-keepclassmembers public class * {void set*(***);*** get*();}
# 保持类protected不被混淆
-keep public class * { public protected <fields>;public protected <methods>; }
配置完成后执⾏maven命令:
clean package -DskipTests
执⾏上述代码后,在target⽬录下会⽣成3个⽂件:
classes.jar 混淆后的classes⽂件,⾥⾯包含完整的项⽬结构
混淆内容的映射
参与混淆的类
踩坑指南
(1) 报错如下:
Error: You have to specify '-keep' options if you want to write out kept elements with '-printseeds'.
shiro安全框架
解决⽅式:根据需求 配置  -keep  要保留的元素
(2)…/proguard.cfg配置⽂件未⽣效
解决⽅式:是因为路径写的有问题,此路径是相对于 编译后的 target ⽂件的路径,如果是maven多模块,这些配置⼜写在⽗模块的⽬录下,重点来了,想要混淆⼦模块的代码,那么这个路径就是相对于⼦模块的target⽂件夹的路径
(3)打包之后不知道混淆成功了没,或者混淆配置⽣效了没,查看这个jar包⾥的代码⼜很⿇烦
解决⽅式:outjar配置⼀个⽬录即可。如果要上传私服,打包之后却有两个包,混淆的那个包⽆法直接上传私服,那么outjar配置的jar包名称和${project.build.finalName}⼀致,即可覆盖。然后⼀键轻松上传私服。
<!--class 混淆后输出的jar包或⽂件夹-->
<outjar>${project.build.finalName}.jar</outjar>

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。