最近开发的项目要做防止反编译,故而进行了代码混淆的研究,而项目中又时使用spring boot框架开发的,经过网上找的资料以及自己的实验,终于将代码进行了最大程度的混淆,特在此记录一下,与诸位分享。
我混淆代码使用的是proguard-maven-plugin这个插件,所有proguard的指令都可以在pom中实现。首先要说的是通过这种方法混淆就是移除没有用到的代码,然后对代码里面的类、变量、方法重命名为人可读性很差的简短名字,比如a,b,c等,所以如果这种程度的混淆无法满足你的需求,还是寻找其他混淆方法,如加密等。
接下来将进行具体如何混淆。首先,整个混淆在pom文件中引入proguard-maven-plugin这个插件,并在pom文件中进行混淆的具体配置即可,pom配置示例如下:
<plugin>
<groupId>com.github.wvengen</groupId>
<artifactId>proguard-maven-plugin</artifactId>
<version>2.0.11</version>
<executions>
<execution>
<!-- 混淆时刻,这里是打包的时候混淆 -->
<phase>package</phase>
<goals>
<!-- 使用插件的什么功能,当然是混淆 -->
<goal>proguard</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- 是否将生成的PG文件安装部署 -->
<attach>true</attach>
<!-- 是否混淆 -->
<obfuscate>true</obfuscate>
<!-- 指定生成文件分类 -->
<attachArtifactClassifier>pg</attachArtifactClassifier>
<options>
<!-- 不做收缩(删除注释、未被引用代码) -->
<option>-dontshrink</option>
<!-- 不做优化(变更代码实现逻辑) -->
<option>-dontoptimize</option>
<!-- 不路过非公用类文件及成员 -->
<option>-dontskipnonpubliclibraryclasses</option>
<option>-dontskipnonpubliclibraryclassmembers</option>
<!-- 优化时允许访问并修改有修饰符的类和类的成员 -->
<option>-allowaccessmodification</option>
<!-- 确定统一的混淆类的成员名称来增加混淆 -->
<option>-useuniqueclassmembernames</option>
<!-- 不混淆所有包名,本人测试混淆后WEB项目问题实在太多,毕竟Spring配置中有
大量固定写法的包名 -->
<option>-keeppackagenames</option>
<option>-adaptclassstrings</option>
<!-- <option>-keepdirectories</option> -->
<!-- 不混淆所有特殊的类 -->
<option>-keepattributes
Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,LocalVariable*Table,*Annotation*,Synthetic,EnclosingMethod</option>
<!-- This option will save all original methods parameters in files
defined in -keep sections, otherwise all parameter names will be obfuscate. -->
<option>-keepparameternames</option>
<option>-keepclassmembers class * {
@org.springframework.beans.factory.annotation.Autowired *;
@javax.annotation.Resource *;
@org.springframework.beans.factory.annotation.Value *;
}
</option>
<option>-keep class !com.xh.okdz.** { *; }</option>
<!-- 不混淆main方法 -->
<option>-keep class com.xh.okdz.OkdzApplication { *; }</option>
<!-- 不混淆所有的set/get方法 -->
<option>-keepclassmembers public class * {void set*(***);***
get*();}</option>
<!-- 不混淆包中的所有类以及类的属性及方法,实体包,混淆了会导致ORM框架及前端无法识别 -->
<!-- 不对包类的类名进行混淆,但对类中的属性和方法混淆 -->
<option>-keep class com.java.controller.** </option>
<option>-keep class com.java.service.** </option>
<option>-keep class com.java.exception.** </option>
<option>-keep class com.java.tasks.** </option>
<option>-keep class com.java.utils.** </option>
<!-- 不混淆包下的所有类名,且类中的方法也不混淆 -->
<option>-keep class com.java.config.**{*;}</option>
<option>-keep class com.java.entity.** {*;}</option>
<option>-keep class com.java.vo.** {*;}</option>
<option>-keep class com.java.annotation.**{*;}</option>
<option>-keep class com.java.dao.** {*;}</option>
</options>
<outjar>${project.build.finalName}-pg.jar</outjar>
<!-- 添加依赖,这里你可以按你的需要修改,这里测试只需要一个JRE的Runtime包就行了 -->
<libs>
<lib>${java.home}/lib/rt.jar</lib>
<lib>${java.home}/lib/jce.jar</lib>
</libs>
<!-- 对什么东西进行加载,这里加载classes就行,配置文件或者其他的三方文件应该不会混淆吧 -->
<injar>classes</injar>
<!-- 输出目录 -->
<outputDirectory>${project.build.directory}</outputDirectory>
</configuration>
<dependencies>
<dependency>
<groupId>net.sf.proguard</groupId>
<artifactId>proguard-base</artifactId>
<version>6.2.2</version>
</dependency>
</dependencies>
</plugin>
使用时将上面pom文件中的plugin标签中的内容引入到自己的pom文件中,将具体的包名换成自己的即可。具体的配置注释中都有,使用过程中主要难点是每个包可混淆到哪种程度,具体的情况需要时最好可以自行进行实验进行验证。下面我将我的混淆配置讲解一下:
-keep class !com.example.** { *; } 是混淆这个包下的类 对于controller、service以及定时任务这三个包,我采用的混淆程度为不对类名进行混淆,但是对属性和方法进行混淆 对于dao、pojo、dto以及配置类的包,我不进行混淆 以上的配置是我自己经过一次次尝试发现的所能混淆的最大程度,否则会报错。注意,在proguard-maven-plugin中默认是对类名,属性,方法全部混淆,所以如果全部混淆,则不需要配置这个包即可。我个人的感悟是混淆的程度主要是由于很多类是交由spring管理,所以这些spring bean的类名以及所注入的对象(由spring管理)最好不要混淆类名,否则spring无法识别以及管理,另外就是DAO类,如果是MySQL这种通过Mapper的XML文件映射的类型,最好不要混淆,否则DAO无法找到对应的SQL语句,其他例如Hbase等通过代码查询,读者可尝试进行混淆。一些工具包也是可以进行混淆的,混淆到那种程度读者可进行尝试。完成上述配置后,便可以执行maven命令进行打包,最终在target目录下会生成自己项目的jar包以及一个classes-pg.jar的jar包,其中自己项目的jar包是没有混淆代码的jar包,而classes-pg.jar包中的内容才是真正混淆后的代码,将项目的jar包用winrar打开(切记不饿能解压,否则jar包无法运行),进入到classes目录下,将classes-pg.jar中的内容(不包括META-INF文件夹)复制到项目的jar包的classes目录下即可,这样最后的项目的jar包便是进行代码混淆后的jar包,读者可自行反编译观察一下代码混淆的效果,如果启动后报错,读者可根据错误信息修改混淆的类即可。另外这里有一篇博客写的挺详细的,读者也可以看一下博文地址。如果报错的内容是类名冲突之类的,可以尝试一下在启动类中加入下面的代码:
public static class CustomGenerator implements BeanNameGenerator {
@Override
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
return definition.getBeanClassName();
}
将每个类名前加入包名,这样基本不会冲突了。至此,代码混淆完成,有问题的我们可以一起交流。