• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Arkguard
2Arkguard 是Javascript和Typescript的源码混淆工具。
3
4# 在DevEco Studio中的用法
5Arkguard已经被集成了到SDK中。可以在DevEco Studio中很方便地使用。Arkguard只能用于Stage模型
6(不支持FA模型)。目前Arkguard只提供名称混淆的能力(因为其它混淆能力会劣化性能)。
7使用Arkguard可以混淆以下名称:
8* 参数名和局部变量名
9* 顶层作用域的名称
10* 属性名称
11
12Arkguard默认使能对参数名和局部变量名的混淆。顶层作用域名称和属性名称的混淆是默认关闭的,
13因为默认打开可能会导致运行时错误。你可以通过[混淆选项](#混淆选项)来开启它们。
14
15创建一个新工程的时候,配置文件`build-profile.json5`中会自动生成以下内容:
16```
17"arkOptions": {
18  "obfuscation": {
19    "ruleOptions": {
20      "enable": true,
21      "files": ["obfuscation-rules.txt"],
22    }
23  }
24}
25```
26创建一个新的library的时候,还会额外生成`consumerFiles`属性:
27```
28"arkOptions": {
29  "obfuscation": {
30    "ruleOptions": {
31      "enable": true,
32      "files": ["obfuscation-rules.txt"],
33    }
34    "consumerFiles": ["consumer-rules.txt"]
35  }
36}
37```
38
39要想开启混淆,需要满足下面的条件:
40* 属性`ruleOptions.enable`的值为`true`,并且所有依赖的library的`ruleOptions.enable`属性是`true`
41* 在release模式构建
42
43属性`ruleOptions.files`中指定的混淆配置文件会在构建HAP或HAR的时候被应用。
44
45属性`consumerFiles`中指定的混淆配置文件会在构建依赖这个library的工程或library时被应用。
46这些混淆配置文件的内容还会被合并到HAR包中的`obfuscation.txt`文件。
47
48当构建HAP或者HAR的时候,最终的混淆规则是自身的`ruleOptions.files`属性,依赖的library的`consumerFiles`属性,
49以及依赖的HAR包中的`obfuscation.txt`文件的合并。如果构建的是HAR,`obfuscation.txt`是自身的`consumerFiles`属性,
50依赖的library的`consumerFiles`属性,以及依赖的HAR包中的`obfuscation.txt`文件的合并。
51构建HAP不会生成`obfuscation.txt`。详细合并的策略可以查看[混淆规则合并策略](#混淆规则合并策略)。
52
53## 配置混淆规则
54在创建工程或library的时候,DevEco Studio会自动生成`obfuscation-rules.txt`和`consumer-rules.txt`文件,
55但是它们默认不会包含任何混淆规则。你可以在这些文件中写混淆规则,或者也可以将规则写在其它文件,
56然后将文件路径放到`ruleOptions.files`和`consumerFiles`中,如下面的例子所示。
57```
58"buildOption": {
59  "arkOptions": {
60    "obfuscation": {
61      "ruleOptions": {
62        "enable": true,
63        "files": ["obfuscation-rules.txt", "myrules.txt"],
64      }
65      "consumerFiles": ["consumer-rules.txt", "my-consumer-rules.txt"]
66    }
67  }
68}
69```
70
71在混淆规则文件中,你可以写[混淆选项](#混淆选项)和[保留选项](#保留选项)。
72
73### 混淆选项
74
75`-disable-obfuscation`
76
77关闭所有混淆。如果你使用这个选项,那么构建出来的HAR或HAR将不会被混淆。默认情况下,
78Arkguard只混淆参数名和局部变量名(通过将它们重新命名为随机的短名字)。
79
80`-enable-property-obfuscation`
81
82开启属性混淆。 如果你使用这个选项,那么所有的属性名都会被混淆,除了下面场景:
83* 被`import/export`的类或对象的属性名不会被混淆。注意: 只有直接导出的类或对象的属性名不会被混淆。
84比如下面例子中的属性名`data`不会被混淆。
85    ```
86    export class MyClass {
87       data: string;
88    }
89    ```
90对于间接导出的场景,比如`export MyClass`和`let a = MyClass; export a;`,如果你不想混淆它们的属性名,
91那么你需要使用[保留选项](#保留选项)来保留这些属性名。另外,对于直接导出的类或对象的属性的属性名,比如下面例子中的`name`和`age`, 如果你不想混淆它们,那么你也需要使用[保留选项](#保留选项)来保留这些属性名。
92    ```
93    export class MyClass {
94       person = {name: "123", age: 100};
95    }
96    ```
97* ArkUI组件中的属性名不会被混淆。比如下面例子中的`message`和`data`不会被混淆。
98    ```
99    @Component struct MyExample {
100        @State message: string = "hello";
101        data: number[] = [];
102        ...
103    }
104    ```
105* 被[保留选项](#保留选项)指定的属性名不会被混淆。
106* 系统API列表中的属性名不会被混淆。系统API列表是构建时从SDK中自动提取出来的一个名称列表。
107* 字符串字面量属性名不会被混淆。比如下面例子中的`"name"`和`"age"`不会被混淆。
108    ```
109    let person = {"name": "abc"};
110    person["age"] = 22;
111    ```
112    如果你想混淆字符串字面量属性名,你需要在该选项的基础上再使用`-enable-string-property-obfuscation`选项。比如
113    ```
114    -enable-property-obfuscation
115    -enable-string-property-obfuscation
116    ```
117    注意:如果你的代码里面有字符串属性名包含特殊字符(除了`a-z, A-Z, 0-9, _`之外的字符),比如`let obj = {"\n": 123, "": 4, " ": 5}`,我们建议不要开启`-enable-string-property-obfuscation`选项,因为当你不想混淆这些名字时,可能无法通过[保留选项](#保留选项)来指定保留这些名字。
118
119`-enable-toplevel-obfuscation`
120
121开启顶层作用域名称混淆。如果你使用这个选项,那么所有的顶层作用域的名称都会被混淆,除了下面场景:
122* 被`import/export`的名称不会被混淆。
123* 当前文件找不到声明的名称不会被混淆。
124* 被[保留选项](#保留选项)指定的顶层作用域名称不会被混淆。
125* 系统API列表中的顶层作用域名称不会被混淆。
126
127`-compact`
128
129去除不必要的空格符和所有的换行符。如果你使用这个选项,那么所有代码会被压缩到一行。
130
131`-remove-log`
132
133删除所有`console.*`语句。
134
135`-print-namecache` filepath
136
137将名称缓存保存到指定的文件路径。名称缓存包含名称混淆前后的映射。如果你使用了`-enable-property-obfuscation`或
138`-enable-toplevel-obfuscation`选项,并且你希望未来进行增量编译(比如热修复),那么你应该使用这个选项,
139并且将缓存文件保管好。
140
141`-apply-namecache` filepath
142
143复用指定的名称缓存文件。名字将会被混淆成缓存映射对应的名字,如果没有对应,将会被混淆成新的随机段名字。
144该选项应该在增量编译场景中被使用。
145
146默认情况下,DevEco Studio会在临时的缓存目录中保存缓存文件,并且在增量编译场景中自动应用该缓存文件。
147
148### 保留选项
149
150保留选项只有在使用`enable-property-obfuscation`或`enable-toplevel-obfuscation`选项时发挥作用。
151
152`-keep-property-name` [,modifiers,...]
153
154指定你想保留的属性名。比如下面的例子:
155```
156-keep-property-name
157age
158firstName
159lastName
160```
161
162**哪些属性名应该被保留?**
163
164为了保障混淆的正确性,我们建议你保留所有不通过点语法访问的属性。
165
166例子:
167```
168var obj = {x0: 0, x1: 0, x2: 0};
169for (var i = 0; i <= 2; i++) {
170    console.log(obj['x' + i]);  // x0, x1, x2 应该被保留
171}
172
173Object.defineProperty(obj, 'y', {});  // y 应该被保留
174console.log(obj.y);
175
176obj.s = 0;
177let key = 's';
178console.log(obj[key]);        // s 应该被保留
179
180obj.u = 0;
181console.log(obj.u);           // u 可以被正确地混淆
182
183obj.t = 0;
184console.log(obj['t']);        // 在开启字符串字面量属性名混淆时t和't'会被正确地混淆,但是我们建议保留
185
186obj['v'] = 0;
187console.log(obj['v']);        // 在开启字符串字面量属性名混淆时'v'会被正确地混淆,但是我们建议保留
188```
189
190`-keep-global-name` [,modifiers,...]
191
192指定要保留的顶层作用域的名称。比如,
193```
194-keep-global-name
195Person
196printPersonName
197```
198
199**哪些顶层作用域的名称应该被保留?**
200
201在Javascript中全局变量是`globalThis`的属性。如果在代码中使用`globalThis`去访问全局变量,那么该变量名应该被保留。
202
203例子:
204```
205var a = 0;
206console.log(globalThis.a);  // a 应该被保留
207
208function foo(){}
209globalThis.foo();           // foo 应该被保留
210
211var c = 0;
212console.log(c);             // c 可以被正确地混淆
213
214function bar(){}
215bar();                      // bar 可以被正确地混淆
216
217class MyClass {}
218let d = new MyClass();      // MyClass 可以被正确地混淆
219```
220
221`-keep-dts` filepath
222
223保留指定路径的`.d.ts`文件中的名称。这里的文件路径可以是一个目录,这种情况下目录中所有`.d.ts`文件中的名称都会被保留。
224如果在构建HAR时使用了这个选项,那么文件中的名称会被合并到最后的`obfuscation.txt`文件中。
225
226### 注释
227
228可以使用`#`在混淆规则文件中进行注释。每行以`#`开头的文本会被当做是注释,比如下面的例子:
229```
230# white list for MainAbility.ets
231-keep-global-name
232MyComponent
233GlobalFunction
234
235-keep-property-name # white list for dynamic property names
236firstName
237lastName
238age
239```
240构建HAR时,注释不会被合并到最后的`obfuscation.txt`文件中。
241
242### 混淆规则合并策略
243一个工程中经常会有许多混淆规则文件,这些文件来自于:
244* 主工程的`ruleOptions.files` (这里主工程我们指的是正在构建的工程)
245* 本地依赖的library中的`consumerFiles`选项中指定的文件
246* 远程依赖的HAR包中的`obfuscate.txt`文件
247
248当构建主工程的时候,这些文件中的混淆规则会按照下面的合并策略(伪代码)进行合并:
249```
250let `listRules` 表示上面提到的所有混淆规则文件的列表
251let finalRule = {
252    disableObfuscation: false,
253    enablePropertyObfuscation: false,
254    enableToplevelObfuscation: false,
255    compact: false,
256    removeLog: false,
257    keepPropertyName: [],
258    keepGlobalName: [],
259    keepDts: [],
260    printNamecache: string,
261    applyNamecache: string
262}
263for each file in `listRules`:
264    for each option in file:
265        switch(option) {
266            case -disable-obfuscation:
267                finalRule.disableObfuscation = true;
268                continue;
269            case -enable-property-obfuscation:
270                finalRule.enablePropertyObfuscation = true;
271                continue;
272            case -enable-toplevel-obfuscation:
273                finalRule.enableToplevelObfuscation = true;
274                continue;
275            case -compact:
276                finalRule.compact = true;
277                continue;
278            case -remove-log:
279                finalRule.removeLog = true;
280                continue;
281            case -print-namecache:
282                finalRule.printNamecache = #{指定的路径名};
283                continue;
284            case -apply-namecache:
285                finalRule.applyNamecache = #{指定的路径名};
286                continue;
287            case -keep-property-name:
288                finalRule.keepPropertyName.push(#{指定的名称});
289                continue;
290            case -keep-global-name:
291                finalRule.keepGlobalName.push(#{指定的名称});
292                continue;
293            case -keep-dts:
294                finalRule.keepDts.push(#{指定的路径});
295                continue;
296        }
297    end-for
298end-for
299```
300最后使用的混淆规则来自于对象`finalRule`。
301
302如果构建的是HAR,那么最终的`obfuscate.txt`文件内容来自于主工程和本地依赖的library的`consumerFiles`选项,
303以及依赖的HAR的`obfuscate.txt`文件的合并。合并策略和上面一样,除了以下的不同:
304* `-keep-dts`选项会被转换成`-keep-global-name`和`-keep-property-name`。
305* `-print-namecache`和`apply-namecache`选项会被忽略,不会出现在最后的`obfuscate.txt`文件中。
306