Java打包混淆之Allatori
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相关推荐
- java代码混淆工具Allatori
目录 1 从官网下载allatori文件 2 Eclipse 下进行代码混淆 2.1 config.xml 详解 3 单个jar文件进行混淆 4 注意事项 1 从官网下载allatori文件 http ...
- java代码混淆器proguard使用大法3种
ProGuard注意事项 1.反射调用类或者方法,可能失败 2.对外接口的类和方法,不要混淆 3.嵌套类 4.native方法 5.枚举类 https://www.guardsquare.com/en ...
- android 子module混淆_Android 多模块打包混淆填坑记
最近有个 sdk 的项目使用了多模块(Module)开发,然后提供 jar 包给接入者使用,要求大部分类是混淆过的,保留几个接口, Android Studio 能够导出 aar 文件,对于导出 ja ...
- Java代码混淆工具ProGuard
目录 Java代码混淆工具ProGuard 简介 描述 作用的环境 功能 工作原理 下载 使用时注意事项 版本问题 JDK位数问题 Java的字节码验证问题 关于使用类似于Hibernate的对象关系 ...
- JAVA代码混淆器大全
JAVA代码混淆器大全 Author/Company Program Shrink. Optim. Obfusc. Preverif. License Eric Lafortune ProGuar ...
- Java代码混淆和加密--Jocky
原文地址为: Java代码混淆和加密--Jocky 1.1 什么是Jocky? 我们知道,Java是一种跨平台的编程语言,其源码(.java文件)被编译成与平台无关的字节码(.class文件),然后在 ...
- java 代码混淆 class字符串加密 jar包war包加密 支持JDK16
1.功能介绍 Java文件是目前最流行的开发语言,因采用对象模式很容易进行整合复用大规模项目开发.但是目前因反编译严重,各行业由java开发的系统很容易本反编译,模仿借鉴,核心代码很容易被盗用. 特别 ...
- java 打包目录_Java打包文件目录问 zip文件
Java打包文件目录问 zip文件. /** * 资源打包下载类 * Created by Ruan Banshu on 2015/4/13. */ public class ZipOpUtil { ...
- Java培训分享5个常用Java代码混淆器
对于Java程序员来说,如果辛辛苦苦写的代码被人摽窃走,将是一件非常恼火的事情.如何保护自己的代码呢,可以通过逆向工程反编译得到Java程序的源代码,这种反编译工具之一就是JAD,尽可能给反编译人员制 ...
最新文章
- python 遍历字典
- 马斯克说到做到!特斯拉牌呼吸机“交货”,用Model 3零部件打造;网友:我滴神啊...
- OpenCV线性搅拌机linear blender的实例(附完整代码)
- 基于Nexys4 DDR的VGA显示图片
- IOT(Index Organized Table)
- 未能正确加载“Microsoft.VisualStudio.Editor.Implementation.EditorPackage“提示信息
- java设计模式-工厂系列
- 在码云上如何创建仓库
- 《数字图像处理 第三版》(冈萨雷斯)——第七章 小波和多分辨率处理
- day02 python基础
- 人工智能与商业智能,区别、定位与联系
- google map 谷歌地图 更改当前定位图标icon大头钉小蓝点
- 在终端输入“python”或者”pip“时出现python’不是内部或外部命令,也不是可运行的程序 或批处理文件
- 第4阶段 Mysql数据库
- 关于系统分析师的考试感想
- VBA小白的福音 如何在EXCEL中实现连续编号自动更新打印?
- 《C Primer Plus》—第九章:函数(指针间接,函数及其定义方式,ANSI C原型,递归,函数调用的底层原理)
- 验证身份证是否真实有效
- pyqt5按钮拖拽,实现拖拽新增和拖拽移动
- 初中生物课堂中提升学生核心素养的有效策略
热门文章
- 2020年计算机专项技能鉴定考试---四川省长宁县职业技术学校
- 光学动作捕捉系统在自动化控制领域中的应用
- 华泰证券研究所谢春生:从全球看金融 IT 架构的变化
- python打印神兽佛祖和美女 | Buddha Bless, No Bug !
- 最新消息:2022高被引科学家名单已公布,都想成为高被引,到底应该怎么做?(附名单)
- Arcgis软件应用(六)利用缓冲区分析和叠置分析进行购房选址
- 银行放水的那些事---必须懂的经济常识
- 电动汽车车载充电机 (OBC) 与车载 DC/DC 转换器技术
- 学生免费领取、配置阿里云服务器
- netstat查看CLOSE_WAIT过多