赞
踩
由于项目需求,需要对项目代码做个混淆
在做的过程中发现,搜索到的大部分帖子都是单Module的和Maven项目的,有一定的借鉴意义,但还是不能直接解决问题。经过一段时间的试错之后,总算把项目代码混淆成功,并运行起来了,在此就做个总结,希望能对也有此需求的大家有所帮助。
使用文档:https://www.guardsquare.com/manual/home
ProGuard是一个压缩、优化和混淆Java字节码文件的免费的工具,它可以删除无用的类、字段、方法和属性。可以删除没用的注释,最大限度地优化字节码文件。它还可以使用简短的无意义的名称来重命名已经存在的类、字段、方法和属性。常常用于Android开发用于混淆最终的项目,增加项目被反编译的难度。
ProGuard处理流程:
需要在此说明的是,Proguard只是增加了反编译的难度,并不是真正的加密。
在项目启动的Module的build.gradle下引入插件
build.gradle参考结构
import proguard.gradle.ProGuardTask
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("com.guardsquare:proguard-gradle:7.3.2")
}
}
task proguard(type: ProGuardTask) {}
注:ProGuard的版本对JDK的版本有限制,具体可参考官方文档。由于我们项目使用的是JDK17,所以使用的是7.3.2,具体项目具体配置
在上述的build.gradle同级目录下,创建规则文件
proguard.pro
#指定Java的版本 -target 17 #proguard会对代码进行优化压缩,他会删除从未使用的类或者类成员变量等 -dontshrink #是否关闭字节码级别的优化,如果不开启则设置如下配置 -dontoptimize #混淆时不生成大小写混合的类名,默认是可以大小写混合 -dontusemixedcaseclassnames # 对于类成员的命名的混淆采取唯一策略 -useuniqueclassmembernames #混淆时不生成大小写混合的类名,默认是可以大小写混合 -dontusemixedcaseclassnames #混淆类名之后,对使用Class.forName('className')之类的地方进行相应替代 -adaptclassstrings #对异常、注解信息予以保留 -keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod # 此选项将保存接口中的所有原始名称(不混淆)--> -keepnames interface ** { *; } # 此选项将保存所有软件包中的所有原始接口文件(不进行混淆) #-keep interface * extends * { *; } #保留参数名,因为控制器,或者Mybatis等接口的参数如果混淆会导致无法接受参数,xml文件找不到参数 -keepparameternames # 保留枚举成员及方法 -keepclassmembers enum * { *; } # 不混淆所有类,保存原始定义的注释- -keepclassmembers class * { @org.springframework.context.annotation.Bean *; @org.springframework.beans.factory.annotation.Autowired *; @org.springframework.beans.factory.annotation.Value *; @org.springframework.stereotype.Service *; @javax.persistence.Table *; @javax.persistence.Entity *; } -keepclasseswithmembers public class * { public static void main(java.lang.String[]);} ##保留main方法的类及其方法名 -keep public class ch.qos.logback.**{*;} -keep class com.fasterxml.jackson.** { *; } -keep public class com.fasterxml.jackson.** { *; } #忽略warn消息 -ignorewarnings #忽略note消息 -dontnote #打印配置信息 -printconfiguration
SpringBoot修改
public class xxApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(xxApplication .class)
.beanNameGenerator(new CustomBeanNameGenerator())
.run(args);
}
private static class CustomBeanNameGenerator implements BeanNameGenerator {
@Override
public String generateBeanName(BeanDefinition d, BeanDefinitionRegistry r) {
return d.getBeanClassName();
}
}
}
注:配置文件是混淆过程中最容易出错的地方,很多时候不容易把握住什么时候该keep,这里简单总结一下
1、涉及全路径的以及较底层类应该保留,如使用了反射或者切面等等
2、对外公开的类应该保留
以上涉及的部分单Module和多Module都没有区别,这部分是真正实现SpringBoot 多Module混淆的部分。
在最开始配置的时候,由于没有配置其他Module,导致最后构建的Jar包只包含启动类。
以下还是在上述的build.gradle上做修改,只涉及到ProGuard
build.gradle
import proguard.gradle.ProGuardTask buildscript { repositories { mavenCentral() } dependencies { classpath("com.guardsquare:proguard-gradle:7.3.2") } } dependencies { implementation project(':xx:a') implementation project(':xx:b') implementation project(':xx:c') implementation project(':xx:d') implementation('com.guardsquare:proguard-gradle:7.3.2') } task proguard(type: ProGuardTask) { // 输出混淆前->混淆后的映射 printmapping "$buildDir/mapping.txt" // 混淆规则文件 configuration 'proguard.pro' // 混淆时依赖的库 libraryjars configurations.runtimeClasspath.collect() // jdk 依赖,区分jdk8 前后版本 if (System.getProperty('java.version').startsWith('1.')) { libraryjars "${System.getProperty('java.home')}/lib/rt.jar" } else { libraryjars "${System.getProperty('java.home')}/jmods/java.base.jmod", jarfilter: '!**.jar', filter: '!module-info.class' libraryjars "${System.getProperty('java.home')}/jmods/java.desktop.jmod", jarfilter: '!**.jar', filter: '!module-info.class' } // 混淆输入 //class 混淆 injars sourceSets.main.output injars "${project(":xx:a").buildDir}\classes\java\main" injars "${project(":xx:b").buildDir}\classes\java\main" injars "${project(":xx:c").buildDir}\classes\java\main" injars "${project(":xx:d").buildDir}\classes\java\main" // 混淆输出 outjars "$buildDir/classes-pro" } // 清除现有的lib目录 task clearJar(type: Delete) { delete "$buildDir\libs\lib" } // 拷贝配置文件 task copyConfigFile(type: Copy) { // 清除现有的配置目录 delete "$buildDir\libs\config" from 'src/main/resources' into 'build/libs/config' } // 将依赖包复制到lib目录 task copyJar(type: Copy, dependsOn: 'clearJar') { from configurations.compileClasspath into "$buildDir\libs\lib" } task clearSdkJar(type: Delete) { delete "$buildDir\libs\sdk.jar" } tasks.register('makeJar', Jar) { //指定生成的jar名 baseName 'xx' from sourceSets.main.output // lib目录的清除和复制任务 dependsOn clearJar dependsOn copyJar // 指定依赖包的路径 manifest { attributes "Manifest-Version": 1.0, 'Main-Class': 'xx.xx.xx', 'Class-Path': configurations.compileClasspath.files.collect { "lib/$it.name" }.join(' ') } } tasks.register('makeProJar', Jar) { dependsOn makeJar dependsOn proguard //指定生成的jar名 baseName 'xx-pro' //从哪里打包class文件 from("$buildDir/classes-pro") dependsOn copyJar // 指定依赖包的路径 manifest { attributes "Manifest-Version": 1.0, 'Main-Class': 'xx.xx.xx', 'Class-Path': configurations.compileClasspath.files.collect { "lib/$it.name" }.join(' ') } doLast { delete 'build/libs/lib/com' } }
注:proguard中的injars是实现多Module混淆的关键,通过injars将其他Module的代码混淆到指定目录
执行gradle clean
执行gradle makeProJar
最后在libs目录下即可看到原Jar包和混淆过后的Jar包,lib目录下为依赖的类库
启动验证:java -jar -Dloader.path=lib xx-pro-1.0-SNAPSHOT.jar
启动不成功的话,可能是proguard.pro配置的不合理,需反复检查验证
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。