今天和大家一起学习下java中的代码混淆技术,后面你也可以让你的代码不再裸露在外了,让人轻易窥视
当需要阅读jar文件的内容时,可能你会使用一些反编译工具,比如jd-gui,但是否有遇到反编译后的内容和想象的不一样,但正常引用该jar又都是正常的?
前段时间,使用了docx4j的库来操作.docx文件进行一些复杂的操作,比如对多个docx文件进行合并,在网上找了很多的方式发现最终生成的文档都有很多多余的内容, 导致原本几兆的文件合并后有几十兆,记得docx4j官网有提供商业版本的方法,准备窥探下其源码来研究下,然而当我下载好jar后打开时,我蒙了...
我们知道,一般情况下编译打包后的jar文件可以通过反编译工具看到jar中的接口、类、方法都是可以被,这样相关的代码实现很容易被模仿借鉴,企业的核心代码很可能被人盗用。特别是一些涉密较强或者商业性的行业软件,当被拿到jar并反编译后如同开源一般。那么通过对class文件进行字节码级别的混淆加密,就能够在一定程度防止技术被模仿或复用, 从而对java软件起到很好的保护作用。
今天主要介绍通过第3种方法实现代码混淆,这里主要使用了proguard工具对应的maven插件 proguard-maven-plugin :
Proguard是一个Java类文件压缩器、优化器、混淆器、预校验器。压缩环节会检测以及移除没有用到的类、字段、方法以及属性。优化环节会分析以及优化方法的字节码。混淆环节会用无意义的短变量去重命名类、变量、方法。这些步骤让代码更精简,更高效,也更难被逆向(破解)
比如我们基于Restful开发一个用户服务接口
packages...
├ entity
| ├ User
├ dao
| ├ UserDao
| ├ impl
| ├ UserDaoImpl
├ service
| ├ UserService
| ├ impl
| ├ UserServiceImpl
├ web
| ├ UserController
通过命令mvn package打包后,结构是这样的:
需要在pom.xml中build标签中加入插件,具体配置如下:
< !-- ProGuard混淆插件-- >
< plugin >
< groupId >com.github.wvengen< /groupId >
< artifactId >proguard-maven-plugin< /artifactId >
< version >2.6.0< /version >
< executions >
< execution >
< !-- 混淆时刻,这里是打包的时候混淆-- >
< phase >package< /phase >
< goals >
< !-- 使用插件的什么功能-- >
< goal >proguard< /goal >
< /goals >
< /execution >
< /executions >
< configuration >
< !-- 是否将生成的PG文件安装部署-- >
< attach >true< /attach >
< !-- 对什么东西进行加载,这里仅有classes成功,毕竟你也不可能对配置文件及JSP混淆吧-- >
< injar >${project.build.finalName}.jar< /injar >
< !--class 混淆后输出的jar包-- >
< outjar >${project.build.finalName}-pg.jar< /outjar >
< !-- 是否混淆-- >
< obfuscate >true< /obfuscate >
< !-- 配置一个文件,通常叫做proguard.cfg,该文件主要是配置options选项,也就是说使用proguard.cfg那么options下的所有内容都可以移到proguard.cfg中 -- >
< proguardInclude >${project.basedir}/proguard.cfg< /proguardInclude >
< !-- 指定生成文件分类 -- >
< attachArtifactClassifier >pg< /attachArtifactClassifier >
< !-- 额外的jar包,通常是项目编译所需要的jar -- >
< libs >
< lib >${java.home}/lib/rt.jar< /lib >
< /libs >
< !-- 对输入jar进行过滤比如,如下配置就是对META-INFO文件不处理。 -- >
< inLibsFilter >!META-INF/**< /inLibsFilter >
< !-- 这是输出路径配置,但是要注意这个路径必须要包括injar标签填写的jar -- >
< outputDirectory >${project.basedir}/target< /outputDirectory >
< !--这里特别重要,此处主要是配置混淆的一些细节选项,比如哪些类不需要混淆,哪些需要混淆-- >
< options >
< !-- 可以在此处写option标签配置,不过我上面使用了proguardInclude,故而我更喜欢在proguard.cfg中配置 -- >
< /options >
< /configuration >
< /plugin >
其中配置文件proguard.cfg如下:
#指定Java的版本
-target 1.8
#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 *;
@org.springframework.stereotype.Component *;
}
#忽略warn消息
-ignorewarnings
#忽略note消息
-dontnote
#打印配置信息
-printconfiguration
通过proguard来实现class内容的混淆相对比较简单,当然还有很多其他的技术方法,比如上面说到的对class进行加密这种更安全的技术手段,感兴趣的你可以继续探究。
其他技术
- Jocky
- retroguard
- androidkiller
- ClassFinal
此篇文章简单介绍了java中的代码混淆技术,我们可以根据具体的项目需求对编译后的代码进行混淆或加密处理,从而保护自己的劳动成果。开头看到的docx4j企业级功能提供 的jar具体是怎么实现代码保护的,目前还没发现其具体采用了什么技术实现,后面继续研究。
全部0条评论
快来发表一下你的评论吧 !