这什么代码,没法看了...

开发 前端
通过proguard来实现class内容的混淆相对比较简单,当然还有很多其他的技术方法,比如上面说到的对class进行加密这种更安全的技术手段。

哈喽,大家好,我是指北君。

今天和大家一起学习下java中的代码混淆技术,后面你也可以让你的代码不再裸露在外了,让人轻易窥视

代码混淆技术

当需要阅读jar文件的内容时,可能你会使用一些反编译工具,比如jd-gui,但是否有遇到反编译后的内容和想象的不一样,但正常引用该jar又都是正常的?

开始的话

前段时间,使用了docx4j的库来操作.docx文件进行一些复杂的操作,比如对多个docx文件进行合并,在网上找了很多的方式发现最终生成的文档都有很多多余的内容, 导致原本几兆的文件合并后有几十兆,记得docx4j官网有提供商业版本的方法,准备窥探下其源码来研究下,然而当我下载好jar后打开时,我蒙了...

图片

简介

我们知道,一般情况下编译打包后的jar文件可以通过反编译工具看到jar中的接口、类、方法都是可以被,这样相关的代码实现很容易被模仿借鉴,企业的核心代码很可能被人盗用。特别是一些涉密较强或者商业性的行业软件,当被拿到jar并反编译后如同开源一般。那么通过对class文件进行字节码级别的混淆加密,就能够在一定程度防止技术被模仿或复用, 从而对java软件起到很好的保护作用。

实现方式

  1. 对class文件进行加密,但是需要特定的Classloader在加载class时对其解密
  2. 针对class文件反编译原理,通过花指令防止文件被反编译
  3. 基于代码混淆技术,对代码中的包、类、方法等名称进行混淆,从而提高代码阅读成本

示例

今天主要介绍通过第3种方法实现代码混淆,这里主要使用了proguard工具对应的maven插件proguard-maven-plugin:

Proguard是一个Java类文件压缩器、优化器、混淆器、预校验器。压缩环节会检测以及移除没有用到的类、字段、方法以及属性。优化环节会分析以及优化方法的字节码。混淆环节会用无意义的短变量去重命名类、变量、方法。这些步骤让代码更精简,更高效,也更难被逆向(破解)

比如我们基于Restful开发一个用户服务接口

  1. 可能你的项目结构会是这样的:
packages...
├ entity
| ├ User
├ dao
| ├ UserDao
| ├ impl
| ├ UserDaoImpl
├ service
| ├ UserService
| ├ impl
| ├ UserServiceImpl
├ web
| ├ UserController

通过命令mvn package打包后,结构是这样的:

图片

  1. 现在引入proguard:

需要在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
  1. 执行打包命令mvc package,可以看到target目录下新增了几个文件
  • obfuscation-pg.jar 混淆处理后的输出jar
  • proguard_map.txt 存放混淆前后类、方法的对应关系
  • proguard_seed.txt 存放保持不变的类 可见包的名称、类名都改成了短字母

图片

实现技术

通过proguard来实现class内容的混淆相对比较简单,当然还有很多其他的技术方法,比如上面说到的对class进行加密这种更安全的技术手段,感兴趣的你可以继续探究。

  • 其他技术
  • Jocky
  • retroguard
  • androidkiller
  • ClassFinal

结束语

此篇文章简单介绍了java中的代码混淆技术,我们可以根据具体的项目需求对编译后的代码进行混淆或加密处理,从而保护自己的劳动成果。开头看到的docx4j企业级功能提供 的jar具体是怎么实现代码保护的,目前还没发现其具体采用了什么技术实现,后面继续研究。

责任编辑:武晓燕 来源: Java技术指北
相关推荐

2017-11-09 14:40:49

悬浮Tab代码

2020-11-20 10:22:34

代码规范设计

2021-01-04 13:33:08

黑客微软网络攻击

2020-05-15 09:30:12

代码函数语言

2015-06-05 11:23:19

前端为什么不要你

2022-05-09 14:33:20

代码设计设计模式

2023-10-25 14:47:08

架构设计人工智能

2023-10-18 10:42:44

WOT大会架构架构演进

2018-03-12 11:52:44

2021-11-02 06:58:53

架构线程池参数

2020-04-29 14:50:40

代码对比工具

2020-06-17 07:42:14

C语言编程核心

2021-11-17 16:24:23

JS 代码函数声明

2023-03-09 09:14:51

ChatGPTAI

2020-10-14 18:53:14

Python编程语言

2021-06-30 00:14:24

JS代码数组

2020-03-05 09:42:43

JavaJava虚拟机数据库

2018-10-18 11:20:06

编程语言代码编码秘诀

2023-12-13 13:41:00

代码Java程序员

2020-03-02 19:08:21

JVMJDKJRE
点赞
收藏

51CTO技术栈公众号