Java代码保护方法之一:ProGuard_java如何保护源码

createh54周前 (02-18)技术教程19

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源码保护手段,但其局限性显而易见:它并未触及代码的逻辑核心与整体架构,仅仅是为破解者增设了一道屏障,提高了些许破解成本。

因此,我们在采用此方法时,应理性看待其保护效果,寻求更为全面和根本的代码保护策略。

相关文章

java中类变量和实例变量的实质区别?

类变量和实例变量的区别相对于static(静态的)或说类的, 本章开始提到的都是instance(实例的)或说对象的。 每个对象都有自己的一份儿对象域或实例域,相互之间没关系, 不共享。 我们可以从对...

Java变量_java变量名命名规则

变量如果按照大部分的书上来说,在程序运行过程中可以改变的量称之为变量。常量就是程序运行中不可改变的量就是常量。变量准确的来说就是存储的名称,如果你要把数据存到内存里,你就需要选择一个数据类型,而且还要...

Java SE 基础教程—JDK的下载安装及环境变量的配置(win10详细版)

1.什么是JDKSun公司提供了一套Java开发环境,简称JDK(Java Development Kit) 它是整个Java的核心,其中包括Java编译器、Java运行工具、Java文档生成工具、J...

初识Java—(二十四)Java类成员_java 类

static关键字修饰的成员就是类成员,其中有类变量Field、类方法、静态初始化块。static修饰的类成员属于整个类,不属于单个实例。6.3.1 理解类成员在Java类里只能包含Field、方法、...

4.Java变量_java 变量

变量(Variables )每个程序都使用值。变量允许您通过将值分配给一个名称来存储值。该名称可用于在程序的后面引用该值。例如,在游戏开发中,您可以使用一个变量来存储玩家得分的点数。每个变量都有一个类...

Java初学者常见的10类问题_java入门例子

对于Java初学者来说,在学习过程中经常会遇到一些常见的问题。以下是Top 10常见问题及其解决方案:1. 环境配置问题问题:Java开发环境(如JDK、IDE)配置不正确。解决方案:确保正确安装了J...