Allatori配置文件指南
Allatori 配置文件指南
写在前面
刚好最近在研究Java代码混淆,发现Allatori用的人还挺多的,但是相关文档比较少,就去把官网的文档顺手翻译了一下,这个应该适用最新版的Allatori,新版目前还没看到破解的,有些功能估计老版本用不了,等有空再研究研究
1 配置文件结构
1.1 Input 标签
Input 标签用于设置需要混淆的 jar(war、ear)文件或文件夹。该标签中至少应包含一个 jar 或 dir 标签,以指定输入和输出文件。
Input 标签有两个可选属性:
| 属性 | 值 |
|---|---|
| basedir | 可选属性。jar 文件的相对路径将相对于指定的目录进行解析。默认情况下,相对路径会相对于配置文件所在位置进行解析。 |
| single-jar | 可选属性。Allatori 会额外创建一个包含所有混淆后类的输出 jar 文件。 |
Jar 标签有两个必填属性:
| 属性 | 值 |
|---|---|
| in | 必填属性。需要混淆的 jar 文件名称。 |
| out | 必填属性。输出 jar 文件的名称。该名称可以与 in 属性的值相同,此时原 jar 文件会被混淆后的版本覆盖。 |
Jar 标签中可包含嵌套标签,用于混淆 war/ear 文件内部的嵌套 jar 文件:
<jar in="web.war" out="web-obf.war">
<nested in="BOOT-INF/lib/some-library.jar"/>
<nested in="BOOT-INF/lib/my*.jar"/>
</jar>
Dir 标签有两个必填属性:
| 属性 | 值 |
|---|---|
| in | 必填属性。包含需要混淆的类文件的目录名称。 |
| out | 必填属性。用于存放混淆后类文件的输出目录名称。为避免因配置中出现拼写错误而意外删除数据,输出目录在写入新文件前不会被清空。因此,在运行 Allatori 之前,应手动清空输出目录(例如,可使用 Ant 的 delete 任务)。 |
示例:
<input basedir="input-jars" single-jar="application.jar">
<jar in="app.jar" out="app-obf.jar"/>
<jar in="input/*.jar" out="output/*.jar"/>
<jar in="web.war" out="web-obf.war">
<nested in="BOOT-INF/lib/some-library.jar"/>
<nested in="BOOT-INF/lib/my*.jar"/>
</jar>
<dir in="in-dir" out="out-dir"/>
</input>
1.2 Classpath 标签
Classpath 标签用于为待混淆的应用设置类路径,其内部包含嵌套的 jar 标签,这些标签指定了需要添加到类路径中的 jar 文件名称。虽然并非必须引用应用所需的所有库 jar 文件,但缺少类路径元素可能会导致混淆效果减弱。在混淆过程中,Allatori 会对所有缺失的类发出警告。
Classpath 标签有一个可选属性:
| 属性 | 值 |
|---|---|
| basedir | 可选属性。jar 文件的相对路径将相对于指定的目录进行解析。默认情况下,相对路径会相对于配置文件所在位置进行解析。 |
嵌套的 jar 标签有一个必填属性:
| 属性 | 值 |
|---|---|
| name | 必填属性。需要添加到类路径中的 jar 文件名称。支持通配符语法:* 匹配文件名中的任意字符;** 表示递归匹配子目录中的文件。 |
示例:
<classpath basedir="library-jars"> <!-- 将 library.jar 添加到类路径中 -->
<jar name="library.jar"/> <!-- 将 lib 目录下的所有 jar 文件添加到类路径中 -->
<jar name="lib/*.jar"/> <!-- 将 lib2 目录及其子目录下的所有 jar 文件添加到类路径中 -->
<jar name="lib2/**/*.jar"/>
</classpath>
1.3 Keep-names 标签
Keep-names 标签用于设置在混淆过程中不应被重命名的类、方法和字段的名称。如果待混淆的应用是一个库,那么需要保留所有公共 API(应用程序编程接口)的名称;如果是独立应用,则至少需要保留主类的名称。此外,对于通过反射机制使用的类和方法的名称,也应进行保留。
可以使用注解对需要重命名的元素进行更精确的控制,且注解的设置会覆盖配置文件中的相关设置。
Keep-names 标签中可包含任意数量的以下嵌套标签:
- field 标签:用于指定不应被重命名的字段。
- method 标签:用于指定不应被重命名的方法。
- class 标签:用于指定不应被重命名的类,该标签内部还可嵌套 field 和 method 标签。
这些嵌套标签用于设置匹配类、字段和方法名称的规则,符合规则的名称在混淆时不会被修改。所有这些标签都可以设置 access 或 template 属性。
access 属性根据访问级别来匹配元素,其可能的取值如下:
| 值 | 描述 |
|---|---|
| private | 匹配具有 private(私有)访问权限的类、字段或方法。 |
| private+ | 匹配具有 private 或更宽松访问权限(即包访问权限、protected、public)的类、字段或方法。 |
| package | 匹配具有 package(包)访问权限的类、字段或方法。 |
| package+ | 匹配具有 package 或更宽松访问权限(即 protected、public)的类、字段或方法。 |
| protected | 匹配具有 protected(受保护)访问权限的类、字段或方法。 |
| protected+ | 匹配具有 protected 或更宽松访问权限(即 public)的类、字段或方法。 |
| public | 匹配具有 public(公共)访问权限的类、字段或方法。 |
template 属性的语法与 Java 语言语法类似,针对 class、field 和 method 标签,其格式有所不同。
1.3.1 class 标签
class 标签用于匹配类,它具有以下属性:
| 属性 | 值 |
|---|---|
| access | 必选*。用于设置匹配规则,可能的取值如上表所示。 |
| template | 必选*。用于设置匹配规则,其格式如下文所述。 |
| ignore | 可选属性。若设置为 “true” 或 “yes”,则匹配到的类会被重命名,但该类内部嵌套的 method 和 field 标签仍会按正常规则处理。此属性可实现在不保留类名的情况下,保留部分字段和方法的名称。若设置为 “keep-if-members-match”,则只有当至少一个嵌套的 method 或 field 标签也能匹配时,才会保留该类的名称。 |
| stop | 可选属性。若设置为 “true” 或 “yes”,则 Allatori 对匹配到的类不再应用后续的规则。 |
*注:access 和 template 属性二者必填其一。
class 标签的 template 属性格式如下:
[not] [@annotation] [modifiers] (class | interface) classname [extends classname] [implements classname] [instanceof classname]
在类名或类型名中,* 符号可匹配任意数量的字符。若名称以 regex: 开头,则会将其视为标准的正则表达式。
示例:
| 值 | 描述 |
|---|---|
| class * | 匹配所有类和接口。 |
| interface * | 匹配所有接口。 |
| public class * | 匹配所有公共类和公共接口。 |
| protected+ class * | 匹配所有受保护和公共的类与接口。 |
| class abc | 匹配所有全限定名中包含 “abc” 的类。 |
| class com.abc.* | 匹配 com.abc 包及其子包下的所有类。 |
| class .abc. | 匹配所有名称为 “abc” 的包及其子包下的所有类。 |
| class * extends java.util.Enumeration | 匹配所有继承自 java.util.Enumeration 的类。 |
| class * extends *.Enumeration | 匹配所有继承自 Enumeration(无论其所在包)的类。 |
| class * instanceof java.io.Serializable | 匹配所有属于 java.io.Serializable 实例的类(即实现了该接口的类)。 |
| class * implements *.MouseListener | 匹配所有实现了 MouseListener(无论其所在包)的类。 |
| @java.lang.Deprecated class * | 匹配所有被 @java.lang.Deprecated 注解标记的类。 |
| class regex:com.package.(foo | bar).* |
| class regex:com.package.(foo | bar)..* |
| not class com.abc.* | 匹配所有不在 com.abc 包及其子包下的类。 |
1.3.2 field 标签
field 标签用于匹配字段。若该标签嵌套在 class 标签内部,则仅对 class 标签匹配到的类生效;若其父标签为 keep-names,则对所有类生效。field 标签具有以下属性:
| 属性 | 值 |
|---|---|
| access | 必选*。用于设置匹配规则,可能的取值如上表所示。 |
| template | 必选*。用于设置匹配规则,其格式如下文所述。 |
*注:access 和 template 属性二者必填其一。
field 标签的 template 属性格式如下:
[not] [@annotation] [modifiers] [type] fieldname [instanceof classname]
在字段名或类型名中,* 符号可匹配任意数量的字符。若名称以 regex: 开头,则会将其视为标准的正则表达式。
示例:
| 值 | 描述 |
|---|---|
| * | 匹配所有字段。 |
| private * | 匹配所有私有字段。 |
| private+ * | 匹配所有字段(包括私有、包访问权限、受保护、公共字段)。 |
| protected+ * | 匹配所有受保护和公共字段。 |
| static * | 匹配所有静态字段。 |
| public static * | 匹配所有公共静态字段。 |
| public int * | 匹配所有公共的 int 类型字段。 |
| java.lang.String * | 匹配所有 String 类型字段。 |
| java.lang.* * | 匹配所有类型属于 java.lang 包的字段。 |
| abc* | 匹配所有名称以 “abc” 开头的字段。 |
| private abc* | 匹配所有名称以 “abc” 开头的私有字段。 |
| * instanceof java.io.Serializable | 匹配所有可序列化(属于 java.io.Serializable 实例)的字段。 |
| @java.lang.Deprecated * | 匹配所有被 @java.lang.Deprecated 注解标记的字段。 |
| regex:(a | b).* |
| not abc* | 匹配所有名称不以 “abc” 开头的字段。 |
1.3.3 method 标签
method 标签用于匹配方法。若该标签嵌套在 class 标签内部,则仅对 class 标签匹配到的类生效;若其父标签为 keep-names,则对所有类生效。method 标签具有以下属性:
| 属性 | 值 |
|---|---|
| access | 必选*。用于设置匹配规则,可能的取值如上表所示。 |
| template | 必选*。用于设置匹配规则,其格式如下文所述。 |
| parameters | 可选属性。若设置为 “keep”,则方法参数的名称不会被修改,此属性对公共 API 方法非常有用。 |
*注:access 和 template 属性二者必填其一。
method 标签的 template 属性格式如下:
[not] [@annotation] [modifiers] [type] methodname(arguments)
在方法名或类型名中,* 符号可匹配任意数量的字符;在参数列表中,* 匹配单个任意参数,** 则匹配任意数量的参数。若名称以 regex: 开头,则会将其视为标准的正则表达式。
示例:
| 值 | 描述 |
|---|---|
| *(**) | 匹配所有方法。 |
| private *(**) | 匹配所有私有方法。 |
| private+ *(**) | 匹配所有方法(包括私有、包访问权限、受保护、公共方法)。 |
| protected+ *(**) | 匹配所有受保护和公共方法。 |
| private+ () | 匹配所有仅有一个参数的方法。 |
| private+ (,*) | 匹配所有有两个参数的方法。 |
| private+ *(java.lang.String) | 匹配所有仅有一个 String 类型参数的方法。 |
| private+ *(java.lang.String,**) | 匹配所有第一个参数为 String 类型的方法。 |
| private+ (java.lang.) | 匹配所有仅有一个参数且该参数类型属于 java.lang 包的方法。 |
| public get*(**) | 匹配所有名称以 “get” 开头的公共方法(通常为 getter 方法)。 |
| public abc(**) | 匹配所有名称中包含 “abc” 的公共方法。 |
| private+ int *(**) | 匹配所有返回值类型为 int 的方法。 |
| @java.lang.Deprecated *(**) | 匹配所有被 @java.lang.Deprecated 注解标记的方法。 |
| public regex:(g | s)et.*(**) |
| not abc(**) | 匹配所有名称中不包含 “abc” 的方法。 |
示例:
<keep-names>
<!-- 对 com.company.abc 包下的类不再应用后续规则,因此该包下的所有类、方法和字段都会被重命名 -->
<class template="class com.company.abc.*" stop="true"/>
<!-- 后续规则指示 Allatori 不对匹配到的元素进行重命名 -->
<!-- 匹配任意包下名称为 "Main" 的类 -->
<class template="class *.Main"/>
<!-- 匹配名称以 "Bean" 结尾的类 -->
<class template="class *Bean">
<!-- 匹配所有字段 -->
<field access="private+"/>
<!-- 匹配公共的 int 类型字段 -->
<field template="public int *"/>
<!-- 匹配所有静态字段 -->
<field template="static *"/>
<!-- 匹配受保护和公共的 String 类型字段 -->
<field template="protected+ java.lang.String *"/>
<!-- 匹配所有方法 -->
<method template="private+ *(**)"/>
<!-- 匹配所有 getter 方法 -->
<method template="private+ get*(**)"/>
<!-- 匹配所有带有 String 类型参数的方法,且这些方法的参数名称不会被修改 -->
<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>
<!-- 匹配小程序(Applet)相关类 -->
<class template="class * instanceof java.applet.Applet"/>
<!-- 匹配 Servlet 相关类 -->
<class template="class * instanceof javax.servlet.Servlet"/>
<!-- 匹配 MIDlet 相关类(移动应用程序) -->
<class template="class * instanceof javax.microedition.midlet.MIDlet"/>
</keep-names>
1.4 Watermark 标签
Watermark 标签用于设置水印的密钥(key)和值(value),该标签有两个属性:
| 属性 | 值 |
|---|---|
| key | 必填属性。用于通过隐写术将水印嵌入应用程序的密钥。 |
| value | 添加水印时必填属性。将嵌入到应用程序 jar 文件中的任意字符串,可包含版权信息、客户名称、公司名称或其他能唯一标识该构建版本的信息。水印可用于识别软件的所有者,或追踪盗版副本的来源。 |
示例:
<watermark key="secure-key-to-extract-watermark" value="Customer: John Smith"/>
水印也可在不进行混淆的情况下,添加到已混淆或未混淆的 jar 文件中。有关添加和提取水印的完整示例,可在 Allatori 发行版附带的教程中找到。
1.5 Expiry 标签
Expiry 标签用于为应用程序设置过期日期。过期日期检查会被插入到多个方法中,而非仅在主方法中,因此难以轻易移除该功能。此特性也可用于混淆那些甚至没有主方法的库。该标签有两个必填属性:
| 属性 | 值 |
|---|---|
| date | 必填属性。过期日期,格式为 yyyy/mm/dd。 |
| string | 必填属性。当应用程序在指定过期日期之后运行时,抛出异常所携带的字符串信息。 |
示例:
<expiry date="2017/01/01" string="EXPIRED!"/>
有关使用过期日期的完整示例,可在 Allatori 发行版附带的教程中找到。
1.6 Property 标签
Property 标签用于设置各种混淆属性,该标签有两个必填属性:name(属性名)和 value(属性值),格式如下:
<property name="property-name" value="property-value"/>
1.6.1 通用属性(General properties)
1.6.1.1 log-file
| 值 | 描述 |
|---|---|
| filename | Allatori 会将混淆日志写入指定的文件。若未设置该属性,则不会创建日志文件。相对路径会相对于配置文件所在位置进行解析。 |
日志文件用于从混淆后的堆栈跟踪信息恢复原始的堆栈跟踪,它保存了混淆后名称与原始名称、行号之间的映射关系。
示例:
<property name="log-file" value="log.xml"/>
<property name="log-file" value="logs/file.xml"/>
可使用堆栈跟踪工具(Stack trace utility)结合日志文件恢复原始名称,命令如下:
java -cp allatori.jar com.allatori.StackTrace2 log.xml input.txt output.txt
1.6.1.2 random-seed
| 值 | 描述 |
|---|---|
| 任意字符串 | 用于初始化随机数生成器的字符串。 |
该属性的默认值为当前时间(以毫秒为单位)。
默认情况下,若对相同的输入 jar 文件两次运行 Allatori,生成的输出 jar 文件会有所不同。被重命名的类、字段和方法会使用不同的名称,字段和方法的顺序也会不同,这样做是为了增加分析两个不同版本混淆应用程序的难度。若需要在多次连续运行 Allatori 时生成相同的输出 jar 文件,则需设置随机种子(random-seed)。建议为应用程序的不同公开版本设置不同的随机种子。
示例:
<property name="random-seed" value="any text here"/>
1.6.2 字符串加密属性(String encryption properties)
1.6.2.1 string-encryption
| 值 | 描述 |
|---|---|
| enable | (默认值)所有可安全替换为加密值的字符串常量都会被加密,Allatori 会添加一个在运行时解密字符串的方法。 |
| disable | 禁用字符串加密功能。 |
| maximum | 对所有字符串常量进行加密,具体限制见下文说明。 |
| maximum-with-warnings | 对所有字符串常量进行加密。对于使用 == 运算符进行的字符串比较,都会产生警告,用户可将这些比较替换为 equals() 方法调用。 |
在某些情况下,字符串可能会按以下方式进行比较:
String myString = "Hello";
...
public boolean test() {
return myString == "Hello";
}
尽管使用 == 运算符而非 equals 方法比较字符串是一种不良实践,但上述示例中的方法会返回 true,因为 JVM 会缓存 String 对象,以便在同一个类中重复使用。然而,经过字符串加密后,该方法会变为如下形式:
public boolean test() {
return myString == new String("Hello");
// 为使示例更清晰,此处未对 "Hello" 字符串进行加密
}
在这个版本的方法中,由于比较的是不同的对象,因此会返回 false。
若将 string-encryption 属性设置为 enable,Allatori 不会对使用 == 运算符比较的字符串进行加密,从而确保应用程序能正常运行。
若始终使用 equals 方法比较字符串,则可将 string-encryption 属性设置为 maximum。
示例:
<property name="string-encryption" value="enable"/>
可通过注解或 apply2class 属性,对指定类启用或禁用字符串加密功能。其中,apply2class 属性的格式与 class 标签的 template 属性格式相同,示例如下:
<!-- 对 com.abc 包下的类禁用字符串加密 -->
<property name="string-encryption" value="disable" apply2class="class com.abc.*"/>
<!-- 对其他所有类启用字符串加密 -->
<property name="string-encryption" value="enable"/>
1.6.2.2 string-encryption-type
| 值 | 描述 |
|---|---|
| fast | (默认值)Allatori 会使用速度极快的字符串加密算法。 |
| strong | Allatori 会使用强度高且复杂的字符串加密算法,但该算法速度相对较慢。 |
| custom (package.EncryptClassName.encryptMethodName, package.DecryptClassName.decryptMethodName) | Allatori 会使用指定的字符串加密/解密方法,详情见下文说明。 |
该属性需在字符串加密功能已启用的前提下才能生效。
示例:
<property name="string-encryption-type" value="strong"/>
可通过注解或 apply2class 属性,为指定类设置字符串加密类型。apply2class 属性的格式与 class 标签的 template 属性格式相同,示例如下:
<!-- 为 com.abc 包下的类设置高强度字符串加密类型 -->
<property name="string-encryption-type" value="strong" apply2class="class com.abc.*"/>
<!-- 为其他所有类设置快速字符串加密类型 -->
<property name="string-encryption-type" value="fast"/>
自定义字符串加密: 有关使用示例,可在 tutorial/step15-custom-string-encryption 文件夹中查找。
加密方法仅在混淆过程中需要,应用程序运行时无需该方法,它可位于不包含在发行版本中的单独 jar 文件中。解密方法在应用程序运行时需要,可放置在应用程序的任意类中。
可将自定义字符串加密与 Allatori 自带的字符串加密结合使用:
<property name="string-encryption-type"
value="custom(package.EncryptClassName.encryptMethodName, package.DecryptClassName.decryptMethodName)"
apply2class="class com.some.package.*"/>
也可使用多个自定义字符串加密方法:
<property name="string-encryption-type"
value="custom(EncryptClassName1.encryptMethodName1, DecryptClassName1.decryptMethodName1)"
apply2class="class com.some.package.*"/>
<property name="string-encryption-type"
value="custom(EncryptClassName2.encryptMethodName2, DecryptClassName2.decryptMethodName2)"
apply2class="class com.some.other.package.*"/>
<!-- 为未匹配上述规则的类设置的方法 -->
<property name="string-encryption-type"
value="custom(EncryptClassName3.encryptMethodName3, DecryptClassName3.decryptMethodName3)"/>
由于自定义字符串加密特性会在运行时替换字符串,因此它也可用于国际化,而非仅用于加密。在混淆过程中(若字符串加密设置为 maximum),所有字符串都会调用加密方法,因此可利用该方法记录所有字符串;而解密方法则可在运行时将字符串替换为其国际化版本。
1.6.2.3 string-encryption-version
| 值 | 描述 |
|---|---|
| v4 | (默认值)使用新的字符串加密算法。 |
| v3 | Allatori 会使用 3.X 版本中的字符串加密算法。 |
该属性需在字符串加密功能已启用的前提下才能生效。
这并不意味着 v3 版本的算法已过时,我们会不时对 v3 和 v4 版本的算法进行更新,以保证其安全性。引入该属性是因为 v3 和 v4 版本算法的核心思路存在显著差异。
示例:
<property name="string-encryption-version" value="v3"/>
1.6.2.4 string-encryption-ignored-strings
| 值 | 描述 |
|---|---|
| filename | 包含应排除在混淆之外的字符串常量的文本文件,这些字符串不会被加密。 |
指定的文本文件中包含字符串模板,每一行代表一个新的模板,* 可匹配任意数量的任意字符。若模板行以 regex: 开头,则会按正则表达式进行处理,示例如下:
Copyright*
All Rights Reserved*
*CompanyName*
regex:\d+
示例:
<property name="string-encryption-ignored-strings" value="patterns.txt"/>
1.6.3 控制流混淆属性(Control flow obfuscation properties)
1.6.3.1 control-flow-obfuscation
| 值 | 描述 |
|---|---|
| enable | (默认值)Allatori 会修改方法的代码,在不改变应用程序运行时行为的前提下,大幅增加反编译的难度。通常,控制流混淆还能使应用程序体积更小、运行速度更快。 |
| disable | 禁用控制流混淆功能。 |
示例:
<property name="control-flow-obfuscation" value="enable"/>
可通过注解或 apply2class 属性,对指定类启用或禁用控制流混淆功能。apply2class 属性的格式与 class 标签的 template 属性格式相同,示例如下:
<!-- 对 com.abc 包下的类禁用控制流混淆 -->
<property name="control-flow-obfuscation" value="disable" apply2class="class com.abc.*"/>
<!-- 对其他所有类启用控制流混淆 -->
<property name="control-flow-obfuscation" value="enable"/>
1.6.3.2 extensive-flow-obfuscation
| 值 | 描述 |
|---|---|
| normal | (默认值)Allatori 会使用控制流混淆技术,这会使混淆后的应用程序体积略微增大、运行速度略微降低,但 Allatori 会尽量减少此类代码转换的次数。 |
| disable | 禁用深度控制流混淆功能。 |
| maximum | Allatori 会充分使用控制流混淆技术,这会使混淆后的应用程序体积略微增大、运行速度略微降低。 |
该属性需在控制流混淆功能已启用的前提下才能生效。
示例:
<property name="extensive-flow-obfuscation" value="maximum"/>
可通过注解或 apply2class 属性,为指定类设置深度控制流混淆。apply2class 属性的格式与 class 标签的 template 属性格式相同,示例如下:
<!-- 为 com.abc 包下的类设置 "maximum" 级别的深度控制流混淆 -->
<property name="extensive-flow-obfuscation" value="maximum" apply2class="class com.abc.*"/>
<!-- 为其他所有类设置 "normal" 级别的深度控制流混淆 -->
<property name="extensive-flow-obfuscation" value="normal"/>
1.6.4 重命名属性(Renaming properties)
1.6.4.1 default-package
| 值 | 描述 |
|---|---|
| 包名 | 完整的包名,可以是已存在的包名,也可以是新的包名。 |
若某个包中的所有类都被重命名,Allatori 会将这些类移动到默认包(default package)中。若要将所有被重命名的类都移动到默认包,则需启用 force-default-package 属性。将默认包设置为空字符串("")可减小生成的 jar 文件体积。
示例:
<property name="default-package" value=""/>
<property name="default-package" value="com.company.product"/>
1.6.4.2 force-default-package
| 值 | 描述 |
|---|---|
| disable | (默认值)仅将那些所在包中所有类都被重命名的类移动到默认包。 |
| enable | 将所有被重命名的类都移动到默认包。 |
该属性需在已设置默认包(default-package)的前提下才能生效。
示例:
<property name="force-default-package" value="enable"/>
1.6.4.3 packages-naming
| 值 | 描述 |
|---|---|
| abc | (默认值)包名会被重命名为 ‘a’、‘b’、‘c’、’d’……‘aa’、‘ab’ 等,且仅使用小写字母。 |
| ABC | 包名会被重命名为 ‘A’、‘B’、‘C’、‘D’……‘AA’、‘AB’ 等,且仅使用大写字母。 |
| 123 | 包名会被重命名为 ‘1’、‘2’、‘3’……‘00’、‘01’ 等。 |
| keep | 保留包的原始名称。 |
| custom(filename.txt) | 包名会根据指定的文本文件生成,文件的每一行代表一个单独的名称元素。例如,若文件中有两行内容分别为 ‘0’ 和 ‘1’,则生成的包名会是 ‘0’、‘1’、‘00’、‘01’、‘10’、‘11’、‘000’ 等。 |
示例:
<property name="packages-naming" value="abc"/>
1.6.4.4 classes-naming
| 值 | 描述 |
|---|---|
| compact | (默认值)Allatori 会尽可能使用单字符作为类名,以减小生成的 jar 文件体积。类名可能包含大小写字母,且仅大小写不同(例如 a.class 和 A.class)。Jar 文件支持大小写不同的文件名,但 Windows 文件系统不支持,因此在 Windows 系统中解压部分类文件时可能会出现问题(a.class 会覆盖 A.class)。不过,包含此类文件名的 jar 文件在所有平台(包括 Windows)上都能正常运行。 |
| iii | 所有类名都具有相同的长度,且仅大小写不同,例如 iiii、iiiI、iiIi 等。与其他重命名选项相比,生成的 jar 文件体积会更大。 |
| lll | 所有类名都由字符 ’l’(小写字母 L)和 ‘1’(数字 1)组合而成,且具有相同的长度,例如 llll、lll1、ll1l 等。与其他重命名选项相比,生成的 jar 文件体积会更大。 |
| abc | 类名会被重命名为 ‘a’、‘b’、‘c’、’d’……‘aa’、‘ab’ 等,且仅使用小写字母。 |
| ABC | 类名会被重命名为 ‘A’、‘B’、‘C’、‘D’……‘AA’、‘AB’ 等,且仅使用大写字母。 |
| 123 | 类名会被重命名为 ‘1’、‘2’、‘3’……‘00’、‘01’ 等。 |
| windows | Allatori 会使用 Windows 系统中禁止使用的名称(如 ‘con’、‘prn’、‘aux’、’nul’ 等)作为类名。在 jar 文件中包含 con.class 是允许的,但在 Windows 系统中无法解压该类文件。类名也可能包含大小写字母且仅大小写不同,包含此类文件名的 jar 文件在所有平台(包括 Windows)上都能正常运行。与 compact 或 abc 命名方式相比,该选项生成的 jar 文件体积会更大。 |
| custom(filename.txt) | 类名会根据指定的文本文件生成,文件的每一行代表一个单独的名称元素。例如,若文件中有两行内容分别为 ‘0’ 和 ‘1’,则生成的类名会是 ‘0’、‘1’、‘00’、‘01’、‘10’、‘11’、‘000’ 等。 |
| unique | 所有被重命名的类都将拥有唯一的名称,不同包中不会出现相同的类名。该选项可与其他类命名选项结合使用。 |
| keep-$-sign | 被重命名的类会保留 Java 内部类的命名格式,例如类 Foo 和 Foo$Bar 会被重命名为 a 和 a$b。默认情况下,Allatori 会将 Foo 和 Foo$Bar 重命名为 a 和 b。该选项可与其他类命名选项结合使用。 |
示例:
<property name="classes-naming" value="abc"/>
1.6.4.5 methods-naming
| 值 | 描述 |
|---|---|
| compact | (默认值)Allatori 会尽可能使用单字符作为方法名,以减小生成的 jar 文件体积。 |
| iii | 所有方法名都具有相同的长度,且仅大小写不同,例如 iiii、iiiI、iiIi 等。与其他重命名选项相比,生成的 jar 文件体积会更大。 |
| lll | 所有方法名都由字符 ’l’(小写字母 L)和 ‘1’(数字 1)组合而成,且具有相同的长度,例如 llll、lll1、ll1l 等。与其他重命名选项相比,生成的 jar 文件体积会更大。 |
| abc | 方法名会被重命名为 ‘a’、‘b’、‘c’、’d’……‘aa’、‘ab’ 等。 |
| ABC | 方法名会被重命名为 ‘A’、‘B’、‘C’、‘D’……‘AA’、‘AB’ 等。 |
| 123 | 方法名会被重命名为 ‘1’、‘2’、‘3’……‘00’、‘01’ 等。 |
| keywords | Allatori 会使用 Java 保留关键字(如 ‘if’、‘for’、‘int’ 等)作为方法名。这种命名方式在类文件格式中是合法的,但会对许多反编译器造成干扰。不过,与 compact 命名方式相比,该选项生成的 jar 文件体积会更大。 |
| real | 通常,根据配置规则,部分方法不会被重命名。Allatori 会将这些未被重命名的方法名分配给被重命名的方法,使得新方法名与原始方法名之间的差异难以辨别。该选项可与其他方法命名选项结合使用(若该选项的名称用尽,则会使用第二个选项的名称)。 |
| custom(filename.txt) | 方法名会根据指定的文本文件生成,文件的每一行代表一个单独的名称元素。例如,若文件中有两行内容分别为 ‘0’ 和 ‘1’,则生成的方法名会是 ‘0’、‘1’、‘00’、‘01’、‘10’、‘11’、‘000’ 等。 |
| unique | 是 unique-renaming 属性的快捷方式,可与其他方法命名选项结合使用。若两个方法的名称和签名相同,则它们会被重命名为相同的新名称;若两个方法的名称或签名不同,则重命名后的名称也会不同。这能确保在后续的增量混淆过程中保持一致性。 |
示例:
<property name="methods-naming" value="keywords"/>
1.6.4.6 fields-naming
| 值 | 描述 |
|---|---|
| compact | (默认值)Allatori 会尽可能使用单字符作为字段名,以减小生成的 jar 文件体积。 |
| iii | 所有字段名都具有相同的长度,且仅大小写不同,例如 iiii、iiiI、iiIi 等。与其他重命名选项相比,生成的 jar 文件体积会更大。 |
| lll | 所有字段名都由字符 ’l’(小写字母 L)和 ‘1’(数字 1)组合而成,且具有相同的长度,例如 llll、lll1、ll1l 等。与其他重命名选项相比,生成的 jar 文件体积会更大。 |
| abc | 字段名会被重命名为 ‘a’、‘b’、‘c’、’d’……‘aa’、‘ab’ 等。 |
| ABC | 字段名会被重命名为 ‘A’、‘B’、‘C’、‘D’……‘AA’、‘AB’ 等。 |
| 123 | 字段名会被重命名为 ‘1’、‘2’、‘3’……‘00’、‘01’ 等。 |
| keywords | Allatori 会使用 Java 保留关键字(如 ‘if’、‘for’、‘int’ 等)作为字段名。这种命名方式在类文件格式中是合法的,但会对许多反编译器造成干扰。不过,与 compact 命名方式相比,该选项生成的 jar 文件体积会更大。 |
| real | 通常,根据配置规则,部分字段不会被重命名。Allatori 会将这些未被重命名的字段名分配给被重命名的字段,使得新字段名与原始字段名之间的差异难以辨别。该选项可与其他字段命名选项结合使用(若该选项的名称用尽,则会使用第二个选项的名称)。 |
| custom(filename.txt) | 字段名会根据指定的文本文件生成,文件的每一行代表一个单独的名称元素。例如,若文件中有两行内容分别为 ‘0’ 和 ‘1’,则生成的字段名会是 ‘0’、‘1’、‘00’、‘01’、‘10’、‘11’、‘000’ 等。 |
| unique | 所有被重命名的字段都将拥有唯一的名称,该选项可与其他字段命名选项结合使用。 |
示例:
<property name="fields-naming" value="keywords"/>
1.6.4.7 classes-naming-prefix
| 值 | 描述 |
|---|---|
| 任意字符串 | 指定的字符串会作为所有被重命名类的名称前缀。 |
示例:
<property name="classes-naming-prefix" value="c_"/>
该属性的一种可能用法是将 MainClass$ 设为前缀:
<property name="classes-naming-prefix" value="MainClass$"/>
此时,部分反编译器会将被重命名的类视为 MainClass 的内部类。
1.6.4.8 methods-naming-prefix
| 值 | 描述 |
|---|---|
| 任意字符串 | 指定的字符串会作为所有被重命名方法的名称前缀。 |
示例:
<property name="methods-naming-prefix" value="m_"/>
1.6.4.9 fields-naming-prefix
| 值 | 描述 |
|---|---|
| 任意字符串 | 指定的字符串会作为所有被重命名字段的名称前缀。 |
示例:
<property name="fields-naming-prefix" value="f_"/>
1.6.4.10 local-variables-naming
| 值 | 描述 |
|---|---|
| optimize | (默认值)Allatori 会对方法中的局部变量进行优化,以减少局部变量的总数。剩余的局部变量会使用相同的名称(单名称重命名选项),这是默认且推荐的选项。 |
| single-name | 几乎所有局部变量都会使用相同的名称,这种方式符合 Java 虚拟机的规范,但会对许多反编译器造成干扰。 |
| abc | 局部变量会被重命名为唯一的名称,如 ‘a’、‘b’、‘c’、’d’ 等。 |
| remove | 移除局部变量的原始名称,这有助于减小生成的 jar 文件体积。 |
| keep-parameters | 保留参数名称不变,其他局部变量会被重命名。该选项对属于公共 API 的方法非常有用。此外,也可通过 keep-names 部分中的 method 标签,仅对指定方法保留参数名称。 |
| keep | 保留所有局部变量的原始名称,不推荐使用该选项。 |
示例:
<property name="local-variables-naming" value="single-name"/>
对于 single-name 和 optimize 重命名选项,默认的单名称为 ‘a’,可通过以下任意一行代码修改该默认名称:
<property name="local-variables-naming" value="optimize:ANY_OTHER_NAME"/>
<property name="local-variables-naming" value="optimize:int"/>
<property name="local-variables-naming" value="single-name:4"/>
1.6.4.11 skip-renaming
| 值 | 描述 |
|---|---|
| disable | (默认值)Allatori 会根据 keep-names 规则对类、方法和字段进行重命名。 |
| enable | 所有类、方法和字段都不会被重命名。局部变量的命名由 local-variables-naming 属性单独控制。字符串加密、控制流混淆等功能会根据配置文件中的设置正常应用。 |
示例:
<property name="skip-renaming" value="enable"/>
1.6.4.12 update-resource-names
| 值 | 描述 |
|---|---|
| disable | (默认值)不修改资源文件的名称。 |
| enable | 资源文件的名称会根据类名的变更进行修改。若资源文件的名称基于某个类名,且该类被重命名,则对应的资源文件也会被重命名。 |
示例:
<property name="update-resource-names" value="enable"/>
1.6.4.13 update-resource-contents
| 值 | 描述 |
|---|---|
| disable | (默认值)不修改资源文件的内容。 |
| enable | 资源文件的内容会根据类名的变更进行更新。 |
| enable:ENCODING | 使用指定的编码格式,根据类名的变更更新资源文件的内容,默认编码格式为 UTF-8。 |
示例:
<property name="update-resource-contents" value="enable"/>
<property name="update-resource-contents" value="enable:UTF-8"/>
可通过 apply2file 属性,将该属性应用于指定的文件:
<property name="update-resource-contents" value="enable" apply2file="*.xml"/>
1.6.5 其他属性(Other properties)
1.6.5.1 line-numbers
| 值 | 描述 |
|---|---|
| obfuscate | (默认值)调试信息会被混淆,不经过进一步处理无法使用。Allatori 提供了一个专用工具,可借助混淆后的堆栈跟踪信息重建原始的堆栈跟踪。混淆后报告的堆栈跟踪如下所示:java.lang.NullPointerExceptionat com.company.c.a(m:61)at com.company.b.b(w:94)at com.company.b.a(w:83)at com.company.a.a(n:75)使用 Allatori 堆栈跟踪工具转换后,堆栈跟踪会变为:java.lang.NullPointerExceptionat com.company.Util.createTestException(Util.java:38) at com.company.TraceTest.testNullObject(TraceTest.java:53)at com.company.TraceTest.allTraceTests(TraceTest.java:14)at com.company.Main.runTest(Main.java:27)使用该选项可减小生成的 jar 文件体积。 |
| remove | 当应用程序的体积至关重要时,可使用该选项。移除行号后报告的堆栈跟踪如下所示:java.lang.NullPointerExceptionat com.company.c.a(Unknown Source)at com.company.c.b(Unknown Source)at com.company.c.c(Unknown Source)at com.company.c.d(Unknown Source) |
| keep | 保留调试信息,不做任何修改。该选项在应用程序内部测试时可能有所帮助,在其他情况下,建议选择其他选项。保留行号后报告的堆栈跟踪如下所示:java.lang.NullPointerExceptionat com.company.c.a(Util.java:38)at com.company.b.a(TraceTest.java:14)at com.company.a.a(Main.java:27) |
(默认值)调试信息会被混淆,不经过进一步处理无法使用。Allatori 提供了一个专用工具,可借助混淆后的堆栈跟踪信息重建原始的堆栈跟踪。混淆后报告的堆栈跟踪如下所示:```java java.lang.NullPointerException at com.company.c.a(m:61) at com.company.b.b(w:94) at com.company.b.a(w:83) at com.company.a.a(n:75)
示例:
```xml
<property name="line-numbers" value="obfuscate"/>
1.6.5.2 generics
| 值 | 描述 |
|---|---|
| keep | (默认值)若使用反射机制确定泛型类型,或需要使用混淆后的 jar 文件作为库来编译其他类,则需保留泛型类型签名。 |
| remove | 移除泛型类型信息,例如字符串向量 Vector 会被视为普通的 Vector。该选项不影响应用程序的性能,还能减小 jar 文件体积,是推荐选项。 |
示例:
<property name="generics" value="remove"/>
可通过 apply2class 属性,为指定类设置该属性。apply2class 属性的格式与 class 标签的 template 属性格式相同,示例如下:
<!-- 保留 com.abc 包下类的泛型类型信息 -->
<property name="generics" value="keep" apply2class="class com.abc.*"/>
<!-- 移除其他所有类的泛型类型信息 -->
<property name="generics" value="remove"/>
1.6.5.3 inner-classes
| 值 | 描述 |
|---|---|
| keep | (默认值)Java 编译器会添加包含内部类名称的信息属性,这些属性在混淆后的类中会被保留。 |
| remove | 移除这些信息属性,使得类的层次结构更难被还原。该选项不影响应用程序的性能,还能减小 jar 文件体积,是推荐选项。 |
示例:
<property name="inner-classes" value="remove"/>
可通过 apply2class 属性,为指定类设置该属性。apply2class 属性的格式与 class 标签的 template 属性格式相同,示例如下:
<!-- 保留 com.abc 包下类的内部类信息 -->
<property name="inner-classes" value="keep" apply2class="class com.abc.*"/>
<!-- 移除其他所有类的内部类信息 -->
<property name="inner-classes" value="remove"/>
1.6.5.4 throws-clause
| 值 | 描述 |
|---|---|
| keep | (默认值)保留方法的 throws 声明(异常声明)。 |
| remove | Java 虚拟机允许抛出未在方法中通过 throws 关键字声明的异常。此思路与 Lombok 的 sneaky throws(隐式抛出异常)类似,但此处用于混淆目的。 |
示例:
<property name="throws-clause" value="remove"/>
可通过 apply2class 和/或 apply2method 属性,为指定类/方法设置该属性。apply2class 属性的格式与 class 标签的 template 属性格式相同,apply2method 属性的格式与 method 标签的 template 属性格式相同,示例如下:
<!-- 移除所有私有方法的 throws 声明 -->
<property name="throws-clause" value="remove" apply2method="private *(**)"/>
<!-- 移除 com.abc 包下类的 throws 声明 -->
<property name="throws-clause" value="remove" apply2class="class com.abc.*"/>
1.6.5.5 member-reorder
| 值 | 描述 |
|---|---|
| enable | (默认值)通常,开发人员会在源文件中按逻辑将相关的方法和字段排列在一起,这种顺序在编译后会被保留。Allatori 会打乱字段和方法的顺序。 |
| random | 与 enable 功能相同,即随机打乱字段和方法的顺序。 |
| alphabetical | 按字母顺序排列字段和方法。 |
| reverse-alphabetical | 按字母逆序排列字段和方法。 |
| disable | 禁用成员重排功能。 |
示例:
<property name="member-reorder" value="random"/>
可通过 apply2class 属性,为指定类设置该属性。apply2class 属性的格式与 class 标签的 template 属性格式相同,示例如下:
<!-- 对 com.abc 包下的类进行成员重排 -->
<property name="member-reorder" value="random" apply2class="class com.abc.*"/>
<!-- 不对其他所有类进行成员重排 -->
<property name="member-reorder" value="disable"/>
1.6.5.6 finalize
| 值 | 描述 |
|---|---|
| disable | (默认值)禁用类的 final 修饰(即不将类声明为最终类)。 |
| enable | 没有子类的类(叶子类)会被声明为 final(最终类)。该特性仅应用于混淆独立应用程序,使用后可能使应用程序运行速度更快。 |
示例:
<property name="finalize" value="enable"/>
1.6.5.7 version-marker
| 值 | 描述 |
|---|---|
| 有效的 Java 标识符 | Allatori 会将给定的标识符用作部分被重命名方法和字段的名称,以此为混淆后的类文件添加标记。该属性可用于标记产品的演示版本,例如 Allatori 演示版本会使用 “ALLATORI_DEMO” 字符串进行标记。请注意,Allatori 演示版本会对混淆后的 jar 文件进行标记,并在该属性值前添加 “ALLATORI_DEMO_” 前缀。 |
示例:
<property name="version-marker" value="THIS_IS_DEMO_VERSION"/>
1.6.5.8 synthetize-methods
| 值 | 描述 |
|---|---|
| private | (默认值)所有私有方法都会被标记为 synthetic(合成方法)。 |
| all | 所有方法都会被标记为 synthetic。 |
| package | 所有具有包访问权限的方法都会被标记为 synthetic。 |
| protected | 所有受保护方法都会被标记为 synthetic。 |
| public | 所有公共方法都会被标记为 synthetic。 |
| disable | Allatori 不会将任何方法标记为 synthetic。 |
部分反编译器不会显示 synthetic 方法。
示例:
<property name="synthetize-methods" value="all"/>
该属性可多次使用:
<property name="synthetize-methods" value="private"/>
<property name="synthetize-methods" value="package"/>
<property name="synthetize-methods" value="protected"/>
可通过 apply2class 属性,为指定类设置该属性。apply2class 属性的格式与 class 标签的 template 属性格式相同,示例如下:
<property name="synthetize-methods" value="all" apply2class="class com.abc.*"/>
<property name="synthetize-methods" value="private"/>
1.6.5.9 synthetize-fields
| 值 | 描述 |
|---|---|
| disable | (默认值)Allatori 不会将任何字段标记为 synthetic(合成字段)。 |
| all | 所有字段都会被标记为 synthetic。 |
| private | 所有私有字段都会被标记为 synthetic。 |
| package | 所有具有包访问权限的字段都会被标记为 synthetic。 |
| protected | 所有受保护字段都会被标记为 synthetic。 |
| public | 所有公共字段都会被标记为 synthetic。 |
部分反编译器不会显示 synthetic 字段。
示例:
<property name="synthetize-fields" value="all"/>
该属性可多次使用:
<property name="synthetize-fields" value="private"/>
<property name="synthetize-fields" value="package"/>
<property name="synthetize-fields" value="protected"/>
可通过 apply2class 属性,为指定类设置该属性。apply2class 属性的格式与 class 标签的 template 属性格式相同,示例如下:
<property name="synthetize-fields" value="all" apply2class="class com.abc.*"/>
<property name="synthetize-fields" value="private"/>
1.6.5.10 set-methods-to-public
| 值 | 描述 |
|---|---|
| disable | (默认值)Allatori 不会将任何方法的访问权限修改为 public(公共)。 |
| all | 所有方法的访问权限都会被修改为 public。需注意,将私有方法修改为公共方法可能会破坏应用程序的功能。 |
| private | 所有私有方法的访问权限都会被修改为 public。将私有方法修改为公共方法可能会破坏应用程序的功能。 |
| package | 所有具有包访问权限的方法的访问权限都会被修改为 public。 |
| protected | 所有受保护方法的访问权限都会被修改为 public。 |
示例:
<property name="set-methods-to-public" value="all"/>
该属性可多次使用:
<property name="set-methods-to-public" value="package"/>
<property name="set-methods-to-public" value="protected"/>
可通过 apply2class 属性,为指定类设置该属性。apply2class 属性的格式与 class 标签的 template 属性格式相同,示例如下:
<property name="set-methods-to-public" value="all" apply2class="class com.abc.*"/>
<property name="set-methods-to-public" value="protected"/>
1.6.5.11 set-fields-to-public
| 值 | 描述 |
|---|---|
| disable | (默认值)Allatori 不会将任何字段的访问权限修改为 public(公共)。 |
| all | 所有字段的访问权限都会被修改为 public。 |
| private | 所有私有字段的访问权限都会被修改为 public。 |
| package | 所有具有包访问权限的字段的访问权限都会被修改为 public。 |
| protected | 所有受保护字段的访问权限都会被修改为 public。 |
示例:
<property name="set-fields-to-public" value="all"/>
该属性可多次使用:
<property name="set-fields-to-public" value="package"/>
<property name="set-fields-to-public" value="protected"/>
可通过 apply2class 属性,为指定类设置该属性。apply2class 属性的格式与 class 标签的 template 属性格式相同,示例如下:
<property name="set-fields-to-public" value="all" apply2class="class com.abc.*"/>
<property name="set-fields-to-public" value="protected"/>
1.6.5.12 remove-toString
| 值 | 描述 |
|---|---|
| disable | (默认值)不删除 toString 方法。 |
| enable | Allatori 会删除混淆类中的 toString() 方法。toString 方法可能会泄露类的相关信息,且通常仅用于调试,因此可以将其删除。 |
示例:
<property name="remove-toString" value="enable"/>
可通过 apply2class 属性,为指定类设置该属性。apply2class 属性的格式与 class 标签的 template 属性格式相同,示例如下:
<property name="remove-toString" value="enable" apply2class="class com.abc.*"/>
<property name="remove-toString" value="enable" apply2class="class com.xyz.*"/>
1.6.5.13 remove-calls
| 值 | 描述 |
|---|---|
| ClassName.methodName | Allatori 会移除对指定方法的调用,该属性可用于移除调试日志相关的调用。ClassName(类名)和 methodName(方法名)中可包含 *,以匹配多个类/方法。若被移除调用的方法有返回值,则该返回值会被替换为 null(数值类型替换为 0,布尔类型替换为 false),且 Allatori 会在混淆过程中输出警告信息。 |
示例:
<property name="remove-calls" value="android.util.Log.d"/>
<property name="remove-calls" value="android.util.Log.*"/>
// 若 methodOne() 方法的调用被移除,则以下代码行
int i = methodOne();
// 会被修改为
int i = 0;
// 若 methodTwo() 方法的调用被移除,则以下代码行
Object o = methodTwo();
// 会被修改为
Object o = null;
可通过 apply2class 属性,为指定类设置该属性。apply2class 属性的格式与 class 标签的 template 属性格式相同,示例如下:
<!-- 移除 com.abc 包下类中对 Logger.debug 方法的调用 -->
<property name="remove-calls" value="com.package.Logger.debug" apply2class="class com.abc.*"/>
1.6.5.14 remove-annotations
| 值 | 描述 |
|---|---|
| AnnotationClassName | Allatori 会移除指定的 AnnotationClassName(注解类名)对应的注解,该属性可用于移除不必要的注解或调试用注解。AnnotationClassName 中可包含 *,以匹配多个注解类。 |
示例:
<property name="remove-annotations" value="kotlin.Metadata"/>
<property name="remove-annotations" value="com.package.annotations.*"/>
可通过 apply2class 属性,为指定类设置该属性。apply2class 属性的格式与 class 标签的 template 属性格式相同,示例如下:
<!-- 移除 com.abc 包下类中的 com.package.Annotation 注解 -->
<property name="remove-annotations" value="com.package.Annotation" apply2class="class com.abc.*"/>
1.6.5.15 output-jar-compression-level
| 值 | 描述 |
|---|---|
| 0-9 | 设置输出 jar 文件的压缩级别,0 表示不压缩,9 表示最高压缩级别,该属性值直接映射到 ZipOutputStream.setLevel(int) 方法的参数。 |
示例:
<property name="output-jar-compression-level" value="9"/>
1.6.5.16 output-jar-duplicate-name-entries
| 值 | 描述 |
|---|---|
| remove | (默认值)若输入 jar 文件的同一文件夹中包含多个名称相同的文件,Allatori 仅会在输出 jar 文件中保留一个文件。 |
| keep | Allatori 会将所有名称重复的 jar 条目写入输出 jar 文件。Zip(jar)文件格式允许存在名称重复的条目,但标准 Java API 不支持写入此类条目。若要在 Java 16+ 版本中运行 Allatori 以实现此功能,需在运行 JVM 时添加 --add-opens java.base/java.util.zip=ALL-UNNAMED 选项;在旧版本 Java 中,则需添加 --illegal-access=permit 选项。 |
示例:
<property name="output-jar-duplicate-name-entries" value="keep"/>
1.6.6 增量混淆属性(Incremental obfuscation properties)
1.6.6.1 incremental-obfuscation
| 值 | 描述 |
|---|---|
| 先前创建的日志文件名称 | 指定上一次 Allatori 运行生成的日志文件名称,相对路径会相对于配置文件所在位置进行解析。增量混淆用于为应用程序创建补丁或附加组件,在这种情况下,需要确保类、方法和字段的新名称与之前混淆版本中的名称保持一致。将上一次 Allatori 运行生成的日志文件作为下一次混淆的输入,可使这两个版本完全兼容,从而让补丁或附加组件能无缝集成到之前部署的应用程序中。使用增量混淆时,即使只需分发部分类,也需将所有类纳入混淆过程。 |
示例:
<property name="incremental-obfuscation" value="input-renaming-log.xml"/>
1.6.6.2 unique-renaming
| 值 | 描述 |
|---|---|
| disable | (默认值)禁用唯一重命名功能。 |
| enable | 若两个方法的名称和签名相同,则它们会被重命名为相同的新名称;若两个方法的名称或签名不同,则重命名后的名称也会不同。该属性可确保在后续的增量混淆过程中保持一致性。 |
示例:
<property name="unique-renaming" value="enable"/>
可通过 apply2class 属性,为指定类设置该属性。apply2class 属性的格式与 class 标签的 template 属性格式相同,示例如下:
<property name="unique-renaming" value="enable" apply2class="class com.abc.*"/>
1.7 Ignore-classes 标签
Ignore-classes 标签用于将部分类完全排除在混淆过程之外,这些类会原封不动地复制到输出 jar 文件中。需注意,被排除的类会以原始名称引用其他类,因此无法对被排除类所引用的类/方法进行重命名。
该标签包含嵌套的 class 标签,这些标签与 keep-names 部分中的 class 标签用法相同。
示例:
<ignore-classes>
<class template="class com.company.abc.*"/>
<class template="class com.company.xyz.SomeClass"/>
</ignore-classes>
2 注解(Annotations)
注解类位于 allatori-annotations.jar 文件中。在混淆过程中,所有 Allatori 注解都会被移除,因此应用程序运行时无需该 jar 文件。注解用于更便捷、更精确地配置混淆器。
以下是 com.allatori.annotations 包中所有可用的注解:
| 注解 | 适用对象 | 描述 |
|---|---|---|
| Rename | 类、方法和字段 | 指示 Allatori 对带注解的元素进行重命名,该注解会覆盖配置文件中的设置。 |
| DoNotRename | 类、方法和字段 | 指示 Allatori 不对带注解的元素进行重命名,该注解会覆盖配置文件中的设置。 |
| StringEncryption | 类 | 可能的取值如下:StringEncryption.ENABLEStringEncryption.DISABLEStringEncryption.MAXIMUMStringEncryption.MAXIMUM_WITH_WARNINGS该注解会覆盖 string-encryption 属性的设置,示例:@StringEncryption(StringEncryption.ENABLE) |
| StringEncryptionType | 类 | 可能的取值如下:StringEncryptionType.FASTStringEncryptionType.STRONG该注解会覆盖 string-encryption-type 属性的设置,示例:@StringEncryptionType(StringEncryptionType.STRONG) |
| ControlFlowObfuscation | 类和方法 | 可能的取值如下:ControlFlowObfuscation.ENABLEControlFlowObfuscation.DISABLE该注解会覆盖 control-flow-obfuscation 属性的设置,示例:@ControlFlowObfuscation(ControlFlowObfuscation.ENABLE) |
| ExtensiveFlowObfuscation | 类和方法 | 可能的取值如下:ExtensiveFlowObfuscation.DISABLEExtensiveFlowObfuscation.NORMALExtensiveFlowObfuscation.MAXIMUM该注解会覆盖 extensive-flow-obfuscation 属性的设置,示例:@ExtensiveFlowObfuscation(ExtensiveFlowObfuscation.MAXIMUM) |
3 Android 混淆(Android obfuscation)
Allatori 支持对 Android 应用程序进行全功能混淆,且能轻松集成到构建流程中。我们已为 Android 项目创建了一个典型的配置文件,极大简化了 Android 应用程序的混淆操作。有关配置文件(allatori.xml)和示例构建文件(build.gradle 和 build.xml),可在 Allatori 发行版附带的教程中找到。
3.1 使用 Android Studio
在 Android Studio 项目中设置 Allatori 需执行以下三个步骤:
- 在项目的 rootDir(根目录)文件夹中创建 allatori 文件夹,并将 allatori.jar 文件复制到该文件夹中;
- 从教程中复制 allatori.xml 文件到项目的 projectDir 文件夹(项目的 build.gradle 文件所在目录);
- 编辑 build.gradle 文件:
android {
...
// 针对应用程序(application 类型项目)
applicationVariants.all { variant ->
variant.javaCompileProvider.get().doLast {
runAllatori(variant)
}
}
// 针对库(library 类型项目)
// libraryVariants.all { variant ->
// variant.javaCompileProvider.get().doLast {
// runAllatori(variant)
// }
// }
}
def runAllatori(variant) {
copy {
from "$projectDir/allatori.xml"
into "$buildDir/intermediates/classes/"
expand(classesRoot: variant.javaCompileProvider.get().destinationDir,
kotlinRoot: "${buildDir}/tmp/kotlin-classes/${variant.name}",
androidJar: "${android.sdkDirectory}/platforms/${android.compileSdkVersion}/android.jar",
classpathJars: variant.javaCompileProvider.get().classpath.getAsPath(),
logFile: "allatori-log-${variant.name}.xml")
rename('allatori.xml', "allatori-${variant.name}.xml")
}
new File("${variant.javaCompileProvider.get().destinationDir}-obfuscated").deleteDir()
javaexec {
main = 'com.allatori.Obfuscate'
classpath = files("$rootDir/allatori/allatori.jar")
args "$buildDir/intermediates/classes/allatori-${variant.name}.xml"
}
new File("${variant.javaCompileProvider.get().destinationDir}").deleteDir()
new File("${variant.javaCompileProvider.get().destinationDir}-obfuscated").renameTo(new File("${variant.javaCompileProvider.get().destinationDir}"))
// Kotlin 支持(若项目使用 Kotlin)
// new File("${buildDir}/tmp/kotlin-classes/${variant.name}").deleteDir()
// new File("${buildDir}/tmp/kotlin-classes/${variant.name}-obfuscated").renameTo(new File("${buildDir}/tmp/kotlin-classes/${variant.name}"))
}
3.2 使用 Ant
在 Android Ant 项目中设置 Allatori 需执行以下三个步骤:
- 在项目文件夹中创建 allatori 文件夹,并将 allatori.jar 文件复制到该文件夹中;
- 从教程中复制 allatori.xml 文件到项目文件夹;
- 在 build.xml 文件中添加以下目标(target):
<target name="-obfuscate" unless="do.not.compile">
<taskdef name="allatori" classname="com.allatori.ant.ObfuscatorTask"
classpath="allatori/allatori.jar"/>
<delete dir="${out.classes.absolute.dir}-obfuscated"/>
<allatori config="allatori.xml"/>
<property name="out.dex.input.absolute.dir"
value="${out.classes.absolute.dir}-obfuscated"/>
</target>
可能需要根据项目实际情况进行进一步配置。在 Allatori 配置文件中,可使用标准 Ant 语法 ${PropertyName} 引用 Ant 构建文件中定义的属性。
4 Eclipse IDE 插件(Eclipse IDE plugin)
Allatori 可轻松与 Eclipse IDE 配合使用,操作步骤如下:
- 将 allatori.jar 文件复制到 eclipse/dropins 文件夹;
- 在 Eclipse 中右键单击项目名称,在弹出的菜单中选择“Configure -> Add Allatori Builder”(配置 -> 添加 Allatori 构建器)(参见截图);
- 执行“Clean rebuild”(清理并重新构建)操作,混淆过程仅在清理构建时运行。
首次运行时,会在项目的根文件夹中创建默认的 allatori.xml 配置文件。
在配置文件中,可使用 ${eclipse-input} 和 ${eclipse-classpath} 属性:
<input>
${eclipse-input}
</input>
<classpath>
${eclipse-classpath}
</classpath>