Java代码保护方法之一:ProGuard_java如何保护源码
ProGuard是一个开源的Java程序代码压缩、优化和混淆工具,是目前Java代码保护最常用的工具。
“瘦身高手”+“优化小能手”+“混乱大师”。
1、压缩(瘦身高手):检查并删除没有被使用的类、字段、方法和属性,从而减小代码库的大小。提高应用的启动速度和降低内存占用。
2、优化(优化小能手):分析代码,并进行一些基本的优化,如内联方法、去除死代码、常量表达式求值、删除不必要的字段存取和方法调用等。能在一定程度上提高代码的执行效率。
3、混淆(混乱大师):将类名、方法名和字段名重命名为难以理解的字母和数字序列,增加反编译的难度,从而保护应用程序不被恶意篡改或进行逆向工程。
对于大部分Java开发者来说,使用最多的是ProGuard的混淆功能。
以Java后端为例,来具体说明ProGuard的使用方法和注意事项。
一、准备工作
jdk1.8
安装jdk1.8
设置环境变量JAVA_HOME和PATH
maven:3.9.3
安装maven
设置环境变量MAVEN_HOME和PATH
二:配置项详解
ProGuard提供了GUI和Maven插件两种使用方法。
对于开发者而言,Maven方式更为方便。通常的配置如下:
maven 配置:
com.github.wvengen proguard-maven-plugin 2.0.14 package proguard true 6.2.2 ${project.basedir}/proguard.cfg ${project.build.finalName}.jar ${project.build.finalName}.jar ${java.home}/lib/rt.jar net.sf.proguard proguard-base 6.2.2 runtime
proguard.cfg文件:
####以下是推荐的固定配置项
#指定Java的版本
-target 1.8
#proguard会对代码进行优化压缩,他会删除从未使用的类或者类成员变量等
-dontshrink
#是否关闭字节码级别的优化,如果不开启则设置如下配置 不做优化(变更代码实现逻辑)
-dontoptimize
#混淆时不生成大小写混合的类名,默认是可以大小写混合
-dontusemixedcaseclassnames
#不会因为警告而中断
-dontwarn
# 对于类成员的命名的混淆采取唯一策略
-useuniqueclassmembernames
#混淆类名之后,对使用Class.forName('className')之类的地方进行相应替代
-adaptclassstrings
#保持目录结构
-keepdirectories
#对异常、注解信息予以保留
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod,Qualifier
#保留枚举成员及方法
-keepclassmembers enum * { *; }
#保留参数名,因为控制器,或者Mybatis等接口的参数如果混淆会导致无法接受参数,xml文件找不到参数
#不参与混淆的类参数也不混淆,controller如果参数也混淆会导致传参映射不上
-keepparameternames
# 不混淆所有类,保存原始定义的注释-
-keepclassmembers class * {
@
org.springframework.context.annotation.Bean *;
@javax.annotation.Resource *;
@
org.springframework.beans.factory.annotation.Autowired *;
@
org.springframework.beans.factory.annotation.Value *;
@
org.springframework.stereotype.Service *;
@
org.springframework.stereotype.Component *;
@
org.springframework.context.annotation.Configuration *;
@
org.springframework.stereotype.Repository *;
@
org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration *;
@
org.springframework.boot.context.properties.ConfigurationProperties *;
@
org.springframework.web.bind.annotation.RestController *;
@
org.springframework.beans.factory.annotation.Qualifier *;
@
io.swagger.annotations.ApiParam *;
@
org.springframework.validation.annotation.Validated *;
@
io.swagger.annotations.ApiModelProperty *;
@
javax.validation.constraints.NotNull *;
@
javax.validation.constraints.Size *;
@
javax.validation.constraints.NotBlank *;
@
javax.validation.constraints.Pattern *;
}
-keep class org.springframework.** {*;}
-keep public class ch.qos.logback.**{*;}
-keep class com.fasterxml.jackson.** { *; }
#忽略warn消息
-ignorewarnings
#打印配置信息
-printconfiguration
######以下这些都需要根据具体项目而更改
#入口程序类不能混淆,混淆会导致springboot启动不了
-keep public class com.dxc.project1.AppStart { *;}
#mybatis的mapper/实体类不混淆,否则会导致xml配置的mapper找不到 ( 保持该目录下所有类及其成员不被混淆)
-keep class
com.dxc.project1.mybatis.mapper.** {*;}
-keep class
com.dxc.project1.mybatis.domain.** {*;}
# controller 层映射前台参数的类、后端返回的 bean 属性类等,不能混淆类的成员属性(如变成 string a;)
-keepclassmembers class com.dxc.project1.**.*request {*;}
-keepclassmembers class com.dxc.project1.**.*response {*;}
-keepclassmembers class com.dxc.project1.**.*vo {*;}
#还有一些配置类和Bean不能混淆 比如logPointCut prefix 这些 @Pointcut
###配置文件:@ConfigurationProperties(prefix = "redisson")
-keep class
com.dxc.project1.aop.aspectj.** {*;}
#保留Serializable序列化的类不被混淆
-keepclassmembers class * implements java.io.Serializable {*;}
参数选项说明:
保留选项说明:
注意选项的命名规律:-keep*用于防止目标被移除或者重命名、-keep*names则仅仅用于防止重命名。
压缩选项:
优化选项:
混淆选项:
预校验选项:
大部分参数不用配置或者使用默认值即可,我建议压缩和优化开关关闭,ProGuard只用来做代码混淆,否则可能会出现一些莫名其妙的问题。
三:多模块
实际的项目中,需要混淆的一般不会是单模块,例如项目project1是主项目,project1依赖project2模块。
com.dxc project2 1.0-SNAPSHOT
需要同时混淆project1和project2,此时的maven配置:
org.apache.maven.plugins maven-assembly-plugin 3.3.0 false ${project.basedir}/assembly.xml assembly-package package single com.github.wvengen proguard-maven-plugin 2.0.14 package proguard true 6.2.2 ${project.basedir}/proguard.cfg ${project.build.finalName}.jar ${project.build.finalName}.jar ${java.home}/lib/rt.jar net.sf.proguard proguard-base 6.2.2 runtime org.springframework.boot spring-boot-maven-plugin 2.3.3.RELEASE com.dxc.project1.AppStart true com.dxc repackage
assembly.xml:
xsi:schemaLocation="
http://maven.apache.org/ASSEMBLY/2.0.0
http://maven.apache.org/xsd/assembly-2.0.0.xsd">${project.version} jar false ${project.build.directory}/classes / com.dxc:* true
混淆后的结果:
总结
ProGuard开箱即用,虽便捷但配置项颇为繁琐,配置完成后还需经过严格的测试流程以确保无误。
此外,代码编写也需遵循一定规范,这无疑增加了开发者的约束,不能随心所欲编程。
尽管这是当前最为普及的Java源码保护手段,但其局限性显而易见:它并未触及代码的逻辑核心与整体架构,仅仅是为破解者增设了一道屏障,提高了些许破解成本。
因此,我们在采用此方法时,应理性看待其保护效果,寻求更为全面和根本的代码保护策略。