js-confuser 2.0.0-alpha.5 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/ISSUE_TEMPLATE/bug_report.md +43 -43
- package/.github/ISSUE_TEMPLATE/feature_request.md +20 -20
- package/.github/workflows/node.js.yml +28 -28
- package/.prettierrc +4 -4
- package/CHANGELOG.md +1015 -989
- package/CODE_OF_CONDUCT.md +131 -131
- package/CONTRIBUTING.md +52 -52
- package/LICENSE +21 -21
- package/Migration.md +72 -71
- package/README.md +86 -78
- package/dist/constants.js +43 -43
- package/dist/index.js +14 -23
- package/dist/obfuscator.js +31 -25
- package/dist/order.js +4 -4
- package/dist/presets.js +31 -31
- package/dist/templates/integrityTemplate.js +4 -4
- package/dist/templates/template.js +1 -2
- package/dist/transforms/astScrambler.js +1 -2
- package/dist/transforms/calculator.js +1 -2
- package/dist/transforms/controlFlowFlattening.js +93 -63
- package/dist/transforms/deadCode.js +1 -2
- package/dist/transforms/dispatcher.js +4 -5
- package/dist/transforms/extraction/duplicateLiteralsRemoval.js +1 -2
- package/dist/transforms/extraction/objectExtraction.js +1 -2
- package/dist/transforms/finalizer.js +1 -2
- package/dist/transforms/flatten.js +1 -2
- package/dist/transforms/identifier/globalConcealing.js +15 -2
- package/dist/transforms/identifier/movedDeclarations.js +8 -7
- package/dist/transforms/identifier/renameVariables.js +7 -7
- package/dist/transforms/lock/integrity.js +11 -10
- package/dist/transforms/lock/lock.js +2 -3
- package/dist/transforms/minify.js +11 -29
- package/dist/transforms/opaquePredicates.js +1 -2
- package/dist/transforms/pack.js +5 -2
- package/dist/transforms/plugin.js +18 -19
- package/dist/transforms/preparation.js +16 -16
- package/dist/transforms/renameLabels.js +1 -2
- package/dist/transforms/rgf.js +8 -9
- package/dist/transforms/shuffle.js +1 -2
- package/dist/transforms/string/encoding.js +1 -2
- package/dist/transforms/string/stringCompression.js +3 -4
- package/dist/transforms/string/stringConcealing.js +8 -3
- package/dist/transforms/string/stringEncoding.js +1 -2
- package/dist/transforms/variableMasking.js +1 -2
- package/dist/utils/NameGen.js +2 -2
- package/dist/utils/PredicateGen.js +1 -2
- package/dist/utils/ast-utils.js +87 -88
- package/dist/utils/function-utils.js +8 -8
- package/dist/utils/node.js +5 -6
- package/dist/utils/object-utils.js +4 -4
- package/dist/utils/random-utils.js +20 -20
- package/dist/utils/static-utils.js +1 -2
- package/dist/validateOptions.js +4 -7
- package/index.d.ts +17 -17
- package/package.json +61 -59
- package/src/constants.ts +168 -168
- package/src/index.ts +118 -118
- package/src/obfuscationResult.ts +49 -49
- package/src/obfuscator.ts +501 -497
- package/src/options.ts +407 -407
- package/src/order.ts +54 -54
- package/src/presets.ts +125 -125
- package/src/templates/bufferToStringTemplate.ts +57 -57
- package/src/templates/deadCodeTemplates.ts +1185 -1185
- package/src/templates/getGlobalTemplate.ts +76 -76
- package/src/templates/integrityTemplate.ts +64 -64
- package/src/templates/setFunctionLengthTemplate.ts +11 -11
- package/src/templates/stringCompressionTemplate.ts +20 -20
- package/src/templates/tamperProtectionTemplates.ts +120 -120
- package/src/templates/template.ts +224 -224
- package/src/transforms/astScrambler.ts +99 -99
- package/src/transforms/calculator.ts +99 -99
- package/src/transforms/controlFlowFlattening.ts +1716 -1664
- package/src/transforms/deadCode.ts +82 -82
- package/src/transforms/dispatcher.ts +450 -450
- package/src/transforms/extraction/duplicateLiteralsRemoval.ts +156 -158
- package/src/transforms/extraction/objectExtraction.ts +186 -186
- package/src/transforms/finalizer.ts +74 -74
- package/src/transforms/flatten.ts +421 -420
- package/src/transforms/identifier/globalConcealing.ts +315 -295
- package/src/transforms/identifier/movedDeclarations.ts +252 -251
- package/src/transforms/identifier/renameVariables.ts +328 -321
- package/src/transforms/lock/integrity.ts +117 -114
- package/src/transforms/lock/lock.ts +418 -425
- package/src/transforms/minify.ts +615 -629
- package/src/transforms/opaquePredicates.ts +100 -100
- package/src/transforms/pack.ts +239 -231
- package/src/transforms/plugin.ts +173 -173
- package/src/transforms/preparation.ts +349 -347
- package/src/transforms/renameLabels.ts +175 -175
- package/src/transforms/rgf.ts +322 -322
- package/src/transforms/shuffle.ts +82 -82
- package/src/transforms/string/encoding.ts +144 -144
- package/src/transforms/string/stringCompression.ts +128 -128
- package/src/transforms/string/stringConcealing.ts +312 -298
- package/src/transforms/string/stringEncoding.ts +80 -80
- package/src/transforms/string/stringSplitting.ts +77 -77
- package/src/transforms/variableMasking.ts +257 -257
- package/src/utils/IntGen.ts +33 -33
- package/src/utils/NameGen.ts +116 -116
- package/src/utils/PredicateGen.ts +61 -61
- package/src/utils/ast-utils.ts +663 -663
- package/src/utils/function-utils.ts +50 -50
- package/src/utils/gen-utils.ts +48 -48
- package/src/utils/node.ts +78 -78
- package/src/utils/object-utils.ts +21 -21
- package/src/utils/random-utils.ts +93 -93
- package/src/utils/static-utils.ts +66 -66
- package/src/validateOptions.ts +256 -259
- package/tsconfig.json +13 -14
- package/dist/probability.js +0 -1
- package/dist/transforms/functionOutlining.js +0 -230
- package/dist/utils/ControlObject.js +0 -125
package/src/obfuscator.ts
CHANGED
|
@@ -1,497 +1,501 @@
|
|
|
1
|
-
import { ok } from "assert";
|
|
2
|
-
import * as t from "@babel/types";
|
|
3
|
-
import generate from "@babel/generator";
|
|
4
|
-
import traverse from "@babel/traverse";
|
|
5
|
-
import { parse } from "@babel/parser";
|
|
6
|
-
import { ObfuscateOptions, ProbabilityMap } from "./options";
|
|
7
|
-
import { applyDefaultsToOptions, validateOptions } from "./validateOptions";
|
|
8
|
-
import { ObfuscationResult, ProfilerCallback } from "./obfuscationResult";
|
|
9
|
-
import { NameGen } from "./utils/NameGen";
|
|
10
|
-
import { Order } from "./order";
|
|
11
|
-
import {
|
|
12
|
-
PluginFunction,
|
|
13
|
-
PluginInstance,
|
|
14
|
-
PluginObject,
|
|
15
|
-
} from "./transforms/plugin";
|
|
16
|
-
import { createObject } from "./utils/object-utils";
|
|
17
|
-
|
|
18
|
-
// Transforms
|
|
19
|
-
import preparation from "./transforms/preparation";
|
|
20
|
-
import renameVariables from "./transforms/identifier/renameVariables";
|
|
21
|
-
import variableMasking from "./transforms/variableMasking";
|
|
22
|
-
import dispatcher from "./transforms/dispatcher";
|
|
23
|
-
import duplicateLiteralsRemoval from "./transforms/extraction/duplicateLiteralsRemoval";
|
|
24
|
-
import objectExtraction from "./transforms/extraction/objectExtraction";
|
|
25
|
-
import globalConcealing from "./transforms/identifier/globalConcealing";
|
|
26
|
-
import stringCompression from "./transforms/string/stringCompression";
|
|
27
|
-
import deadCode from "./transforms/deadCode";
|
|
28
|
-
import stringSplitting from "./transforms/string/stringSplitting";
|
|
29
|
-
import shuffle from "./transforms/shuffle";
|
|
30
|
-
import astScrambler from "./transforms/astScrambler";
|
|
31
|
-
import calculator from "./transforms/calculator";
|
|
32
|
-
import movedDeclarations from "./transforms/identifier/movedDeclarations";
|
|
33
|
-
import renameLabels from "./transforms/renameLabels";
|
|
34
|
-
import rgf from "./transforms/rgf";
|
|
35
|
-
import flatten from "./transforms/flatten";
|
|
36
|
-
import stringConcealing from "./transforms/string/stringConcealing";
|
|
37
|
-
import lock from "./transforms/lock/lock";
|
|
38
|
-
import controlFlowFlattening from "./transforms/controlFlowFlattening";
|
|
39
|
-
import opaquePredicates from "./transforms/opaquePredicates";
|
|
40
|
-
import minify from "./transforms/minify";
|
|
41
|
-
import finalizer from "./transforms/finalizer";
|
|
42
|
-
import integrity from "./transforms/lock/integrity";
|
|
43
|
-
import pack, { PackInterface } from "./transforms/pack";
|
|
44
|
-
|
|
45
|
-
export const DEFAULT_OPTIONS: ObfuscateOptions = {
|
|
46
|
-
target: "node",
|
|
47
|
-
compact: true,
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
export default class Obfuscator {
|
|
51
|
-
plugins: {
|
|
52
|
-
plugin: PluginObject;
|
|
53
|
-
pluginInstance: PluginInstance;
|
|
54
|
-
}[] = [];
|
|
55
|
-
options: ObfuscateOptions;
|
|
56
|
-
|
|
57
|
-
totalPossibleTransforms: number = 0;
|
|
58
|
-
|
|
59
|
-
globalState = {
|
|
60
|
-
lock: {
|
|
61
|
-
integrity: {
|
|
62
|
-
sensitivityRegex: / |\n|;|,|\{|\}|\(|\)|\.|\[|\]/g,
|
|
63
|
-
},
|
|
64
|
-
|
|
65
|
-
createCountermeasuresCode: (): t.Statement[] => {
|
|
66
|
-
throw new Error("Not implemented");
|
|
67
|
-
},
|
|
68
|
-
},
|
|
69
|
-
|
|
70
|
-
// After RenameVariables completes, this map will contain the renamed variables
|
|
71
|
-
// Most use cases involve grabbing the Program(global) mappings
|
|
72
|
-
renamedVariables: new Map<t.Node, Map<string, string>>(),
|
|
73
|
-
|
|
74
|
-
// Internal functions, should not be renamed/removed
|
|
75
|
-
internals: {
|
|
76
|
-
stringCompressionLibraryName: "",
|
|
77
|
-
nativeFunctionName: "",
|
|
78
|
-
integrityHashName: "",
|
|
79
|
-
invokeCountermeasuresFnName: "",
|
|
80
|
-
},
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
// Pack Interface for sharing globals across RGF functions
|
|
84
|
-
packInterface: PackInterface;
|
|
85
|
-
|
|
86
|
-
isInternalVariable(name: string) {
|
|
87
|
-
return Object.values(this.globalState.internals).includes(name);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
shouldTransformNativeFunction(nameAndPropertyPath: string[]) {
|
|
91
|
-
if (!this.options.lock?.tamperProtection) {
|
|
92
|
-
return false;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Custom implementation for Tamper Protection
|
|
96
|
-
if (typeof this.options.lock.tamperProtection === "function") {
|
|
97
|
-
return this.options.lock.tamperProtection(nameAndPropertyPath.join("."));
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (
|
|
101
|
-
this.options.target === "browser" &&
|
|
102
|
-
nameAndPropertyPath.length === 1 &&
|
|
103
|
-
nameAndPropertyPath[0] === "fetch"
|
|
104
|
-
) {
|
|
105
|
-
return true;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
var globalObject = {};
|
|
109
|
-
try {
|
|
110
|
-
globalObject =
|
|
111
|
-
typeof globalThis !== "undefined"
|
|
112
|
-
? globalThis
|
|
113
|
-
:
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
typeof fn === "
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
).
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
push(
|
|
184
|
-
push(this.options.
|
|
185
|
-
push(this.options.
|
|
186
|
-
push(
|
|
187
|
-
push(this.options.
|
|
188
|
-
push(this.options.
|
|
189
|
-
push(this.options.
|
|
190
|
-
push(this.options.
|
|
191
|
-
push(this.options.
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
push(
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
push(
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
push(this.options.
|
|
204
|
-
push(this.options.
|
|
205
|
-
push(this.options.
|
|
206
|
-
push(this.options.
|
|
207
|
-
|
|
208
|
-
push(
|
|
209
|
-
push(this.options.
|
|
210
|
-
push(this.options.
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
);
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
if (
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
return
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
return
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
if (typeof map === "
|
|
412
|
-
return (
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
if (typeof map === "
|
|
416
|
-
return map;
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
);
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
);
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
}
|
|
1
|
+
import { ok } from "assert";
|
|
2
|
+
import * as t from "@babel/types";
|
|
3
|
+
import generate from "@babel/generator";
|
|
4
|
+
import traverse from "@babel/traverse";
|
|
5
|
+
import { parse } from "@babel/parser";
|
|
6
|
+
import { ObfuscateOptions, ProbabilityMap } from "./options";
|
|
7
|
+
import { applyDefaultsToOptions, validateOptions } from "./validateOptions";
|
|
8
|
+
import { ObfuscationResult, ProfilerCallback } from "./obfuscationResult";
|
|
9
|
+
import { NameGen } from "./utils/NameGen";
|
|
10
|
+
import { Order } from "./order";
|
|
11
|
+
import {
|
|
12
|
+
PluginFunction,
|
|
13
|
+
PluginInstance,
|
|
14
|
+
PluginObject,
|
|
15
|
+
} from "./transforms/plugin";
|
|
16
|
+
import { createObject } from "./utils/object-utils";
|
|
17
|
+
|
|
18
|
+
// Transforms
|
|
19
|
+
import preparation from "./transforms/preparation";
|
|
20
|
+
import renameVariables from "./transforms/identifier/renameVariables";
|
|
21
|
+
import variableMasking from "./transforms/variableMasking";
|
|
22
|
+
import dispatcher from "./transforms/dispatcher";
|
|
23
|
+
import duplicateLiteralsRemoval from "./transforms/extraction/duplicateLiteralsRemoval";
|
|
24
|
+
import objectExtraction from "./transforms/extraction/objectExtraction";
|
|
25
|
+
import globalConcealing from "./transforms/identifier/globalConcealing";
|
|
26
|
+
import stringCompression from "./transforms/string/stringCompression";
|
|
27
|
+
import deadCode from "./transforms/deadCode";
|
|
28
|
+
import stringSplitting from "./transforms/string/stringSplitting";
|
|
29
|
+
import shuffle from "./transforms/shuffle";
|
|
30
|
+
import astScrambler from "./transforms/astScrambler";
|
|
31
|
+
import calculator from "./transforms/calculator";
|
|
32
|
+
import movedDeclarations from "./transforms/identifier/movedDeclarations";
|
|
33
|
+
import renameLabels from "./transforms/renameLabels";
|
|
34
|
+
import rgf from "./transforms/rgf";
|
|
35
|
+
import flatten from "./transforms/flatten";
|
|
36
|
+
import stringConcealing from "./transforms/string/stringConcealing";
|
|
37
|
+
import lock from "./transforms/lock/lock";
|
|
38
|
+
import controlFlowFlattening from "./transforms/controlFlowFlattening";
|
|
39
|
+
import opaquePredicates from "./transforms/opaquePredicates";
|
|
40
|
+
import minify from "./transforms/minify";
|
|
41
|
+
import finalizer from "./transforms/finalizer";
|
|
42
|
+
import integrity from "./transforms/lock/integrity";
|
|
43
|
+
import pack, { PackInterface } from "./transforms/pack";
|
|
44
|
+
|
|
45
|
+
export const DEFAULT_OPTIONS: ObfuscateOptions = {
|
|
46
|
+
target: "node",
|
|
47
|
+
compact: true,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export default class Obfuscator {
|
|
51
|
+
plugins: {
|
|
52
|
+
plugin: PluginObject;
|
|
53
|
+
pluginInstance: PluginInstance;
|
|
54
|
+
}[] = [];
|
|
55
|
+
options: ObfuscateOptions;
|
|
56
|
+
|
|
57
|
+
totalPossibleTransforms: number = 0;
|
|
58
|
+
|
|
59
|
+
globalState = {
|
|
60
|
+
lock: {
|
|
61
|
+
integrity: {
|
|
62
|
+
sensitivityRegex: / |\n|;|,|\{|\}|\(|\)|\.|\[|\]/g,
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
createCountermeasuresCode: (): t.Statement[] => {
|
|
66
|
+
throw new Error("Not implemented");
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
// After RenameVariables completes, this map will contain the renamed variables
|
|
71
|
+
// Most use cases involve grabbing the Program(global) mappings
|
|
72
|
+
renamedVariables: new Map<t.Node, Map<string, string>>(),
|
|
73
|
+
|
|
74
|
+
// Internal functions, should not be renamed/removed
|
|
75
|
+
internals: {
|
|
76
|
+
stringCompressionLibraryName: "",
|
|
77
|
+
nativeFunctionName: "",
|
|
78
|
+
integrityHashName: "",
|
|
79
|
+
invokeCountermeasuresFnName: "",
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
// Pack Interface for sharing globals across RGF functions
|
|
84
|
+
packInterface: PackInterface;
|
|
85
|
+
|
|
86
|
+
isInternalVariable(name: string) {
|
|
87
|
+
return Object.values(this.globalState.internals).includes(name);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
shouldTransformNativeFunction(nameAndPropertyPath: string[]) {
|
|
91
|
+
if (!this.options.lock?.tamperProtection) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Custom implementation for Tamper Protection
|
|
96
|
+
if (typeof this.options.lock.tamperProtection === "function") {
|
|
97
|
+
return this.options.lock.tamperProtection(nameAndPropertyPath.join("."));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (
|
|
101
|
+
this.options.target === "browser" &&
|
|
102
|
+
nameAndPropertyPath.length === 1 &&
|
|
103
|
+
nameAndPropertyPath[0] === "fetch"
|
|
104
|
+
) {
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
var globalObject = {};
|
|
109
|
+
try {
|
|
110
|
+
globalObject =
|
|
111
|
+
typeof globalThis !== "undefined"
|
|
112
|
+
? globalThis
|
|
113
|
+
: // @ts-ignore
|
|
114
|
+
typeof window !== "undefined"
|
|
115
|
+
? // @ts-ignore
|
|
116
|
+
window
|
|
117
|
+
: typeof global !== "undefined"
|
|
118
|
+
? global
|
|
119
|
+
: // @ts-ignore
|
|
120
|
+
typeof self !== "undefined"
|
|
121
|
+
? // @ts-ignore
|
|
122
|
+
self
|
|
123
|
+
: new Function("return this")();
|
|
124
|
+
} catch (e) {}
|
|
125
|
+
|
|
126
|
+
var fn = globalObject;
|
|
127
|
+
for (var item of nameAndPropertyPath) {
|
|
128
|
+
fn = fn?.[item];
|
|
129
|
+
if (typeof fn === "undefined") return false;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
var hasNativeCode =
|
|
133
|
+
typeof fn === "function" && ("" + fn).includes("[native code]");
|
|
134
|
+
|
|
135
|
+
return hasNativeCode;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
getStringCompressionLibraryName() {
|
|
139
|
+
if (this.parentObfuscator) {
|
|
140
|
+
return this.parentObfuscator.getStringCompressionLibraryName();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return this.globalState.internals.stringCompressionLibraryName;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
getObfuscatedVariableName(originalName: string, programNode: t.Node) {
|
|
147
|
+
const renamedVariables = this.globalState.renamedVariables.get(programNode);
|
|
148
|
+
|
|
149
|
+
return renamedVariables?.get(originalName) || originalName;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* The main Name Generator for `Rename Variables`
|
|
154
|
+
*/
|
|
155
|
+
nameGen: NameGen;
|
|
156
|
+
|
|
157
|
+
public constructor(
|
|
158
|
+
userOptions: ObfuscateOptions,
|
|
159
|
+
public parentObfuscator?: Obfuscator,
|
|
160
|
+
) {
|
|
161
|
+
validateOptions(userOptions);
|
|
162
|
+
this.options = applyDefaultsToOptions({ ...userOptions });
|
|
163
|
+
this.nameGen = new NameGen(this.options.identifierGenerator);
|
|
164
|
+
|
|
165
|
+
const shouldAddLockTransform =
|
|
166
|
+
this.options.lock &&
|
|
167
|
+
(Object.keys(this.options.lock).filter(
|
|
168
|
+
(key) =>
|
|
169
|
+
key !== "customLocks" &&
|
|
170
|
+
this.isProbabilityMapProbable(this.options.lock[key]),
|
|
171
|
+
).length > 0 ||
|
|
172
|
+
this.options.lock.customLocks.length > 0);
|
|
173
|
+
|
|
174
|
+
const allPlugins: PluginFunction[] = [];
|
|
175
|
+
|
|
176
|
+
const push = (probabilityMap, ...pluginFns) => {
|
|
177
|
+
this.totalPossibleTransforms += pluginFns.length;
|
|
178
|
+
if (!this.isProbabilityMapProbable(probabilityMap)) return;
|
|
179
|
+
|
|
180
|
+
allPlugins.push(...pluginFns);
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
push(true, preparation);
|
|
184
|
+
push(this.options.objectExtraction, objectExtraction);
|
|
185
|
+
push(this.options.flatten, flatten);
|
|
186
|
+
push(shouldAddLockTransform, lock);
|
|
187
|
+
push(this.options.rgf, rgf);
|
|
188
|
+
push(this.options.dispatcher, dispatcher);
|
|
189
|
+
push(this.options.deadCode, deadCode);
|
|
190
|
+
push(this.options.controlFlowFlattening, controlFlowFlattening);
|
|
191
|
+
push(this.options.calculator, calculator);
|
|
192
|
+
push(this.options.globalConcealing, globalConcealing);
|
|
193
|
+
push(this.options.opaquePredicates, opaquePredicates);
|
|
194
|
+
push(this.options.stringSplitting, stringSplitting);
|
|
195
|
+
push(this.options.stringConcealing, stringConcealing);
|
|
196
|
+
// String Compression is only applied to the main obfuscator
|
|
197
|
+
// Any RGF functions will not have string compression due to the size of the decompression function
|
|
198
|
+
|
|
199
|
+
push(
|
|
200
|
+
!parentObfuscator && this.options.stringCompression,
|
|
201
|
+
stringCompression,
|
|
202
|
+
);
|
|
203
|
+
push(this.options.variableMasking, variableMasking);
|
|
204
|
+
push(this.options.duplicateLiteralsRemoval, duplicateLiteralsRemoval);
|
|
205
|
+
push(this.options.shuffle, shuffle);
|
|
206
|
+
push(this.options.movedDeclarations, movedDeclarations);
|
|
207
|
+
push(this.options.renameLabels, renameLabels);
|
|
208
|
+
push(this.options.minify, minify);
|
|
209
|
+
push(this.options.astScrambler, astScrambler);
|
|
210
|
+
push(this.options.renameVariables, renameVariables);
|
|
211
|
+
|
|
212
|
+
push(true, finalizer);
|
|
213
|
+
push(this.options.pack, pack);
|
|
214
|
+
push(this.options.lock?.integrity, integrity);
|
|
215
|
+
|
|
216
|
+
allPlugins.map((pluginFunction) => {
|
|
217
|
+
var pluginInstance: PluginInstance;
|
|
218
|
+
var plugin = pluginFunction({
|
|
219
|
+
Plugin: (order: Order, mergeObject?) => {
|
|
220
|
+
ok(typeof order === "number");
|
|
221
|
+
var pluginOptions = {
|
|
222
|
+
order,
|
|
223
|
+
name: Order[order],
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
const newPluginInstance = new PluginInstance(pluginOptions, this);
|
|
227
|
+
if (typeof mergeObject === "object" && mergeObject) {
|
|
228
|
+
Object.assign(newPluginInstance, mergeObject);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
pluginInstance = newPluginInstance;
|
|
232
|
+
|
|
233
|
+
// @ts-ignore
|
|
234
|
+
return newPluginInstance as any;
|
|
235
|
+
},
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
ok(
|
|
239
|
+
pluginInstance,
|
|
240
|
+
"Plugin instance not created: " + pluginFunction.toString(),
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
this.plugins.push({
|
|
244
|
+
plugin,
|
|
245
|
+
pluginInstance,
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
this.plugins = this.plugins.sort(
|
|
250
|
+
(a, b) => a.pluginInstance.order - b.pluginInstance.order,
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
if (!parentObfuscator && this.hasPlugin(Order.StringCompression)) {
|
|
254
|
+
this.globalState.internals.stringCompressionLibraryName =
|
|
255
|
+
this.nameGen.generate(false);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
index: number = 0;
|
|
260
|
+
|
|
261
|
+
obfuscateAST(
|
|
262
|
+
ast: t.File,
|
|
263
|
+
options?: {
|
|
264
|
+
profiler?: ProfilerCallback;
|
|
265
|
+
},
|
|
266
|
+
): t.File {
|
|
267
|
+
let finalASTHandler: PluginObject["finalASTHandler"][] = [];
|
|
268
|
+
|
|
269
|
+
for (let i = 0; i < this.plugins.length; i++) {
|
|
270
|
+
this.index = i;
|
|
271
|
+
const { plugin, pluginInstance } = this.plugins[i];
|
|
272
|
+
|
|
273
|
+
if (this.options.verbose) {
|
|
274
|
+
console.log(
|
|
275
|
+
`Applying ${pluginInstance.name} (${i + 1}/${this.plugins.length})`,
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
traverse(ast, plugin.visitor);
|
|
280
|
+
plugin.post?.();
|
|
281
|
+
|
|
282
|
+
if (plugin.finalASTHandler) {
|
|
283
|
+
finalASTHandler.push(plugin.finalASTHandler);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (options?.profiler) {
|
|
287
|
+
options?.profiler({
|
|
288
|
+
index: i,
|
|
289
|
+
currentTransform: pluginInstance.name,
|
|
290
|
+
nextTransform: this.plugins[i + 1]?.pluginInstance?.name,
|
|
291
|
+
totalTransforms: this.plugins.length,
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
for (const handler of finalASTHandler) {
|
|
297
|
+
ast = handler(ast);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return ast;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
async obfuscate(sourceCode: string): Promise<ObfuscationResult> {
|
|
304
|
+
// Parse the source code into an AST
|
|
305
|
+
let ast = Obfuscator.parseCode(sourceCode);
|
|
306
|
+
|
|
307
|
+
ast = this.obfuscateAST(ast);
|
|
308
|
+
|
|
309
|
+
// Generate the transformed code from the modified AST with comments removed and compacted output
|
|
310
|
+
const code = this.generateCode(ast);
|
|
311
|
+
|
|
312
|
+
return {
|
|
313
|
+
code: code,
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
getPlugin(order: Order) {
|
|
318
|
+
return this.plugins.find((x) => x.pluginInstance.order === order);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
hasPlugin(order: Order) {
|
|
322
|
+
return !!this.getPlugin(order);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Calls `Obfuscator.generateCode` with the current instance options
|
|
327
|
+
*/
|
|
328
|
+
generateCode<T extends t.Node = t.File>(ast: T): string {
|
|
329
|
+
return Obfuscator.generateCode(ast, this.options);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Generates code from an AST using `@babel/generator`
|
|
334
|
+
*/
|
|
335
|
+
static generateCode<T extends t.Node = t.File>(
|
|
336
|
+
ast: T,
|
|
337
|
+
options: ObfuscateOptions = DEFAULT_OPTIONS,
|
|
338
|
+
): string {
|
|
339
|
+
const compact = !!options.compact;
|
|
340
|
+
|
|
341
|
+
const { code } = generate(ast, {
|
|
342
|
+
comments: false, // Remove comments
|
|
343
|
+
minified: compact,
|
|
344
|
+
// jsescOption: {
|
|
345
|
+
// String Encoding using Babel
|
|
346
|
+
// escapeEverything: true,
|
|
347
|
+
// },
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
return code;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Parses the source code into an AST using `t.parseSync`
|
|
355
|
+
*/
|
|
356
|
+
static parseCode(sourceCode: string): t.File {
|
|
357
|
+
// Parse the source code into an AST
|
|
358
|
+
let ast = parse(sourceCode, {
|
|
359
|
+
sourceType: "unambiguous",
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
return ast;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
probabilityMapCounter = new WeakMap<Object, number>();
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Evaluates a ProbabilityMap.
|
|
369
|
+
* @param map The setting object.
|
|
370
|
+
* @param customFnArgs Args given to user-implemented function, such as a variable name.
|
|
371
|
+
*/
|
|
372
|
+
computeProbabilityMap<
|
|
373
|
+
T,
|
|
374
|
+
F extends (...args: any[]) => any = (...args: any[]) => any,
|
|
375
|
+
>(
|
|
376
|
+
map: ProbabilityMap<T, F>,
|
|
377
|
+
...customImplementationArgs: F extends (...args: infer P) => any ? P : never
|
|
378
|
+
): boolean | string {
|
|
379
|
+
// Check if this probability map uses the {value: ..., limit: ...} format
|
|
380
|
+
if (typeof map === "object" && map && "value" in map) {
|
|
381
|
+
// Check for the limit property
|
|
382
|
+
if ("limit" in map && typeof map.limit === "number" && map.limit >= 0) {
|
|
383
|
+
// Check if the limit has been reached
|
|
384
|
+
if (this.probabilityMapCounter.get(map) >= map.limit) {
|
|
385
|
+
return false;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
var value = this.computeProbabilityMap(
|
|
390
|
+
map.value as ProbabilityMap<T, F>,
|
|
391
|
+
...customImplementationArgs,
|
|
392
|
+
);
|
|
393
|
+
|
|
394
|
+
if (value) {
|
|
395
|
+
// Increment the counter for this map
|
|
396
|
+
this.probabilityMapCounter.set(
|
|
397
|
+
map,
|
|
398
|
+
this.probabilityMapCounter.get(map) + 1 || 1,
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
return value;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if (!map) {
|
|
406
|
+
return false;
|
|
407
|
+
}
|
|
408
|
+
if (map === true || map === 1) {
|
|
409
|
+
return true;
|
|
410
|
+
}
|
|
411
|
+
if (typeof map === "number") {
|
|
412
|
+
return Math.random() < map;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
if (typeof map === "function") {
|
|
416
|
+
return (map as Function)(...customImplementationArgs);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
if (typeof map === "string") {
|
|
420
|
+
return map;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
var asObject: { [mode: string]: number } = {};
|
|
424
|
+
if (Array.isArray(map)) {
|
|
425
|
+
map.forEach((x: any) => {
|
|
426
|
+
asObject[x.toString()] = 1;
|
|
427
|
+
});
|
|
428
|
+
} else {
|
|
429
|
+
asObject = map as any;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
var total = Object.values(asObject).reduce((a, b) => a + b);
|
|
433
|
+
var percentages = createObject(
|
|
434
|
+
Object.keys(asObject),
|
|
435
|
+
Object.values(asObject).map((x) => x / total),
|
|
436
|
+
);
|
|
437
|
+
|
|
438
|
+
var ticket = Math.random();
|
|
439
|
+
|
|
440
|
+
var count = 0;
|
|
441
|
+
var winner = null;
|
|
442
|
+
Object.keys(percentages).forEach((key) => {
|
|
443
|
+
var x = Number(percentages[key]);
|
|
444
|
+
|
|
445
|
+
if (ticket >= count && ticket < count + x) {
|
|
446
|
+
winner = key;
|
|
447
|
+
}
|
|
448
|
+
count += x;
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
return winner;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* Determines if a probability map can return a positive result (true, or some string mode).
|
|
456
|
+
* - Negative probability maps are used to remove transformations from running entirely.
|
|
457
|
+
* @param map
|
|
458
|
+
*/
|
|
459
|
+
isProbabilityMapProbable<T>(map: ProbabilityMap<T>): boolean {
|
|
460
|
+
ok(!Number.isNaN(map), "Numbers cannot be NaN");
|
|
461
|
+
|
|
462
|
+
if (!map || typeof map === "undefined") {
|
|
463
|
+
return false;
|
|
464
|
+
}
|
|
465
|
+
if (typeof map === "function") {
|
|
466
|
+
return true;
|
|
467
|
+
}
|
|
468
|
+
if (typeof map === "number") {
|
|
469
|
+
if (map > 1 || map < 0) {
|
|
470
|
+
throw new Error(`Numbers must be between 0 and 1 for 0% - 100%`);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
if (Array.isArray(map)) {
|
|
474
|
+
ok(
|
|
475
|
+
map.length != 0,
|
|
476
|
+
"Empty arrays are not allowed for options. Use false instead.",
|
|
477
|
+
);
|
|
478
|
+
|
|
479
|
+
if (map.length == 1) {
|
|
480
|
+
return !!map[0];
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
if (typeof map === "object") {
|
|
484
|
+
if (map instanceof Date) return true;
|
|
485
|
+
if (map instanceof RegExp) return true;
|
|
486
|
+
if ("value" in map && !map.value) return false;
|
|
487
|
+
if ("limit" in map && map.limit === 0) return false;
|
|
488
|
+
|
|
489
|
+
var keys = Object.keys(map);
|
|
490
|
+
ok(
|
|
491
|
+
keys.length != 0,
|
|
492
|
+
"Empty objects are not allowed for options. Use false instead.",
|
|
493
|
+
);
|
|
494
|
+
|
|
495
|
+
if (keys.length == 1) {
|
|
496
|
+
return !!map[keys[0]];
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
return true;
|
|
500
|
+
}
|
|
501
|
+
}
|