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()"/>