js-confuser 1.7.1 → 1.7.3

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.
Files changed (153) hide show
  1. package/.github/workflows/node.js.yml +1 -1
  2. package/CHANGELOG.md +73 -0
  3. package/README.md +32 -31
  4. package/dist/compiler.js +2 -8
  5. package/dist/constants.js +22 -10
  6. package/dist/index.js +15 -30
  7. package/dist/obfuscator.js +15 -62
  8. package/dist/options.js +33 -40
  9. package/dist/order.js +4 -7
  10. package/dist/parser.js +5 -13
  11. package/dist/precedence.js +6 -8
  12. package/dist/presets.js +4 -6
  13. package/dist/probability.js +13 -24
  14. package/dist/templates/bufferToString.js +121 -5
  15. package/dist/templates/core.js +35 -0
  16. package/dist/templates/crash.js +22 -11
  17. package/dist/templates/es5.js +125 -6
  18. package/dist/templates/functionLength.js +24 -6
  19. package/dist/templates/globals.js +9 -0
  20. package/dist/templates/template.js +189 -43
  21. package/dist/transforms/antiTooling.js +26 -22
  22. package/dist/transforms/calculator.js +19 -55
  23. package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +242 -333
  24. package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +46 -25
  25. package/dist/transforms/deadCode.js +542 -31
  26. package/dist/transforms/dispatcher.js +112 -112
  27. package/dist/transforms/es5/antiClass.js +70 -44
  28. package/dist/transforms/es5/antiDestructuring.js +14 -38
  29. package/dist/transforms/es5/antiES6Object.js +39 -48
  30. package/dist/transforms/es5/antiSpreadOperator.js +5 -14
  31. package/dist/transforms/es5/antiTemplate.js +10 -19
  32. package/dist/transforms/es5/es5.js +7 -40
  33. package/dist/transforms/extraction/classExtraction.js +83 -0
  34. package/dist/transforms/extraction/duplicateLiteralsRemoval.js +41 -80
  35. package/dist/transforms/extraction/objectExtraction.js +24 -56
  36. package/dist/transforms/finalizer.js +6 -20
  37. package/dist/transforms/flatten.js +51 -99
  38. package/dist/transforms/identifier/globalAnalysis.js +21 -26
  39. package/dist/transforms/identifier/globalConcealing.js +72 -56
  40. package/dist/transforms/identifier/movedDeclarations.js +66 -38
  41. package/dist/transforms/identifier/renameVariables.js +36 -68
  42. package/dist/transforms/identifier/variableAnalysis.js +21 -48
  43. package/dist/transforms/lock/antiDebug.js +20 -25
  44. package/dist/transforms/lock/integrity.js +53 -52
  45. package/dist/transforms/lock/lock.js +161 -126
  46. package/dist/transforms/minify.js +77 -108
  47. package/dist/transforms/opaquePredicates.js +12 -49
  48. package/dist/transforms/preparation.js +28 -49
  49. package/dist/transforms/renameLabels.js +5 -22
  50. package/dist/transforms/rgf.js +125 -72
  51. package/dist/transforms/shuffle.js +42 -47
  52. package/dist/transforms/stack.js +41 -98
  53. package/dist/transforms/string/encoding.js +76 -27
  54. package/dist/transforms/string/stringCompression.js +75 -68
  55. package/dist/transforms/string/stringConcealing.js +127 -135
  56. package/dist/transforms/string/stringEncoding.js +6 -26
  57. package/dist/transforms/string/stringSplitting.js +5 -30
  58. package/dist/transforms/transform.js +76 -104
  59. package/dist/traverse.js +11 -18
  60. package/dist/util/compare.js +27 -29
  61. package/dist/util/gen.js +32 -86
  62. package/dist/util/guard.js +5 -1
  63. package/dist/util/identifiers.js +9 -72
  64. package/dist/util/insert.js +27 -77
  65. package/dist/util/math.js +0 -3
  66. package/dist/util/object.js +3 -7
  67. package/dist/util/random.js +31 -36
  68. package/dist/util/scope.js +6 -3
  69. package/docs/Countermeasures.md +13 -6
  70. package/docs/Integrity.md +35 -28
  71. package/docs/RGF.md +6 -1
  72. package/docs/RenameVariables.md +116 -0
  73. package/docs/TamperProtection.md +100 -0
  74. package/docs/Template.md +117 -0
  75. package/package.json +3 -3
  76. package/src/constants.ts +17 -0
  77. package/src/index.ts +7 -5
  78. package/src/options.ts +60 -7
  79. package/src/order.ts +2 -2
  80. package/src/templates/bufferToString.ts +79 -11
  81. package/src/templates/core.ts +29 -0
  82. package/src/templates/crash.ts +6 -38
  83. package/src/templates/es5.ts +1 -1
  84. package/src/templates/functionLength.ts +21 -3
  85. package/src/templates/globals.ts +3 -0
  86. package/src/templates/template.ts +205 -46
  87. package/src/transforms/antiTooling.ts +33 -11
  88. package/src/transforms/calculator.ts +4 -2
  89. package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +12 -5
  90. package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +46 -10
  91. package/src/transforms/deadCode.ts +74 -42
  92. package/src/transforms/dispatcher.ts +99 -73
  93. package/src/transforms/es5/antiClass.ts +25 -12
  94. package/src/transforms/es5/antiDestructuring.ts +1 -1
  95. package/src/transforms/es5/antiES6Object.ts +2 -2
  96. package/src/transforms/es5/antiTemplate.ts +1 -1
  97. package/src/transforms/extraction/classExtraction.ts +168 -0
  98. package/src/transforms/extraction/duplicateLiteralsRemoval.ts +11 -16
  99. package/src/transforms/extraction/objectExtraction.ts +4 -15
  100. package/src/transforms/flatten.ts +20 -5
  101. package/src/transforms/identifier/globalAnalysis.ts +18 -1
  102. package/src/transforms/identifier/globalConcealing.ts +119 -72
  103. package/src/transforms/identifier/movedDeclarations.ts +90 -24
  104. package/src/transforms/identifier/renameVariables.ts +16 -1
  105. package/src/transforms/lock/antiDebug.ts +2 -2
  106. package/src/transforms/lock/integrity.ts +13 -11
  107. package/src/transforms/lock/lock.ts +122 -30
  108. package/src/transforms/minify.ts +28 -13
  109. package/src/transforms/opaquePredicates.ts +2 -2
  110. package/src/transforms/preparation.ts +16 -0
  111. package/src/transforms/rgf.ts +139 -12
  112. package/src/transforms/shuffle.ts +3 -3
  113. package/src/transforms/stack.ts +19 -4
  114. package/src/transforms/string/encoding.ts +88 -51
  115. package/src/transforms/string/stringCompression.ts +86 -17
  116. package/src/transforms/string/stringConcealing.ts +148 -118
  117. package/src/transforms/string/stringEncoding.ts +1 -2
  118. package/src/transforms/string/stringSplitting.ts +1 -2
  119. package/src/transforms/transform.ts +63 -46
  120. package/src/types.ts +2 -0
  121. package/src/util/compare.ts +39 -5
  122. package/src/util/gen.ts +10 -3
  123. package/src/util/guard.ts +10 -0
  124. package/src/util/insert.ts +17 -0
  125. package/src/util/random.ts +81 -1
  126. package/src/util/scope.ts +14 -2
  127. package/test/code/Cash.test.ts +94 -5
  128. package/test/code/StrictMode.src.js +65 -0
  129. package/test/code/StrictMode.test.js +37 -0
  130. package/test/compare.test.ts +62 -2
  131. package/test/options.test.ts +129 -55
  132. package/test/templates/template.test.ts +211 -1
  133. package/test/transforms/controlFlowFlattening/expressionObfuscation.test.ts +37 -18
  134. package/test/transforms/dispatcher.test.ts +55 -0
  135. package/test/transforms/extraction/classExtraction.test.ts +86 -0
  136. package/test/transforms/extraction/duplicateLiteralsRemoval.test.ts +8 -0
  137. package/test/transforms/extraction/objectExtraction.test.ts +2 -0
  138. package/test/transforms/identifier/globalConcealing.test.ts +89 -0
  139. package/test/transforms/identifier/movedDeclarations.test.ts +61 -0
  140. package/test/transforms/identifier/renameVariables.test.ts +75 -1
  141. package/test/transforms/lock/tamperProtection.test.ts +336 -0
  142. package/test/transforms/minify.test.ts +37 -0
  143. package/test/transforms/rgf.test.ts +50 -0
  144. package/dist/transforms/controlFlowFlattening/choiceFlowObfuscation.js +0 -62
  145. package/dist/transforms/controlFlowFlattening/controlFlowObfuscation.js +0 -159
  146. package/dist/transforms/controlFlowFlattening/switchCaseObfuscation.js +0 -106
  147. package/dist/transforms/eval.js +0 -84
  148. package/dist/transforms/hexadecimalNumbers.js +0 -63
  149. package/dist/transforms/hideInitializingCode.js +0 -270
  150. package/dist/transforms/identifier/nameRecycling.js +0 -218
  151. package/dist/transforms/label.js +0 -67
  152. package/dist/transforms/preparation/nameConflicts.js +0 -116
  153. package/dist/transforms/preparation/preparation.js +0 -188
@@ -1,12 +1,11 @@
1
1
  import { ok } from "assert";
2
2
  import { ObfuscateOrder } from "../../order";
3
3
  import Template from "../../templates/template";
4
- import { isBlock } from "../../traverse";
5
- import { isDirective } from "../../util/compare";
4
+ import { getBlock } from "../../traverse";
5
+ import { isDirective, isModuleSource } from "../../util/compare";
6
6
  import {
7
7
  ArrayExpression,
8
8
  CallExpression,
9
- FunctionExpression,
10
9
  Identifier,
11
10
  Literal,
12
11
  MemberExpression,
@@ -22,54 +21,39 @@ import {
22
21
  choice,
23
22
  getRandomInteger,
24
23
  getRandomString,
24
+ shuffle,
25
25
  } from "../../util/random";
26
26
  import Transform from "../transform";
27
- import Encoding from "./encoding";
27
+ import {
28
+ EncodingImplementation,
29
+ EncodingImplementations,
30
+ createEncodingImplementation,
31
+ hasAllEncodings,
32
+ } from "./encoding";
28
33
  import { ComputeProbabilityMap } from "../../probability";
29
- import { BufferToStringTemplate } from "../../templates/bufferToString";
30
-
31
- export function isModuleSource(object: Node, parents: Node[]) {
32
- if (!parents[0]) {
33
- return false;
34
- }
35
-
36
- if (parents[0].type == "ImportDeclaration" && parents[0].source == object) {
37
- return true;
38
- }
39
-
40
- if (parents[0].type == "ImportExpression" && parents[0].source == object) {
41
- return true;
42
- }
43
-
44
- if (
45
- parents[1] &&
46
- parents[1].type == "CallExpression" &&
47
- parents[1].arguments[0] === object &&
48
- parents[1].callee.type == "Identifier"
49
- ) {
50
- if (
51
- parents[1].callee.name == "require" ||
52
- parents[1].callee.name == "import"
53
- ) {
54
- return true;
55
- }
56
- }
57
-
58
- return false;
34
+ import {
35
+ BufferToStringTemplate,
36
+ createGetGlobalTemplate,
37
+ } from "../../templates/bufferToString";
38
+ import { criticalFunctionTag, predictableFunctionTag } from "../../constants";
39
+
40
+ interface FunctionObject {
41
+ block: Node;
42
+ fnName: string;
43
+ encodingImplementation: EncodingImplementation;
59
44
  }
60
45
 
61
46
  export default class StringConcealing extends Transform {
62
47
  arrayExpression: Node;
63
48
  set: Set<string>;
64
- index: { [str: string]: [number, string] };
49
+ index: { [str: string]: [number, string, Node] }; // index, fnName, block
65
50
 
66
51
  arrayName = this.getPlaceholder();
67
52
  ignore = new Set<string>();
68
53
  variablesMade = 1;
69
- encoding: { [type: string]: string } = Object.create(null);
70
54
  gen: ReturnType<Transform["getGenerator"]>;
71
55
 
72
- hasAllEncodings: boolean;
56
+ functionObjects: FunctionObject[] = [];
73
57
 
74
58
  constructor(o) {
75
59
  super(o, ObfuscateOrder.StringConcealing);
@@ -77,84 +61,111 @@ export default class StringConcealing extends Transform {
77
61
  this.set = new Set();
78
62
  this.index = Object.create(null);
79
63
  this.arrayExpression = ArrayExpression([]);
80
- this.hasAllEncodings = false;
81
64
  this.gen = this.getGenerator();
65
+ }
66
+
67
+ apply(tree) {
68
+ super.apply(tree);
82
69
 
83
70
  // Pad array with useless strings
84
- var dead = getRandomInteger(5, 15);
71
+ var dead = getRandomInteger(50, 200);
85
72
  for (var i = 0; i < dead; i++) {
86
73
  var str = getRandomString(getRandomInteger(5, 40));
87
- var fn = this.transform(Literal(str), []);
74
+ var fn = this.transform(Literal(str), [tree]);
88
75
  if (fn) {
89
76
  fn();
90
77
  }
91
78
  }
92
- }
93
-
94
- apply(tree) {
95
- super.apply(tree);
96
79
 
97
80
  var cacheName = this.getPlaceholder();
98
- var bufferToStringName = this.getPlaceholder();
81
+ var bufferToStringName = this.getPlaceholder() + predictableFunctionTag;
99
82
 
100
83
  // This helper functions convert UInt8 Array to UTf-string
101
84
  prepend(
102
85
  tree,
103
- ...BufferToStringTemplate.compile({ name: bufferToStringName })
86
+ ...BufferToStringTemplate.compile({
87
+ name: bufferToStringName,
88
+ getGlobalFnName: this.getPlaceholder() + predictableFunctionTag,
89
+ GetGlobalTemplate: createGetGlobalTemplate(this, tree, []),
90
+ })
104
91
  );
105
92
 
106
- Object.keys(this.encoding).forEach((type) => {
107
- var { template } = Encoding[type];
108
- var decodeFn = this.getPlaceholder();
109
- var getterFn = this.encoding[type];
93
+ for (var functionObject of this.functionObjects) {
94
+ var {
95
+ block,
96
+ fnName: getterFnName,
97
+ encodingImplementation,
98
+ } = functionObject;
99
+
100
+ var decodeFn =
101
+ this.getPlaceholder() + predictableFunctionTag + criticalFunctionTag;
110
102
 
111
103
  append(
112
- tree,
113
- template.single({ name: decodeFn, bufferToString: bufferToStringName })
104
+ block,
105
+ encodingImplementation.template.single({
106
+ __fnName__: decodeFn,
107
+ __bufferToString__: bufferToStringName,
108
+ })
114
109
  );
110
+ // All these are fake and never ran
111
+ var ifStatements = new Template(`if ( z == x ) {
112
+ return y[${cacheName}[z]] = ${getterFnName}(x, y);
113
+ }
114
+ if ( y ) {
115
+ [b, y] = [a(b), x || z]
116
+ return ${getterFnName}(x, b, z)
117
+ }
118
+ if ( z && a !== ${decodeFn} ) {
119
+ ${getterFnName} = ${decodeFn}
120
+ return ${getterFnName}(x, -1, z, a, b)
121
+ }
122
+ if ( a === ${getterFnName} ) {
123
+ ${decodeFn} = y
124
+ return ${decodeFn}(z)
125
+ }
126
+ if( a === undefined ) {
127
+ ${getterFnName} = b
128
+ }
129
+ if( z == a ) {
130
+ return y ? x[b[y]] : ${cacheName}[x] || (z=(b[x] || a), ${cacheName}[x] = z(${this.arrayName}[x]))
131
+ }
132
+ `).compile();
115
133
 
116
- append(
117
- tree,
118
- Template(`
119
-
120
- function ${getterFn}(x, y, z, a = ${decodeFn}, b = ${cacheName}){
121
- if ( z ) {
122
- return y[${cacheName}[z]] = ${getterFn}(x, y);
123
- } else if ( y ) {
124
- [b, y] = [a(b), x || z]
125
- }
126
-
127
- return y ? x[b[y]] : ${cacheName}[x] || (z=(b[x], a), ${cacheName}[x] = z(${this.arrayName}[x]))
128
- }
129
-
130
- `).single()
134
+ // Not all fake if-statements are needed
135
+ ifStatements = ifStatements.filter(() => chance(50));
136
+
137
+ // This one is always used
138
+ ifStatements.push(
139
+ new Template(`
140
+ if ( x !== y ) {
141
+ return b[x] || (b[x] = a(${this.arrayName}[x]))
142
+ }
143
+ `).single()
131
144
  );
132
- });
133
145
 
134
- var flowIntegrity = this.getPlaceholder();
146
+ shuffle(ifStatements);
147
+
148
+ var varDeclaration = new Template(`
149
+ var ${getterFnName} = (x, y, z, a, b)=>{
150
+ if(typeof a === "undefined") {
151
+ a = ${decodeFn}
152
+ }
153
+ if(typeof b === "undefined") {
154
+ b = ${cacheName}
155
+ }
156
+ }
157
+ `).single();
158
+
159
+ varDeclaration.declarations[0].init.body.body.push(...ifStatements);
160
+
161
+ prepend(block, varDeclaration);
162
+ }
135
163
 
136
164
  prepend(
137
165
  tree,
138
166
  VariableDeclaration([
139
167
  VariableDeclarator(cacheName, ArrayExpression([])),
140
- VariableDeclarator(flowIntegrity, Literal(0)),
141
- VariableDeclarator(
142
- this.arrayName,
143
- CallExpression(
144
- FunctionExpression(
145
- [],
146
- [
147
- VariableDeclaration(
148
- VariableDeclarator("a", this.arrayExpression)
149
- ),
150
- Template(
151
- `return (${flowIntegrity} ? a["pop"]() : ${flowIntegrity}++, a)`
152
- ).single(),
153
- ]
154
- ),
155
- []
156
- )
157
- ),
168
+ VariableDeclarator(this.arrayName, this.arrayExpression),
158
169
  ])
159
170
  );
160
171
  }
@@ -166,7 +177,7 @@ export default class StringConcealing extends Transform {
166
177
  object.value.length >= 3 &&
167
178
  !isModuleSource(object, parents) &&
168
179
  !isDirective(object, parents) //&&
169
- /*!parents.find((x) => x.$dispatcherSkip)*/
180
+ /*!parents.find((x) => x.$multiTransformSkip)*/
170
181
  );
171
182
  }
172
183
 
@@ -192,48 +203,67 @@ export default class StringConcealing extends Transform {
192
203
  return;
193
204
  }
194
205
 
195
- // HARD CODED LIMIT of 10,000 (after 1,000 elements)
196
- if (this.set.size > 1000 && !chance(this.set.size / 100)) return;
206
+ var currentBlock = getBlock(object, parents);
197
207
 
198
- var types = Object.keys(this.encoding);
208
+ // Find created functions
209
+ var functionObjects: FunctionObject[] = parents
210
+ .filter((node) => node.$stringConcealingFunctionObject)
211
+ .map((item) => item.$stringConcealingFunctionObject);
199
212
 
200
- var type = choice(types);
201
- if (!type || (!this.hasAllEncodings && chance(10))) {
202
- var allowed = Object.keys(Encoding).filter(
203
- (type) => !this.encoding[type]
204
- );
213
+ // Choose random functionObject to use
214
+ var functionObject = choice(functionObjects);
215
+
216
+ if (
217
+ !functionObject ||
218
+ (!hasAllEncodings() &&
219
+ chance(25 / this.functionObjects.length) &&
220
+ !currentBlock.$stringConcealingFunctionObject)
221
+ ) {
222
+ // No functions, create one
205
223
 
206
- if (!allowed.length) {
207
- this.hasAllEncodings = true;
208
- } else {
209
- var random = choice(allowed);
210
- type = random;
224
+ var newFunctionObject: FunctionObject = {
225
+ block: currentBlock,
226
+ encodingImplementation: createEncodingImplementation(),
227
+ fnName: this.getPlaceholder() + predictableFunctionTag,
228
+ };
211
229
 
212
- this.encoding[random] = this.getPlaceholder();
213
- }
230
+ this.functionObjects.push(newFunctionObject);
231
+ currentBlock.$stringConcealingFunctionObject = newFunctionObject;
232
+ functionObject = newFunctionObject;
214
233
  }
215
234
 
216
- var fnName = this.encoding[type];
217
- var encoder = Encoding[type];
235
+ var { fnName, encodingImplementation } = functionObject;
218
236
 
219
- // The decode function must return correct result
220
- var encoded = encoder.encode(object.value);
221
- if (encoder.decode(encoded) != object.value) {
222
- this.ignore.add(object.value);
223
- this.warn(type, object.value.slice(0, 100));
224
- return;
237
+ var index = -1;
238
+
239
+ // String already decoded?
240
+ if (this.set.has(object.value)) {
241
+ var row = this.index[object.value];
242
+ if (parents.includes(row[2])) {
243
+ [index, fnName] = row;
244
+ ok(typeof index === "number");
245
+ }
225
246
  }
226
247
 
227
- var index = -1;
228
- if (!this.set.has(object.value)) {
248
+ if (index == -1) {
249
+ // The decode function must return correct result
250
+ var encoded = encodingImplementation.encode(object.value);
251
+ if (encodingImplementation.decode(encoded) !== object.value) {
252
+ this.ignore.add(object.value);
253
+ this.warn(
254
+ encodingImplementation.identity,
255
+ object.value.slice(0, 100)
256
+ );
257
+ delete EncodingImplementations[encodingImplementation.identity];
258
+
259
+ return;
260
+ }
261
+
229
262
  this.arrayExpression.elements.push(Literal(encoded));
230
263
  index = this.arrayExpression.elements.length - 1;
231
- this.index[object.value] = [index, fnName];
264
+ this.index[object.value] = [index, fnName, currentBlock];
232
265
 
233
266
  this.set.add(object.value);
234
- } else {
235
- [index, fnName] = this.index[object.value];
236
- ok(typeof index === "number");
237
267
  }
238
268
 
239
269
  ok(index != -1, "index == -1");
@@ -269,7 +299,7 @@ export default class StringConcealing extends Transform {
269
299
 
270
300
  var constantReferenceType = choice(["variable", "array", "object"]);
271
301
 
272
- var place = choice(parents.filter((node) => isBlock(node)));
302
+ var place = currentBlock;
273
303
  if (!place) {
274
304
  this.error(new Error("No lexical block to insert code"));
275
305
  }
@@ -1,7 +1,6 @@
1
1
  import Transform from "../transform";
2
2
  import { choice } from "../../util/random";
3
- import { isDirective } from "../../util/compare";
4
- import { isModuleSource } from "./stringConcealing";
3
+ import { isDirective, isModuleSource } from "../../util/compare";
5
4
  import { ComputeProbabilityMap } from "../../probability";
6
5
  import { Identifier } from "../../util/gen";
7
6
 
@@ -3,8 +3,7 @@ import { Node, Literal, BinaryExpression } from "../../util/gen";
3
3
  import { clone } from "../../util/insert";
4
4
  import { getRandomInteger, shuffle, splitIntoChunks } from "../../util/random";
5
5
  import { ObfuscateOrder } from "../../order";
6
- import { isModuleSource } from "./stringConcealing";
7
- import { isDirective } from "../../util/compare";
6
+ import { isDirective, isModuleSource } from "../../util/compare";
8
7
  import { ok } from "assert";
9
8
  import { ComputeProbabilityMap } from "../../probability";
10
9
 
@@ -1,13 +1,19 @@
1
1
  import traverse, { ExitCallback } from "../traverse";
2
- import { AddComment, Node } from "../util/gen";
2
+ import {
3
+ AddComment,
4
+ Node,
5
+ VariableDeclaration,
6
+ VariableDeclarator,
7
+ } from "../util/gen";
3
8
  import {
4
9
  alphabeticalGenerator,
5
10
  choice,
11
+ createZeroWidthGenerator,
6
12
  getRandomInteger,
13
+ shuffle,
7
14
  } from "../util/random";
8
15
  import { ok } from "assert";
9
16
  import Obfuscator from "../obfuscator";
10
- import { ObfuscateOptions } from "../options";
11
17
  import { ComputeProbabilityMap } from "../probability";
12
18
  import {
13
19
  placeholderVariablePrefix,
@@ -15,6 +21,9 @@ import {
15
21
  reservedKeywords,
16
22
  } from "../constants";
17
23
  import { ObfuscateOrder } from "../order";
24
+ import { prepend } from "../util/insert";
25
+ import Lock from "./lock/lock";
26
+ import Template from "../templates/template";
18
27
 
19
28
  /**
20
29
  * Base-class for all transformations.
@@ -61,7 +70,7 @@ export default class Transform {
61
70
  /**
62
71
  * The user's options.
63
72
  */
64
- options: ObfuscateOptions;
73
+ options: Obfuscator["options"];
65
74
 
66
75
  /**
67
76
  * Only required for top-level transformations.
@@ -78,6 +87,10 @@ export default class Transform {
78
87
  */
79
88
  after: Transform[];
80
89
 
90
+ initVariables = new Map<string, string>();
91
+
92
+ zeroWidthGenerator = createZeroWidthGenerator();
93
+
81
94
  constructor(obfuscator, priority: number = -1) {
82
95
  ok(obfuscator instanceof Obfuscator, "obfuscator should be an Obfuscator");
83
96
 
@@ -99,6 +112,32 @@ export default class Transform {
99
112
  );
100
113
  }
101
114
 
115
+ /**
116
+ * Gets the `Lock` transformation.
117
+ */
118
+ get lockTransform(): Lock {
119
+ var transform = this.obfuscator.transforms["Lock"] as Lock;
120
+
121
+ ok(transform, "Lock transform not created");
122
+
123
+ return transform;
124
+ }
125
+
126
+ /**
127
+ * Wraps the given name with the `__JS_CONFUSER_VAR__` function call.
128
+ *
129
+ * If `Rename Variables` is disabled, the name is returned as-is.
130
+ * @param name
131
+ * @returns
132
+ */
133
+ jsConfuserVar(name: string) {
134
+ if (!this.obfuscator.transforms["RenameVariables"]) {
135
+ return `"${name}"`;
136
+ }
137
+
138
+ return `__JS_CONFUSER_VAR__(${name})`;
139
+ }
140
+
102
141
  /**
103
142
  * Run an AST through the transformation (including `pre` and `post` transforms)
104
143
  * @param tree
@@ -277,49 +316,7 @@ export default class Transform {
277
316
  return "var_" + count;
278
317
 
279
318
  case "zeroWidth":
280
- var keyWords = [
281
- "if",
282
- "in",
283
- "for",
284
- "let",
285
- "new",
286
- "try",
287
- "var",
288
- "case",
289
- "else",
290
- "null",
291
- "break",
292
- "catch",
293
- "class",
294
- "const",
295
- "super",
296
- "throw",
297
- "while",
298
- "yield",
299
- "delete",
300
- "export",
301
- "import",
302
- "public",
303
- "return",
304
- "switch",
305
- "default",
306
- "finally",
307
- "private",
308
- "continue",
309
- "debugger",
310
- "function",
311
- "arguments",
312
- "protected",
313
- "instanceof",
314
- "function",
315
- "await",
316
- "async",
317
- ];
318
-
319
- var safe = "\u200C".repeat(count + 1);
320
-
321
- var base = choice(keyWords) + safe;
322
- return base;
319
+ return this.zeroWidthGenerator.generate();
323
320
  }
324
321
 
325
322
  throw new Error("Invalid 'identifierGenerator' mode: " + mode);
@@ -336,6 +333,26 @@ export default class Transform {
336
333
  return identifier;
337
334
  }
338
335
 
336
+ createInitVariable = (value: Template, parents: Node[]) => {
337
+ var key = value.templates[0];
338
+ if (this.initVariables.has(key)) {
339
+ return this.initVariables.get(key);
340
+ }
341
+
342
+ var root = parents[parents.length - 1];
343
+ ok(root.type === "Program");
344
+
345
+ var name = this.getPlaceholder();
346
+ this.initVariables.set(key, name);
347
+
348
+ prepend(
349
+ root,
350
+ VariableDeclaration(VariableDeclarator(name, value.single().expression))
351
+ );
352
+
353
+ return name;
354
+ };
355
+
339
356
  /**
340
357
  * Smartly appends a comment to a Node.
341
358
  * - Includes the transformation's name.
package/src/types.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import Obfuscator from "./obfuscator";
2
2
  import { ObfuscateOptions } from "./options";
3
+ import Template from "./templates/template";
3
4
  import Transform from "./transforms/transform";
4
5
 
5
6
  /**
@@ -21,6 +22,7 @@ export interface IJsConfuser {
21
22
 
22
23
  Transform: typeof Transform;
23
24
  Obfuscator: typeof Obfuscator;
25
+ Template: typeof Template;
24
26
  }
25
27
 
26
28
  /**
@@ -74,19 +74,52 @@ export function isDirective(object: Node, parents: Node[]) {
74
74
  return parents[dIndex].expression == (parents[dIndex - 1] || object);
75
75
  }
76
76
 
77
+ export function isModuleSource(object: Node, parents: Node[]) {
78
+ if (!parents[0]) {
79
+ return false;
80
+ }
81
+
82
+ if (parents[0].type == "ImportDeclaration" && parents[0].source == object) {
83
+ return true;
84
+ }
85
+
86
+ if (parents[0].type == "ImportExpression" && parents[0].source == object) {
87
+ return true;
88
+ }
89
+
90
+ if (
91
+ parents[1] &&
92
+ parents[1].type == "CallExpression" &&
93
+ parents[1].arguments[0] === object &&
94
+ parents[1].callee.type == "Identifier"
95
+ ) {
96
+ if (
97
+ parents[1].callee.name == "require" ||
98
+ parents[1].callee.name == "import"
99
+ ) {
100
+ return true;
101
+ }
102
+ }
103
+
104
+ return false;
105
+ }
106
+
107
+ export function isMoveable(object: Node, parents: Node[]) {
108
+ return !isDirective(object, parents) && !isModuleSource(object, parents);
109
+ }
110
+
77
111
  export function isIndependent(object: Node, parents: Node[]) {
78
112
  if (object.type == "Literal") {
79
113
  return true;
80
114
  }
81
115
 
82
- var parent = parents[0];
83
-
84
116
  if (object.type == "Identifier") {
85
- var set = new Set(["null", "undefined"]);
86
- if (set.has(object.name)) {
117
+ if (primitiveIdentifiers.has(object.name)) {
87
118
  return true;
88
119
  }
89
- if (parent.type == "Property") {
120
+
121
+ var parent = parents[0];
122
+ if (parent && parent.type == "Property") {
90
123
  if (!parent.computed && parent.key == object) {
91
124
  return true;
92
125
  }
@@ -105,6 +138,7 @@ export function isIndependent(object: Node, parents: Node[]) {
105
138
  if (object != $object) {
106
139
  if (!Array.isArray($object) && !isIndependent($object, $parents)) {
107
140
  allowIt = false;
141
+ return "EXIT";
108
142
  }
109
143
  }
110
144
  });
package/src/util/gen.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { ok } from "assert";
2
+ import { predictableFunctionTag } from "../constants";
2
3
  import { isValidIdentifier } from "./compare";
3
4
 
4
5
  export type Type =
@@ -306,6 +307,7 @@ export function FunctionExpression(params: Node[], body: any[]) {
306
307
  generator: false,
307
308
  expression: false,
308
309
  async: false,
310
+ [predictableFunctionTag]: true,
309
311
  };
310
312
  }
311
313
 
@@ -340,6 +342,7 @@ export function FunctionDeclaration(
340
342
  generator: false,
341
343
  expression: false,
342
344
  async: false,
345
+ [predictableFunctionTag]: true,
343
346
  };
344
347
  }
345
348
 
@@ -529,16 +532,20 @@ export function AddComment(node: Node, text: string) {
529
532
  return node;
530
533
  }
531
534
 
535
+ export function Super() {
536
+ return { type: "Super" };
537
+ }
538
+
532
539
  export function MethodDefinition(
533
- identifier: Node,
540
+ key: Node,
534
541
  functionExpression: Node,
535
542
  kind: "method" | "constructor" | "get" | "set",
536
- isStatic = true,
543
+ isStatic = false,
537
544
  computed = false
538
545
  ) {
539
546
  return {
540
547
  type: "MethodDefinition",
541
- key: identifier,
548
+ key: key,
542
549
  computed: computed,
543
550
  value: functionExpression,
544
551
  kind: kind,
package/src/util/guard.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { variableFunctionName } from "../constants";
1
2
  import { Node } from "./gen";
2
3
 
3
4
  export function isStringLiteral(node: Node) {
@@ -5,3 +6,12 @@ export function isStringLiteral(node: Node) {
5
6
  node.type === "Literal" && typeof node.value === "string" && !node.regex
6
7
  );
7
8
  }
9
+
10
+ export function isJSConfuserVar(p: Node[]) {
11
+ return p.find(
12
+ (x) =>
13
+ x.type === "CallExpression" &&
14
+ x.callee.type === "Identifier" &&
15
+ x.callee.name == variableFunctionName
16
+ );
17
+ }