1.前言

熟悉Java的人都知道Java代码编译成class文件就可以部署运行了,但是class文件通过jdk-gui等工具是很容易反编译就看到源代码的,在代码给到客户私有化部署时,为了保护咱们自己的知识产权,我们会使用加密、花指令、混淆等方式对代码进行保护,其中加密方式时最安全的,但是实现需要比较强的能力,花指令其实就是防止反编译,而混淆就是提升代码反编译之后的阅读障碍。混淆是简单而且易于操作的,所以基础的保护就采用这中方式,但是混淆也是有对应反混淆的工具的,所以如果是超级严格的知识产权保护,一般都是采用混淆配合另外两种方式一起使用的,我这里是采用第三方混淆工具Allatori对我们的代码进行混淆的,还有另外一个常用的纯java开发的混淆工具是ProGuard。

2.Allatori

Allatori是第二代Java混淆器,Allatori不仅能混淆代码还提供了很多附加功能,使得被Allatori混淆的代码几乎不可能被逆向解析,同时Allatori还可以最小化应用程序的大小,提升代码运行速度,Allatori和其他混淆器一样具有水印和过期功能。

2.1Allatori配置文件的结构以及各个标签的作用

<config><!-- input标签是用来设置将要被混淆的jar(war,ear)文件的,input标签至少必须包含一个jar或dir标签来配置输入输出文件  --><!-- input标签的basedir属性,可选配置,用来设置jar文件的相对文件目录的 --><!-- input标签的single-jar属性,可选配置,Allatori会创建一个包含所有混淆过的类的额外输出jar文件--><input basedir="input-jars" single-jar="application.jar"><!-- jar标签,设置输入输出文件,这种是具体的jar文件,输入输出同名的话,混淆后的文件会覆盖混淆前的为文件  --><jar in="app.jar" out="app-obf.jar"/><!-- jar标签,通配符的配置方式  --><jar in="input/*.jar" out="output/*.jar"/><!-- dir标签,配置输入输出目录  --><dir in="in-dir" out="out-dir"/></input><!-- classpath标签用于设置被混淆程序的类路径,它不必配置应用程序所需的所有jar包,但是缺少依赖包可能混淆没那么彻底,同时混淆的过程中也可能会出现告警 --><!-- basedir,与input的basedir同理,配置一个相对路径 --><classpath basedir="library-jars"><!-- 添加一个library.jar的jar到类路径中 --><jar name="library.jar"/><!-- 配置一个目录下的jar到类路径 --><jar name="lib/*.jar"/><!-- 配置lib2下的目录以及它的子目录下的jar到类路径 --><jar name="lib2/**/*.jar"/></classpath><!-- keep-names标签用于在混淆过程中标记不需要重命名的类、方法、字段的名称,所以该标签下有class/method/field这三种标签。通常不建议混淆的几种情况如下:  --><!-- 1.如果混淆的jar是一个公共类库,那么public类型的api就不能被混淆(即不需要重命名) --><!-- 2.如果混淆的jar是一个独立的应用程序,那么该应用程序的启动类即主类不应该被混淆 --><!-- 3.如果某些类和方法被反射使用了,那么这些类和方法也不应该被混淆 --><keep-names><!-- class标签用来匹配类,它有access、template、ignore、stop四个属性,至少要带有access、template中的一个属性 --><!-- access通过访问权限隔离来匹配,带加号('+'),表示更宽的权限范围都可以匹配上 --><!-- template通过表达式来匹配,*标识通配符 --><!-- ignore可选,当它设置为'true'或'yes'时,类会被混淆,但是方法和属性不会被混淆 --><!-- stop可选,当它设置为'true'或'yes'时,类、方法、属性都会被混淆 --><!-- stop属性,控制是否被重命名,等于true,配置的class com.company.abc.*下的类、方法、属性都会被重命名 --><class template="class com.company.abc.*" stop="true"/><!-- 下面是不需要重名名的规则 --><!-- 匹配任何包下名字为'Main'的类 --><class template="class *.Main"/><!-- 匹配以‘Bean’结尾的类 --><class template="class *Bean"><!-- 匹配所有的属性,access匹配方式 --><field access="private+"/><!-- 匹配所有public int的属性 --><field template="public int *"/><!-- 匹配所有的静态属性 --><field template="static *"/><!-- 匹配所有protected和public且为String的属性 --><field template="protected+ java.lang.String *"/><!-- 匹配所有方法 --><method template="private+ *(**)"/><!-- 匹配所有Get方法 --><method template="private+ get*(**)"/><!-- 匹配所有参数为String的方法,同时parameters="keep"会使方法的参数不会被混淆 --><method template="private+ *(java.lang.String)" parameters="keep"/></class><!-- 匹配序列化的类 --><class template="class * instanceof java.io.Serializable"><field template="static final long serialVersionUID"/><method template="void writeObject(java.io.ObjectOutputStream)"/><method template="void readObject(java.io.ObjectInputStream)"/><method template="java.lang.Object writeReplace()"/><method template="java.lang.Object readResolve()"/></class><!-- 匹配所有applets --><class template="class * instanceof java.applet.Applet"/><!-- 匹配所有servlets --><class template="class * instanceof javax.servlet.Servlet"/><!-- 匹配所有 midlets --><class template="class * instanceof javax.microedition.midlet.MIDlet"/></keep-names><!-- ignore-classes标签配置忽略混淆的类,被忽略混淆的类所引用的类和方法也不会被混淆 --><!-- ignore-classes的匹配规则和keep-names的匹配规则是一样的 --><ignore-classes><class template="class com.company.abc.*"/><class template="class com.company.xyz.SomeClass"/></ignore-classes><!-- watermark标签是用来设置水印的标签的,它有key和value两个属性,不管jar是否混淆,都可以添加水印 --><!--  key必填,应用程序嵌入水印的密钥 --><!-- value必须,水印的具体类容,可以是版本、客户名称、公司名称等等,也可以通过额外的配置文件去配置--><watermark key="secure-key-to-extract-watermark" value="Customer: John Smith"/><!-- expiry标签设置应用程序的过期时间,它有两个属性data、string --><!-- data到期日期,必填,yyyy/mm/dd格式 --><!-- string,必填,程序到期后的提示信息 --><expiry date="2017/01/01" string="EXPIRED!"/><!-- property标签用来设置不同混淆处理的属性,它有两个属性,name和value--><!-- name为log-file的属性是日志文件,日志文件用来从混淆后的堆栈还原原始堆栈跟踪的,它保持对名称和行号的原始映射的混淆 --><!-- value 为日志文件名或路劲加文件名,不配置的话,日志就不会被创建--><property name="log-file" value="log.xml"/><!-- random-seed随机种子,不设置的情况下,每次混淆出来的jar内容其实都是不一样的,这样每次重新打包无法分析差异,以及定位问题,随机种子就保证了同一应用程序可以输出相同的混淆jar,同一应用程序的不同版本我们应该使用不同的随机种子  --><!-- 随机种子的值可以是任何文本,默认值为当前时间的毫秒数 --><property name="random-seed" value="any text here"/><!-- string-encryption, encryption虽然是加密的意思,但这里这个标签我觉得应该是string字符串比较的优化,可能会导致结果与源代码的不一致--><property name="string-encryption" value="enable"/><!-- 通过apply2class设置不同的加密类型应用于不同的类下的字符串,加密类型有三种:fast、strong、custom --><!-- fast,默认类型,Allatori将使用非常快速的字符串混淆算法 --><!-- strong,Allatori将使用强大而复杂的字符串混淆算法,但是这比较缓慢 --><!-- custom,Allatori将使用指定的字符串混淆算法 --><property name="string-encryption-type" value="strong" apply2class="class com.abc.*"/><!-- string-encryption-version 混淆字符串的算法版本,默认V4,V4和V3是不同算法思想,不代表V3过时 --><property name="string-encryption-version" value="v3"/><!-- string-encryption-ignored-strings 设置该文件中包含的字符串都不会被混淆 --><property name="string-encryption-ignored-strings" value="patterns.txt"/><!-- 通过apply2class启动或禁用控制流混淆处理,属性有enable 和 disable --><!-- enable默认属性,Allatori会修改方法的代码,但不会改变程序运行的行为,这会使得反编译更困难,同时使程序更小更快 --><property name="control-flow-obfuscation" value="disable" apply2class="class com.abc.*"/><!-- 配置指定的类使用控制流混淆处理,它有三种属性normal、disable、maximum --><!-- normal默认,Allatori默认混淆程序控制流,这会让程序更大更慢,Allatori也会尽量少的去转换--><!-- disable,禁用控制流混淆 --><!-- maximum,充分使用控制流混淆 --><property name="extensive-flow-obfuscation" value="maximum" apply2class="class com.abc.*"/><!-- 配置默认包的名称,如果某个包下的所有类都被重命名了,该包下的类就会被移动到这个默认包下,配置空字符会使得输出包变小 --><property name="default-package" value="com.company.product"/><!-- 是否强制将所有重命名的类移动到默认包下,默认disable --><!-- disable默认,只有包下所有的类重命名了才会移动到默认包下面,否则只有重命名了,类就会被移动到默认包下 --><property name="force-default-package" value="enable"/><!-- 包混淆命名规则,有abc、123、keep、customer四种 --><!-- abc/123,包名混淆会被命名为abc/123等等字符串或数字,默认abc --><!-- keep 维持包的原名字,即不混淆 --><!-- custom(filename.txt) 自定义,名字从配置的文件中取--><property name="packages-naming" value="abc"/><!-- 类名字的混淆规则 --><!-- compact默认,尽可能的使用单字符混淆类名,可能存在a和A的class --><!-- iii/abc/123 使用罗马数字/字符串/阿拉伯数字命名 --><!-- windows 使用windows上禁用的名称作为类名('con'、'prn'、'aux'、'nul'等)--><!-- custom(filename.txt) 自定义,从自定义文件中取--><!-- unique 类名的混淆唯一 --><!-- keep-$-sign 类名重命名保留java内部的命名符号$ --><property name="classes-naming" value="abc"/><!-- 方法名混淆命名规则,跟类名混淆类似,没有 keep-$-sign,多了real和keywords --><!-- real,方法名没被配置规则所重命名就会被命名为重命名方法 --><!-- keywords,使用java的保留字命名--><property name="methods-naming" value="keywords"/><!-- 属性混淆命名,同方法名一样的规则 --><property name="fields-naming" value="keywords"/><!-- 指定的字符串会作为所有重命名类、方法、属性的前缀 --><property name="classes-naming-prefix" value="c_"/><property name="methods-naming-prefix" value="m_"/><property name="fields-naming-prefix" value="f_"/><!-- optimize默认,局部变量名优化,减少局部变量名,尽量使用同一名称 --><!-- single-name,几乎所有的局部变量名使用同一名称--><!-- abc,局部变量名使用a/b/c等字符串--><!-- remove,删除原始的局部变量名--><!-- keep-parameters,参数名不变,局部变量名被重命名--><!-- keep 保留原局部变量,但不推荐--><property name="local-variables-naming" value="single-name"/> <!-- disable默认,Allatori根据keep names规则执行类、方法和字段的重命名 --><!-- enable,不会重命名所有类、方法和字段。局部变量命名由局部变量命名属性单独控制。根据配置文件中的设置,将正常应用字符串加密、流混淆等--><property name="skip-renaming" value="enable"/><!-- 资源文件重命名,diable默认,不重命名 --><property name="update-resource-names" value="enable"/><!-- 指定资源文件内容的字符编码集 --><property name="update-resource-contents" value="enable" apply2file="*.xml"/><!-- 堆栈信息行号设置,obfuscate默认,堆栈信息行号也会被混淆,不过可以恢复--><!-- remove 移除堆栈信息行号,keep 保留原始堆栈信息行号--><property name="line-numbers" value="obfuscate"/><!-- keep 如果您使用反射来确定泛型类型,或者需要使用模糊化jar作为库来编译其他类,那么您需要保留泛型类型签名。 --><!-- remove 移除泛型 --><property name="generics" value="keep" apply2class="class com.abc.*"/><!-- Java内部类设置,keep默认混淆类的内部类会被保留 --><!-- remove 会移除信息属性和改变类结构--><property name="inner-classes" value="keep" apply2class="class com.abc.*"/><!-- Allatori将会混淆类内部的字段和方法的顺序,enable默认,random和enable相同会混淆顺序 --><!-- alphabetic字段和方法将会按照字母顺序排列,disable类内部的方法和属性顺序混淆不可用 --><property name="member-reorder" value="random" apply2class="class com.abc.*"/><!-- 设置进行类垃圾回收,disable默认,默认禁用类回收,enable 无子类的类将会被设置为final,这个设置仅用于独立应用程序 --><property name="finalize" value="enable"/><!-- Allatori将使用给定的标识符重命名方法和字段的名称,这会标记你的混淆文件,你可以用这些来标记你的演示版本 --><!-- 这个值会添加到'ALLATORI_DEMO_'后面作为你的演示版本的名称 --><property name="version-marker" value="THIS_IS_DEMO_VERSION"/><!-- 标记为复合的方法,private,all,package,protected,public,disable,根据权限来确定是否标记 --><property name="synthetize-methods" value="all" apply2class="class com.abc.*"/><!-- 标记为复合的属性,private,all,package,protected,public,disable,根据权限来确定是否标记 --><property name="synthetize-fields" value="all" apply2class="class com.abc.*"/><!-- 移除toString方法,disable默认不会移除,enable由于toString通常用于调试,故会删除toString方法 --><property name="remove-toString" value="enable" apply2class="class com.abc.*"/><!-- 移除指定方法的调用,可用于删除调试日志记录调用 --><property name="remove-calls" value="com.package.Logger.debug" apply2class="class com.abc.*"/><!-- 是否删除一些注释,可用于删除不必要的或者调试的注释 --><property name="remove-annotations" value="com.package.Annotation" apply2class="class com.abc.*"/><!-- 设置压缩级别,根据ZipOutputStream来的0不压缩,9最高压缩 --><property name="output-jar-compression-level" value="9"/><!-- 如果输入jar的同文件目录下包含了同名文件是否保留一个,remove默认保留一个 --><!-- Allatori允许同名文件的输出,但是java标准api不允许,所以你要设置JVM的‑‑illegal‑access=permit参数保留同名文件 --><property name="output-jar-duplicate-name-entries" value="keep"/><!-- 设置增量log文件,用来保证这次的混淆跟上次的混淆相同部分的一致性 --><property name="incremental-obfuscation" value="input-renaming-log.xml"/><!-- 同名方法混淆一致性的设置,disabled默认禁用,enable,同名方法和属性混淆后的名字和属性也是一致的 --><property name="unique-renaming" value="enable" apply2class="class com.abc.*"/>
</config>

3.maven结合Allatori混淆springBoot项目

3.1从官网demo中copy出jar包

3.2配置pom文件

  <!-- resouces拷贝文件插件 --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-resources-plugin</artifactId><version>2.6</version><!-- 插件执行的时候申明所有的phase--><executions><execution><id>copy-allatori-config</id><phase>package</phase><goals><goal>copy-resources</goal></goals><configuration><!-- 拷贝文件的目录,我们最终打包存放的位置是target目录 --><outputDirectory>${basedir}/target</outputDirectory><resources><resource><!-- 这个目录放recsource,是因为resource打包时本身会被copy到target中 --><directory>src/main/resources</directory><includes><!-- Allatori配置文件的文件名 --><include>allatori.xml</include></includes><filtering>true</filtering></resource></resources></configuration></execution></executions></plugin><!-- 执行java程序,这里执行的是混淆的jar包程序,对代码进行混淆 --><plugin><groupId>org.codehaus.mojo</groupId><artifactId>exec-maven-plugin</artifactId><version>1.2.1</version><executions><execution><id>run-allatori</id><phase>package</phase><goals><goal>exec</goal></goals></execution></executions><configuration><includePluginDependencies>true</includePluginDependencies><executable>java</executable><arguments><argument>-Xms128m</argument><argument>-Xmx512m</argument><argument>-jar</argument><!-- 指定应用的Allatori的jar包的位置,我放在了当前项目的allatori文件下 --><argument>allatori/allatori.jar</argument><!-- 制定代码混淆时的配置文件,混淆时jar包是在target目录下,我们的配置文件也要在那个目录下 --><argument>${basedir}/target/allatori.xml</argument></arguments></configuration></plugin>

maven的pom文件这是需要新增的两个插件,其他之前配置的插件不用动就行

3.3配置allatori配置文件allatori.xml

<config><input><!-- 配置输入输出jar,输入是混淆前的jar,输出是混淆后的jar,可以同名,同名会覆盖 --><jar in="test.jar" out="obf-test.jar"/></input><!-- 混淆jar的依赖包,可以不配置,但是混淆时会出现告警或者error,配置了混淆更彻底 --><classpath><jar name="snc-dpm-biz/lib/*.jar"/></classpath><!-- 保持命名的类、方法、属性 --><keep-names><!-- 由于Mybatis的mapper的实现类使用了反射,所以一般不重命名 --><class template="class *Mapper"><method template="public *(**)"/></class></keep-names><!-- 混淆忽略的类  --><ignore-classes><!-- 一般包含框架的类,springboot的启动类,Vo类,外部公共api等等 --><class template="class com.shsnc.dpm.Run"/></ignore-classes><!-- 保持方法的参数命名,不进行混淆,这个是为了controller对应前端的传参,也可以不混淆controller --><property name="local-variables-naming" value="keep-parameters"/><!-- 混淆后,前后名字对照的日志文件,一般是为了多次混淆结果一致去配置的 --><property name="log-file" value="log.xml"/>
</config>

allatori.xml的可配置的东西很多,参考第二部分配置文件的结构中的解释说明,这里只是个简单的配置

3.4混淆打包后的结果

混淆后的项目启动其实会报错,然后查看报错的信息,根据报错信息剔除掉报错类的混淆,直到项目启动且运行无误

springboot混淆包启动报错的常见情况

由于springboot遵循约定大于配置的问题,所以很多默认的配置是基于命名的,而混淆又是以重命名为主要手段的,所以springboot项目混淆后一定会报错,springboot项目包混淆需要注意的
1.保持类名唯一,spring的核心bean定义是会以类的类名的首字母小写来命名bean并实例化到spring容器中的,因此必须保证类名唯一

 <!-- 类名重命名唯一,防止spring容器中存在bean定义相同的key值,但实际是不同class的冲突问题 --><property name="classes-naming" value="unique"/><!-- 给类名加前缀,这样就算类名唯一,只是大小写不一样的情况下,也不会发生类定义冲突的问题 --><property name="classes-naming-prefix" value="d_"/>

2.有用到反射,Class的类建议不混淆
3.Mapper接口不混淆,mybatis默认也是通过JDK动态代理来生成实现类的,动态代理也用到了反射
4.框架以及第三方组件相关的包建议不混淆,springframework,alibba,Redission等
5.对外的api的参数名不混淆

 <!-- 保持方法的参数命名,不进行混淆,可以添加apply2class属性缩小范围 --><property name="local-variables-naming" value="keep-parameters"/>

6.有用到feign接口的,不混淆,feign也是动态代理实现的
7.自动注入,同类型的不同实例,建议都加Qualifier指定名字去注入实例,比如kafkaTemplate,RedisTemplate等存在多个的时候

4.总结

1.混淆的配置,需要多多去尝试才能理解偷不同配置的作用
2.混淆只是提高代码阅以及反编译难度,进一步的代码安全还是要通过混淆结合加密等方式去进行,混淆虽然号称不可反编译,实际还是可以反编译的,另外为了保证项目的完整性,很难混淆到自己真正想混淆的代码,核心知识的保护,我觉得还是需要使用更加可靠的手段去保护,混淆只是个初级手段。

Java打包混淆之Allatori相关推荐

  1. java代码混淆工具Allatori

    目录 1 从官网下载allatori文件 2 Eclipse 下进行代码混淆 2.1 config.xml 详解 3 单个jar文件进行混淆 4 注意事项 1 从官网下载allatori文件 http ...

  2. java代码混淆器proguard使用大法3种

    ProGuard注意事项 1.反射调用类或者方法,可能失败 2.对外接口的类和方法,不要混淆 3.嵌套类 4.native方法 5.枚举类 https://www.guardsquare.com/en ...

  3. android 子module混淆_Android 多模块打包混淆填坑记

    最近有个 sdk 的项目使用了多模块(Module)开发,然后提供 jar 包给接入者使用,要求大部分类是混淆过的,保留几个接口, Android Studio 能够导出 aar 文件,对于导出 ja ...

  4. Java代码混淆工具ProGuard

    目录 Java代码混淆工具ProGuard 简介 描述 作用的环境 功能 工作原理 下载 使用时注意事项 版本问题 JDK位数问题 Java的字节码验证问题 关于使用类似于Hibernate的对象关系 ...

  5. JAVA代码混淆器大全

      JAVA代码混淆器大全 Author/Company Program Shrink. Optim. Obfusc. Preverif. License Eric Lafortune ProGuar ...

  6. Java代码混淆和加密--Jocky

    原文地址为: Java代码混淆和加密--Jocky 1.1 什么是Jocky? 我们知道,Java是一种跨平台的编程语言,其源码(.java文件)被编译成与平台无关的字节码(.class文件),然后在 ...

  7. java 代码混淆 class字符串加密 jar包war包加密 支持JDK16

    1.功能介绍 Java文件是目前最流行的开发语言,因采用对象模式很容易进行整合复用大规模项目开发.但是目前因反编译严重,各行业由java开发的系统很容易本反编译,模仿借鉴,核心代码很容易被盗用. 特别 ...

  8. java 打包目录_Java打包文件目录问 zip文件

    Java打包文件目录问 zip文件. /** * 资源打包下载类 * Created by Ruan Banshu on 2015/4/13. */ public class ZipOpUtil { ...

  9. Java培训分享5个常用Java代码混淆器

    对于Java程序员来说,如果辛辛苦苦写的代码被人摽窃走,将是一件非常恼火的事情.如何保护自己的代码呢,可以通过逆向工程反编译得到Java程序的源代码,这种反编译工具之一就是JAD,尽可能给反编译人员制 ...

最新文章

  1. python 遍历字典
  2. 马斯克说到做到!特斯拉牌呼吸机“交货”,用Model 3零部件打造;网友:我滴神啊...
  3. OpenCV线性搅拌机linear blender的实例(附完整代码)
  4. 基于Nexys4 DDR的VGA显示图片
  5. IOT(Index Organized Table)
  6. 未能正确加载“Microsoft.VisualStudio.Editor.Implementation.EditorPackage“提示信息
  7. java设计模式-工厂系列
  8. 在码云上如何创建仓库
  9. 《数字图像处理 第三版》(冈萨雷斯)——第七章 小波和多分辨率处理
  10. day02 python基础
  11. 人工智能与商业智能,区别、定位与联系
  12. google map 谷歌地图 更改当前定位图标icon大头钉小蓝点
  13. 在终端输入“python”或者”pip“时出现python’不是内部或外部命令,也不是可运行的程序 或批处理文件
  14. 第4阶段 Mysql数据库
  15. 关于系统分析师的考试感想
  16. VBA小白的福音 如何在EXCEL中实现连续编号自动更新打印?
  17. 《C Primer Plus》—第九章:函数(指针间接,函数及其定义方式,ANSI C原型,递归,函数调用的底层原理)
  18. 验证身份证是否真实有效
  19. pyqt5按钮拖拽,实现拖拽新增和拖拽移动
  20. 初中生物课堂中提升学生核心素养的有效策略

热门文章

  1. 2020年计算机专项技能鉴定考试---四川省长宁县职业技术学校
  2. 光学动作捕捉系统在自动化控制领域中的应用
  3. 华泰证券研究所谢春生:从全球看金融 IT 架构的变化
  4. python打印神兽佛祖和美女 | Buddha Bless, No Bug !
  5. 最新消息:2022高被引科学家名单已公布,都想成为高被引,到底应该怎么做?(附名单)
  6. Arcgis软件应用(六)利用缓冲区分析和叠置分析进行购房选址
  7. 银行放水的那些事---必须懂的经济常识
  8. 电动汽车车载充电机 (OBC) 与车载 DC/DC 转换器技术
  9. 学生免费领取、配置阿里云服务器
  10. netstat查看CLOSE_WAIT过多