Java代码混淆-proguard

最近开发的项目要做防止反编译,故而进行了代码混淆的研究,而项目中又时使用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();
        }

将每个类名前加入包名,这样基本不会冲突了。至此,代码混淆完成,有问题的我们可以一起交流。

猜你喜欢

转载自blog.csdn.net/qq_45699784/article/details/125764225