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,19 +1,7 @@
1
1
  import Transform from "../transform";
2
2
  import { walk } from "../../traverse";
3
- import {
4
- Node,
5
- Location,
6
- Identifier,
7
- VariableDeclaration,
8
- VariableDeclarator,
9
- } from "../../util/gen";
10
- import {
11
- clone,
12
- deleteDeclaration,
13
- getVarContext,
14
- isVarContext,
15
- prepend,
16
- } from "../../util/insert";
3
+ import { Node, Location, Identifier, VariableDeclarator } from "../../util/gen";
4
+ import { getVarContext, isVarContext } from "../../util/insert";
17
5
  import { ObfuscateOrder } from "../../order";
18
6
  import { getIdentifierInfo } from "../../util/identifiers";
19
7
  import { isValidIdentifier } from "../../util/compare";
@@ -316,8 +304,9 @@ export default class ObjectExtraction extends Transform {
316
304
  ...variableDeclarators
317
305
  );
318
306
 
307
+ // const can only be safely changed to let
319
308
  if (declaration.kind === "const") {
320
- declaration.kind = "var";
309
+ declaration.kind = "let";
321
310
  }
322
311
 
323
312
  // update all identifiers that pointed to the old object
@@ -1,5 +1,9 @@
1
1
  import { ok } from "assert";
2
- import { noRenameVariablePrefix, reservedIdentifiers } from "../constants";
2
+ import {
3
+ noRenameVariablePrefix,
4
+ predictableFunctionTag,
5
+ reservedIdentifiers,
6
+ } from "../constants";
3
7
  import { ObfuscateOrder } from "../order";
4
8
  import { walk } from "../traverse";
5
9
  import {
@@ -35,6 +39,7 @@ import {
35
39
  import { shuffle } from "../util/random";
36
40
  import Transform from "./transform";
37
41
  import { FunctionLengthTemplate } from "../templates/functionLength";
42
+ import { ObjectDefineProperty } from "../templates/globals";
38
43
 
39
44
  /**
40
45
  * Flatten takes functions and isolates them from their original scope, and brings it to the top level of the program.
@@ -235,7 +240,11 @@ export default class Flatten extends Transform {
235
240
  return;
236
241
  }
237
242
 
238
- var newFnName = this.getPlaceholder() + "_flat_" + currentFnName;
243
+ var newFnName =
244
+ this.getPlaceholder() +
245
+ "_flat_" +
246
+ currentFnName +
247
+ predictableFunctionTag;
239
248
  var flatObjectName = this.getPlaceholder() + "_flat_object";
240
249
 
241
250
  const getFlatObjectMember = (propertyName: string) => {
@@ -498,15 +507,21 @@ export default class Flatten extends Transform {
498
507
  // Preserve function.length property
499
508
  var originalFunctionLength = computeFunctionLength(object.params);
500
509
 
501
- object.params = [SpreadElement(Identifier(argumentsName))];
510
+ object.params = [RestElement(Identifier(argumentsName))];
502
511
 
503
- if (originalFunctionLength !== 0) {
512
+ if (this.options.preserveFunctionLength && originalFunctionLength !== 0) {
504
513
  if (!this.functionLengthName) {
505
514
  this.functionLengthName = this.getPlaceholder();
506
515
 
507
516
  prepend(
508
517
  parents[parents.length - 1] || object,
509
- FunctionLengthTemplate.single({ name: this.functionLengthName })
518
+ FunctionLengthTemplate.single({
519
+ name: this.functionLengthName,
520
+ ObjectDefineProperty: this.createInitVariable(
521
+ ObjectDefineProperty,
522
+ parents
523
+ ),
524
+ })
510
525
  );
511
526
  }
512
527
 
@@ -1,5 +1,6 @@
1
1
  import { reservedKeywords } from "../../constants";
2
2
  import { Location, Node } from "../../util/gen";
3
+ import { isJSConfuserVar } from "../../util/guard";
3
4
  import { getIdentifierInfo } from "../../util/identifiers";
4
5
  import Transform from "../transform";
5
6
 
@@ -43,10 +44,26 @@ export default class GlobalAnalysis extends Transform {
43
44
  return;
44
45
  }
45
46
 
47
+ if (isJSConfuserVar(parents)) {
48
+ delete this.globals[object.name];
49
+ this.notGlobals.add(object.name);
50
+ return;
51
+ }
52
+
46
53
  // Cannot be defined or overridden
47
54
  if (info.spec.isDefined || info.spec.isModified) {
48
- delete this.globals[object.name];
55
+ if (info.spec.isModified) {
56
+ // Only direct overwrites should be considered
57
+ // Changing object properties is allowed
58
+ if (
59
+ parents[0].type === "MemberExpression" &&
60
+ parents[0].object === object
61
+ ) {
62
+ return;
63
+ }
64
+ }
49
65
 
66
+ delete this.globals[object.name];
50
67
  this.notGlobals.add(object.name);
51
68
  return;
52
69
  }
@@ -22,9 +22,15 @@ import {
22
22
  } from "../../util/gen";
23
23
  import { append, prepend } from "../../util/insert";
24
24
  import { chance, getRandomInteger } from "../../util/random";
25
- import { reservedIdentifiers } from "../../constants";
25
+ import {
26
+ predictableFunctionTag,
27
+ reservedIdentifiers,
28
+ variableFunctionName,
29
+ } from "../../constants";
26
30
  import { ComputeProbabilityMap } from "../../probability";
27
31
  import GlobalAnalysis from "./globalAnalysis";
32
+ import { createGetGlobalTemplate } from "../../templates/bufferToString";
33
+ import { isJSConfuserVar } from "../../util/guard";
28
34
 
29
35
  /**
30
36
  * Global Concealing hides global variables being accessed.
@@ -33,6 +39,12 @@ import GlobalAnalysis from "./globalAnalysis";
33
39
  */
34
40
  export default class GlobalConcealing extends Transform {
35
41
  globalAnalysis: GlobalAnalysis;
42
+ ignoreGlobals = new Set([
43
+ "require",
44
+ "__dirname",
45
+ "eval",
46
+ variableFunctionName,
47
+ ]);
36
48
 
37
49
  constructor(o) {
38
50
  super(o, ObfuscateOrder.GlobalConcealing);
@@ -52,7 +64,9 @@ export default class GlobalConcealing extends Transform {
52
64
  delete globals[del];
53
65
  });
54
66
 
55
- delete globals["require"];
67
+ for (var varName of this.ignoreGlobals) {
68
+ delete globals[varName];
69
+ }
56
70
 
57
71
  reservedIdentifiers.forEach((x) => {
58
72
  delete globals[x];
@@ -69,63 +83,114 @@ export default class GlobalConcealing extends Transform {
69
83
  });
70
84
 
71
85
  if (Object.keys(globals).length > 0) {
72
- var used = new Set();
86
+ var usedStates = new Set<number>();
73
87
 
74
88
  // Make getter function
75
89
 
76
90
  // holds "window" or "global"
77
91
  var globalVar = this.getPlaceholder();
78
92
 
79
- // holds outermost "this"
80
- var thisVar = this.getPlaceholder();
81
-
82
- // "window" or "global" in node
83
- var global =
84
- this.options.globalVariables.values().next().value || "window";
85
- var alternateGlobal = global === "window" ? "global" : "window";
86
-
87
- var getGlobalVariableFnName = this.getPlaceholder();
88
- var getThisVariableFnName = this.getPlaceholder();
93
+ var getGlobalVariableFnName =
94
+ this.getPlaceholder() + predictableFunctionTag;
89
95
 
90
96
  // Returns global variable or fall backs to `this`
91
- var getGlobalVariableFn = Template(`
92
- var ${getGlobalVariableFnName} = function(){
93
- try {
94
- return ${global} || ${alternateGlobal} || (new Function("return this"))();
95
- } catch (e){
96
- return ${getThisVariableFnName}["call"](this);
97
- }
98
- }`).single();
99
-
100
- var getThisVariableFn = Template(`
101
- var ${getThisVariableFnName} = function(){
102
- try {
103
- return this;
104
- } catch (e){
105
- return null;
106
- }
107
- }`).single();
97
+ var getGlobalVariableFn = createGetGlobalTemplate(
98
+ this,
99
+ object,
100
+ parents
101
+ ).compile({
102
+ getGlobalFnName: getGlobalVariableFnName,
103
+ });
108
104
 
109
105
  // 2. Replace old accessors
110
- var globalFn = this.getPlaceholder();
106
+ var globalFn = this.getPlaceholder() + predictableFunctionTag;
111
107
 
112
108
  var newNames: { [globalVarName: string]: number } = Object.create(null);
113
109
 
114
110
  Object.keys(globals).forEach((name) => {
115
111
  var locations: Location[] = globals[name];
116
- var state;
112
+ var state: number;
117
113
  do {
118
- state = getRandomInteger(-1000, 1000 + used.size);
119
- } while (used.has(state));
120
- used.add(state);
114
+ state = getRandomInteger(-1000, 1000 + usedStates.size);
115
+ } while (usedStates.has(state));
116
+ usedStates.add(state);
121
117
 
122
118
  newNames[name] = state;
123
119
 
124
- locations.forEach(([node, parents]) => {
125
- this.replace(
126
- node,
127
- CallExpression(Identifier(globalFn), [Literal(state)])
128
- );
120
+ locations.forEach(([node, p]) => {
121
+ if (p.find((x) => x.$multiTransformSkip)) {
122
+ return;
123
+ }
124
+
125
+ var newExpression = CallExpression(Identifier(globalFn), [
126
+ Literal(state),
127
+ ]);
128
+
129
+ this.replace(node, newExpression);
130
+
131
+ if (
132
+ this.options.lock?.tamperProtection &&
133
+ this.lockTransform.nativeFunctionName
134
+ ) {
135
+ var isMemberExpression = false;
136
+ var nameAndPropertyPath = [name];
137
+ var callExpression: Node;
138
+
139
+ var index = 0;
140
+ do {
141
+ if (p[index].type === "CallExpression") {
142
+ callExpression = p[index];
143
+ break;
144
+ }
145
+
146
+ var memberExpression = p[index];
147
+ if (memberExpression.type !== "MemberExpression") return;
148
+ var property = memberExpression.property;
149
+ var stringValue =
150
+ property.type === "Literal"
151
+ ? property.value
152
+ : memberExpression.computed
153
+ ? null
154
+ : property.type === "Identifier"
155
+ ? property.name
156
+ : null;
157
+
158
+ if (!stringValue) return;
159
+
160
+ isMemberExpression = true;
161
+ nameAndPropertyPath.push(stringValue);
162
+ index++;
163
+ } while (index < p.length);
164
+
165
+ if (
166
+ !this.lockTransform.shouldTransformNativeFunction(
167
+ nameAndPropertyPath
168
+ )
169
+ )
170
+ return;
171
+
172
+ if (callExpression && callExpression.type === "CallExpression") {
173
+ if (isMemberExpression) {
174
+ callExpression.callee = CallExpression(
175
+ Identifier(this.lockTransform.nativeFunctionName),
176
+ [
177
+ callExpression.callee.object,
178
+ callExpression.callee.computed
179
+ ? callExpression.callee.property
180
+ : Literal(
181
+ callExpression.callee.property.name ||
182
+ callExpression.callee.property.value
183
+ ),
184
+ ]
185
+ );
186
+ } else {
187
+ callExpression.callee = CallExpression(
188
+ Identifier(this.lockTransform.nativeFunctionName),
189
+ [{ ...callExpression.callee }]
190
+ );
191
+ }
192
+ }
193
+ }
129
194
  });
130
195
  });
131
196
 
@@ -136,10 +201,10 @@ export default class GlobalConcealing extends Transform {
136
201
  do {
137
202
  state = getRandomInteger(
138
203
  0,
139
- 1000 + used.size + this.options.globalVariables.size * 100
204
+ 1000 + usedStates.size + this.options.globalVariables.size * 100
140
205
  );
141
- } while (used.has(state));
142
- used.add(state);
206
+ } while (usedStates.has(state));
207
+ usedStates.add(state);
143
208
 
144
209
  newNames[name] = state;
145
210
  }
@@ -159,15 +224,7 @@ export default class GlobalConcealing extends Transform {
159
224
  var code = newNames[name];
160
225
  var body: Node[] = [
161
226
  ReturnStatement(
162
- LogicalExpression(
163
- "||",
164
- MemberExpression(
165
- Identifier(globalVar),
166
- Literal(name),
167
- true
168
- ),
169
- MemberExpression(Identifier(thisVar), Literal(name), true)
170
- )
227
+ MemberExpression(Identifier(globalVar), Literal(name), true)
171
228
  ),
172
229
  ];
173
230
  if (chance(50)) {
@@ -180,7 +237,7 @@ export default class GlobalConcealing extends Transform {
180
237
  "||",
181
238
  Literal(name),
182
239
  MemberExpression(
183
- Identifier(thisVar),
240
+ Identifier(globalVar),
184
241
  Literal(name),
185
242
  true
186
243
  )
@@ -195,18 +252,10 @@ export default class GlobalConcealing extends Transform {
195
252
  })
196
253
  ),
197
254
  ReturnStatement(
198
- LogicalExpression(
199
- "||",
200
- MemberExpression(
201
- Identifier(globalVar),
202
- Identifier(returnName),
203
- true
204
- ),
205
- MemberExpression(
206
- Identifier(thisVar),
207
- Identifier(returnName),
208
- true
209
- )
255
+ MemberExpression(
256
+ Identifier(globalVar),
257
+ Identifier(returnName),
258
+ true
210
259
  )
211
260
  ),
212
261
  ]
@@ -214,8 +263,8 @@ export default class GlobalConcealing extends Transform {
214
263
 
215
264
  var tempVar = this.getPlaceholder();
216
265
 
217
- var variableDeclaration = Template(`
218
- var ${globalVar}, ${thisVar};
266
+ var variableDeclaration = new Template(`
267
+ var ${globalVar};
219
268
  `).single();
220
269
 
221
270
  variableDeclaration.declarations.push(
@@ -226,11 +275,9 @@ export default class GlobalConcealing extends Transform {
226
275
  FunctionExpression(
227
276
  [],
228
277
  [
229
- getGlobalVariableFn,
230
- getThisVariableFn,
231
-
232
- Template(
233
- `return ${thisVar} = ${getThisVariableFnName}["call"](this, ${globalFn}), ${globalVar} = ${getGlobalVariableFnName}["call"](this)`
278
+ ...getGlobalVariableFn,
279
+ new Template(
280
+ `return ${globalVar} = ${getGlobalVariableFnName}["call"](this)`
234
281
  ).single(),
235
282
  ]
236
283
  ),
@@ -6,10 +6,21 @@ import {
6
6
  Identifier,
7
7
  Node,
8
8
  VariableDeclarator,
9
+ AssignmentPattern,
9
10
  } from "../../util/gen";
10
- import { isForInitialize, prepend } from "../../util/insert";
11
+ import {
12
+ isForInitialize,
13
+ isFunction,
14
+ isStrictModeFunction,
15
+ prepend,
16
+ } from "../../util/insert";
11
17
  import { ok } from "assert";
12
18
  import { ObfuscateOrder } from "../../order";
19
+ import { choice } from "../../util/random";
20
+ import { predictableFunctionTag } from "../../constants";
21
+ import { isIndependent, isMoveable } from "../../util/compare";
22
+ import { getFunctionParameters } from "../../util/identifiers";
23
+ import { isLexicalScope } from "../../util/scope";
13
24
 
14
25
  /**
15
26
  * Defines all the names at the top of every lexical block.
@@ -33,35 +44,86 @@ export default class MovedDeclarations extends Transform {
33
44
  var forInitializeType = isForInitialize(object, parents);
34
45
 
35
46
  // Get the block statement or Program node
36
- var blockIndex = parents.findIndex((x) => isBlock(x));
47
+ var blockIndex = parents.findIndex((x) => isLexicalScope(x));
37
48
  var block = parents[blockIndex];
38
- var body = block.body;
39
- var bodyObject = parents[blockIndex - 2] || object;
49
+ var body: Node[] =
50
+ block.type === "SwitchCase" ? block.consequent : block.body;
51
+ ok(Array.isArray(body), "No body array found.");
40
52
 
41
- // Make sure in the block statement, and not already at the top of it
53
+ var bodyObject = parents[blockIndex - 2] || object;
42
54
  var index = body.indexOf(bodyObject);
43
- if (index === -1 || index === 0) return;
44
55
 
45
- var topVariableDeclaration;
46
- if (body[0].type === "VariableDeclaration" && body[0].kind === "var") {
47
- topVariableDeclaration = body[0];
56
+ var varName = object.declarations[0].id.name;
57
+ ok(typeof varName === "string");
58
+
59
+ var predictableFunctionIndex = parents.findIndex((x) => isFunction(x));
60
+ var predictableFunction = parents[predictableFunctionIndex];
61
+
62
+ var deleteStatement = false;
63
+
64
+ if (
65
+ predictableFunction &&
66
+ ((predictableFunction.id &&
67
+ predictableFunction.id.name.includes(predictableFunctionTag)) ||
68
+ predictableFunction[predictableFunctionTag]) && // Must have predictableFunctionTag in the name, or on object
69
+ predictableFunction[predictableFunctionTag] !== false && // If === false, the function is deemed not predictable
70
+ predictableFunction.params.length < 1000 && // Max 1,000 parameters
71
+ !predictableFunction.params.find((x) => x.type === "RestElement") && // Cannot add parameters after spread operator
72
+ !(
73
+ ["Property", "MethodDefinition"].includes(
74
+ parents[predictableFunctionIndex + 1]?.type
75
+ ) && parents[predictableFunctionIndex + 1]?.kind !== "init"
76
+ ) && // Preserve getter/setter methods
77
+ !getFunctionParameters(
78
+ predictableFunction,
79
+ parents.slice(predictableFunctionIndex)
80
+ ).find((entry) => entry[0].name === varName) // Ensure not duplicate param name
81
+ ) {
82
+ // Use function f(..., x, y, z) to declare name
83
+
84
+ var value = object.declarations[0].init;
85
+ var isPredictablyComputed =
86
+ predictableFunction.body === block &&
87
+ !isStrictModeFunction(predictableFunction) &&
88
+ value &&
89
+ isIndependent(value, []) &&
90
+ isMoveable(value, [object.declarations[0], object, ...parents]);
91
+
92
+ var defineWithValue = isPredictablyComputed;
93
+
94
+ if (defineWithValue) {
95
+ predictableFunction.params.push(
96
+ AssignmentPattern(Identifier(varName), value)
97
+ );
98
+ object.declarations[0].init = null;
99
+ deleteStatement = true;
100
+ } else {
101
+ predictableFunction.params.push(Identifier(varName));
102
+ }
48
103
  } else {
49
- topVariableDeclaration = {
50
- type: "VariableDeclaration",
51
- declarations: [],
52
- kind: "var",
53
- };
104
+ // Use 'var x, y, z' to declare name
54
105
 
55
- prepend(block, topVariableDeclaration);
56
- }
106
+ // Make sure in the block statement, and not already at the top of it
107
+ if (index === -1 || index === 0) return;
57
108
 
58
- var varName = object.declarations[0].id.name;
59
- ok(typeof varName === "string");
109
+ var topVariableDeclaration;
110
+ if (body[0].type === "VariableDeclaration" && body[0].kind === "var") {
111
+ topVariableDeclaration = body[0];
112
+ } else {
113
+ topVariableDeclaration = {
114
+ type: "VariableDeclaration",
115
+ declarations: [],
116
+ kind: "var",
117
+ };
60
118
 
61
- // Add `var x` at the top of the block
62
- topVariableDeclaration.declarations.push(
63
- VariableDeclarator(Identifier(varName))
64
- );
119
+ prepend(block, topVariableDeclaration);
120
+ }
121
+
122
+ // Add `var x` at the top of the block
123
+ topVariableDeclaration.declarations.push(
124
+ VariableDeclarator(Identifier(varName))
125
+ );
126
+ }
65
127
 
66
128
  var assignmentExpression = AssignmentExpression(
67
129
  "=",
@@ -79,8 +141,12 @@ export default class MovedDeclarations extends Transform {
79
141
  this.replace(object, Identifier(varName));
80
142
  }
81
143
  } else {
82
- // Replace `var x = value` to `x = value`
83
- this.replace(object, ExpressionStatement(assignmentExpression));
144
+ if (deleteStatement && index !== -1) {
145
+ body.splice(index, 1);
146
+ } else {
147
+ // Replace `var x = value` to `x = value`
148
+ this.replace(object, ExpressionStatement(assignmentExpression));
149
+ }
84
150
  }
85
151
  };
86
152
  }
@@ -1,7 +1,7 @@
1
1
  import { ok } from "assert";
2
2
  import { ObfuscateOrder } from "../../order";
3
3
  import { walk } from "../../traverse";
4
- import { Node } from "../../util/gen";
4
+ import { Literal, Node } from "../../util/gen";
5
5
  import { getIdentifierInfo } from "../../util/identifiers";
6
6
  import {
7
7
  isVarContext,
@@ -15,6 +15,7 @@ import {
15
15
  noRenameVariablePrefix,
16
16
  placeholderVariablePrefix,
17
17
  reservedIdentifiers,
18
+ variableFunctionName,
18
19
  } from "../../constants";
19
20
  import { ComputeProbabilityMap } from "../../probability";
20
21
  import VariableAnalysis from "./variableAnalysis";
@@ -267,6 +268,20 @@ export default class RenameVariables extends Transform {
267
268
  }
268
269
  }
269
270
 
271
+ if (
272
+ parents[1] &&
273
+ parents[1].type === "CallExpression" &&
274
+ parents[1].arguments === parents[0]
275
+ ) {
276
+ if (
277
+ parents[1].callee.type === "Identifier" &&
278
+ parents[1].callee.name === variableFunctionName
279
+ ) {
280
+ this.replace(parents[1], Literal(newName));
281
+ return;
282
+ }
283
+ }
284
+
270
285
  // console.log(o.name, "->", newName);
271
286
  // 5. Update Identifier node's 'name' property
272
287
  object.name = newName;
@@ -16,7 +16,7 @@ import { getRandomInteger } from "../../util/random";
16
16
  import Transform from "../transform";
17
17
  import Lock from "./lock";
18
18
 
19
- var DevToolsDetection = Template(
19
+ var DevToolsDetection = new Template(
20
20
  `
21
21
  try {
22
22
  if ( setInterval ) {
@@ -52,7 +52,7 @@ export default class AntiDebug extends Transform {
52
52
  fnName,
53
53
  [],
54
54
  [
55
- ...Template(`
55
+ ...new Template(`
56
56
  var ${startTimeName} = new Date();
57
57
  debugger;
58
58
  var ${endTimeName} = new Date();