js-confuser 1.2.1 → 1.4.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.
Files changed (94) hide show
  1. package/CHANGELOG.md +171 -0
  2. package/README.md +7 -6
  3. package/dist/options.js +5 -1
  4. package/dist/parser.js +1 -2
  5. package/dist/presets.js +2 -2
  6. package/dist/transforms/calculator.js +48 -60
  7. package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +482 -95
  8. package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +4 -0
  9. package/dist/transforms/controlFlowFlattening/{switchCaseObfucation.js → switchCaseObfuscation.js} +2 -2
  10. package/dist/transforms/deadCode.js +1 -1
  11. package/dist/transforms/dispatcher.js +14 -13
  12. package/dist/transforms/extraction/duplicateLiteralsRemoval.js +5 -10
  13. package/dist/transforms/flatten.js +5 -1
  14. package/dist/transforms/hideInitializingCode.js +17 -2
  15. package/dist/transforms/identifier/globalConcealing.js +46 -25
  16. package/dist/transforms/identifier/movedDeclarations.js +69 -68
  17. package/dist/transforms/identifier/renameVariables.js +22 -98
  18. package/dist/transforms/identifier/variableAnalysis.js +133 -0
  19. package/dist/transforms/label.js +11 -2
  20. package/dist/transforms/lock/antiDebug.js +32 -13
  21. package/dist/transforms/lock/lock.js +13 -2
  22. package/dist/transforms/minify.js +117 -120
  23. package/dist/transforms/opaquePredicates.js +4 -2
  24. package/dist/transforms/preparation/preparation.js +8 -0
  25. package/dist/transforms/renameLabels.js +17 -3
  26. package/dist/transforms/rgf.js +8 -3
  27. package/dist/transforms/shuffle.js +25 -9
  28. package/dist/transforms/stack.js +5 -9
  29. package/dist/transforms/string/encoding.js +209 -0
  30. package/dist/transforms/string/stringCompression.js +10 -10
  31. package/dist/transforms/string/stringConcealing.js +94 -65
  32. package/dist/transforms/string/stringSplitting.js +7 -7
  33. package/dist/transforms/transform.js +10 -0
  34. package/dist/traverse.js +1 -35
  35. package/dist/util/gen.js +3 -1
  36. package/dist/util/identifiers.js +9 -19
  37. package/dist/util/insert.js +6 -40
  38. package/dist/util/scope.js +17 -0
  39. package/package.json +2 -2
  40. package/src/options.ts +19 -3
  41. package/src/parser.ts +1 -2
  42. package/src/presets.ts +2 -2
  43. package/src/transforms/calculator.ts +87 -91
  44. package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +742 -142
  45. package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +6 -0
  46. package/src/transforms/controlFlowFlattening/{switchCaseObfucation.ts → switchCaseObfuscation.ts} +6 -2
  47. package/src/transforms/deadCode.ts +8 -0
  48. package/src/transforms/dispatcher.ts +29 -14
  49. package/src/transforms/extraction/duplicateLiteralsRemoval.ts +43 -19
  50. package/src/transforms/flatten.ts +15 -2
  51. package/src/transforms/hideInitializingCode.ts +432 -406
  52. package/src/transforms/identifier/globalConcealing.ts +148 -46
  53. package/src/transforms/identifier/movedDeclarations.ts +78 -101
  54. package/src/transforms/identifier/renameVariables.ts +21 -96
  55. package/src/transforms/identifier/variableAnalysis.ts +124 -0
  56. package/src/transforms/label.ts +20 -2
  57. package/src/transforms/lock/antiDebug.ts +69 -26
  58. package/src/transforms/lock/lock.ts +37 -3
  59. package/src/transforms/minify.ts +154 -130
  60. package/src/transforms/opaquePredicates.ts +25 -3
  61. package/src/transforms/preparation/preparation.ts +8 -1
  62. package/src/transforms/renameLabels.ts +26 -3
  63. package/src/transforms/rgf.ts +6 -1
  64. package/src/transforms/shuffle.ts +87 -29
  65. package/src/transforms/stack.ts +6 -8
  66. package/src/transforms/string/encoding.ts +310 -0
  67. package/src/transforms/string/stringCompression.ts +37 -24
  68. package/src/transforms/string/stringConcealing.ts +157 -160
  69. package/src/transforms/string/stringSplitting.ts +12 -8
  70. package/src/transforms/transform.ts +15 -2
  71. package/src/traverse.ts +1 -31
  72. package/src/util/gen.ts +5 -3
  73. package/src/util/identifiers.ts +20 -20
  74. package/src/util/insert.ts +12 -78
  75. package/src/util/scope.ts +9 -0
  76. package/test/{transforms/compare.test.ts → compare.test.ts} +2 -2
  77. package/test/index.test.ts +109 -1
  78. package/test/templates/template.test.ts +14 -0
  79. package/test/transforms/controlFlowFlattening/controlFlowFlattening.test.ts +392 -10
  80. package/test/transforms/dispatcher.test.ts +30 -0
  81. package/test/transforms/flatten.test.ts +28 -0
  82. package/test/transforms/hideInitializingCode.test.ts +336 -336
  83. package/test/transforms/identifier/globalConcealing.test.ts +1 -2
  84. package/test/transforms/identifier/movedDeclarations.test.ts +137 -112
  85. package/test/transforms/identifier/renameVariables.test.ts +124 -13
  86. package/test/transforms/lock/antiDebug.test.ts +43 -0
  87. package/test/transforms/lock/selfDefending.test.ts +68 -0
  88. package/test/transforms/minify.test.ts +137 -0
  89. package/test/transforms/renameLabels.test.ts +33 -0
  90. package/test/transforms/rgf.test.ts +29 -0
  91. package/test/transforms/string/stringSplitting.test.ts +33 -0
  92. package/test/util/identifiers.test.ts +105 -17
  93. package/dist/util/expr.js +0 -60
  94. package/src/util/expr.ts +0 -56
@@ -12,8 +12,16 @@ import {
12
12
  MemberExpression,
13
13
  SwitchStatement,
14
14
  SwitchCase,
15
+ LogicalExpression,
16
+ VariableDeclarator,
17
+ FunctionExpression,
18
+ ExpressionStatement,
19
+ SequenceExpression,
20
+ AssignmentExpression,
21
+ VariableDeclaration,
22
+ BreakStatement,
15
23
  } from "../../util/gen";
16
- import { prepend } from "../../util/insert";
24
+ import { append, prepend } from "../../util/insert";
17
25
  import { getIdentifierInfo } from "../../util/identifiers";
18
26
  import { getRandomInteger } from "../../util/random";
19
27
  import { reservedIdentifiers, reservedKeywords } from "../../constants";
@@ -98,15 +106,12 @@ class GlobalAnalysis extends Transform {
98
106
  */
99
107
  export default class GlobalConcealing extends Transform {
100
108
  globalAnalysis: GlobalAnalysis;
101
- globalVar: string;
102
109
 
103
110
  constructor(o) {
104
111
  super(o, ObfuscateOrder.GlobalConcealing);
105
112
 
106
113
  this.globalAnalysis = new GlobalAnalysis(o);
107
114
  this.before.push(this.globalAnalysis);
108
-
109
- this.globalVar = null;
110
115
  }
111
116
 
112
117
  match(object: Node, parents: Node[]) {
@@ -120,6 +125,8 @@ export default class GlobalConcealing extends Transform {
120
125
  delete globals[del];
121
126
  });
122
127
 
128
+ delete globals["require"];
129
+
123
130
  reservedIdentifiers.forEach((x) => {
124
131
  delete globals[x];
125
132
  });
@@ -141,28 +148,38 @@ export default class GlobalConcealing extends Transform {
141
148
 
142
149
  // 1. Make getter function
143
150
 
144
- this.globalVar = this.getPlaceholder();
151
+ // holds "window" or "global"
152
+ var globalVar = this.getPlaceholder();
153
+
154
+ // holds outermost "this"
155
+ var thisVar = this.getPlaceholder();
156
+
145
157
  // "window" or "global" in node
146
158
  var global =
147
159
  this.options.globalVariables.values().next().value || "window";
148
- var callee = this.getPlaceholder();
160
+ var getGlobalVariableFnName = this.getPlaceholder();
161
+ var getThisVariableFnName = this.getPlaceholder();
149
162
 
150
163
  // Returns global variable or fall backs to `this`
151
- var functionDeclaration = Template(`
152
- function ${callee}(){
164
+ var getGlobalVariableFn = Template(`
165
+ var ${getGlobalVariableFnName} = function(){
153
166
  try {
154
167
  return ${global};
155
168
  } catch (e){
169
+ return ${getThisVariableFnName}["call"](this);
170
+ }
171
+ }`).single();
172
+
173
+ var getThisVariableFn = Template(`
174
+ var ${getThisVariableFnName} = function(){
175
+ try {
156
176
  return this;
177
+ } catch (e){
178
+ return null;
157
179
  }
158
180
  }`).single();
159
181
 
160
182
  // 2. Replace old accessors
161
-
162
- var variableDeclaration = Template(`
163
- var ${this.globalVar} = ${callee}.call(this);
164
- `).single();
165
-
166
183
  var globalFn = this.getPlaceholder();
167
184
 
168
185
  var newNames = Object.create(null);
@@ -179,6 +196,20 @@ export default class GlobalConcealing extends Transform {
179
196
 
180
197
  locations.forEach(([node, parents]) => {
181
198
  if (!parents.find((x) => x.$dispatcherSkip)) {
199
+ // Do not replace
200
+ if (parents[0]) {
201
+ if (
202
+ parents[0].type == "ClassDeclaration" ||
203
+ parents[0].type == "ClassExpression" ||
204
+ parents[0].type == "FunctionExpression" ||
205
+ parents[0].type == "FunctionDeclaration"
206
+ ) {
207
+ if (parents[0].id === node) {
208
+ return;
209
+ }
210
+ }
211
+ }
212
+
182
213
  this.replace(
183
214
  node,
184
215
  CallExpression(Identifier(globalFn), [Literal(state)])
@@ -188,49 +219,120 @@ export default class GlobalConcealing extends Transform {
188
219
  });
189
220
 
190
221
  // Adds all global variables to the switch statement
191
- // this.options.globalVariables.forEach((name) => {
192
- // if (!newNames[name]) {
193
- // var state;
194
- // do {
195
- // state = getRandomInteger(
196
- // -1000,
197
- // 1000 + used.size + this.options.globalVariables.size
198
- // );
199
- // } while (used.has(state));
200
- // used.add(state);
201
-
202
- // newNames[name] = state;
203
- // }
204
- // });
205
-
206
- prepend(
207
- object,
208
- FunctionDeclaration(
209
- globalFn,
210
- [Identifier("index")],
211
- [
212
- SwitchStatement(
213
- Identifier("index"),
214
- Object.keys(newNames).map((name) => {
215
- var code = newNames[name];
216
-
217
- return SwitchCase(Literal(code), [
218
- ReturnStatement(
222
+ this.options.globalVariables.forEach((name) => {
223
+ if (!newNames[name]) {
224
+ var state;
225
+ do {
226
+ state = getRandomInteger(
227
+ -1000,
228
+ 1000 + used.size + this.options.globalVariables.size * 100
229
+ );
230
+ } while (used.has(state));
231
+ used.add(state);
232
+
233
+ newNames[name] = state;
234
+ }
235
+ });
236
+
237
+ var indexParamName = this.getPlaceholder();
238
+ var returnName = this.getPlaceholder();
239
+
240
+ var functionDeclaration = FunctionDeclaration(
241
+ globalFn,
242
+ [Identifier(indexParamName)],
243
+ [
244
+ VariableDeclaration(VariableDeclarator(returnName)),
245
+ SwitchStatement(
246
+ Identifier(indexParamName),
247
+ Object.keys(newNames).map((name) => {
248
+ var code = newNames[name];
249
+ var body: Node[] = [
250
+ ReturnStatement(
251
+ LogicalExpression(
252
+ "||",
219
253
  MemberExpression(
220
- Identifier(this.globalVar),
254
+ Identifier(globalVar),
221
255
  Literal(name),
222
256
  true
257
+ ),
258
+ MemberExpression(Identifier(thisVar), Literal(name), true)
259
+ )
260
+ ),
261
+ ];
262
+ if (Math.random() > 0.5 && name) {
263
+ body = [
264
+ ExpressionStatement(
265
+ AssignmentExpression(
266
+ "=",
267
+ Identifier(returnName),
268
+ LogicalExpression(
269
+ "||",
270
+ Literal(name),
271
+ MemberExpression(
272
+ Identifier(thisVar),
273
+ Literal(name),
274
+ true
275
+ )
276
+ )
223
277
  )
224
278
  ),
225
- ]);
226
- })
279
+ BreakStatement(),
280
+ ];
281
+ }
282
+
283
+ return SwitchCase(Literal(code), body);
284
+ })
285
+ ),
286
+ ReturnStatement(
287
+ LogicalExpression(
288
+ "||",
289
+ MemberExpression(
290
+ Identifier(globalVar),
291
+ Identifier(returnName),
292
+ true
293
+ ),
294
+ MemberExpression(
295
+ Identifier(thisVar),
296
+ Identifier(returnName),
297
+ true
298
+ )
299
+ )
300
+ ),
301
+ ]
302
+ );
303
+
304
+ var tempVar = this.getPlaceholder();
305
+
306
+ var variableDeclaration = Template(`
307
+ var ${globalVar}, ${thisVar};
308
+ `).single();
309
+
310
+ variableDeclaration.declarations.push(
311
+ VariableDeclarator(
312
+ tempVar,
313
+ CallExpression(
314
+ MemberExpression(
315
+ FunctionExpression(
316
+ [],
317
+ [
318
+ getGlobalVariableFn,
319
+ getThisVariableFn,
320
+
321
+ Template(
322
+ `return ${thisVar} = ${getThisVariableFnName}["call"](this, ${globalFn}), ${globalVar} = ${getGlobalVariableFnName}["call"](this)`
323
+ ).single(),
324
+ ]
325
+ ),
326
+ Literal("call"),
327
+ true
227
328
  ),
228
- ]
329
+ []
330
+ )
229
331
  )
230
332
  );
231
333
 
232
334
  prepend(object, variableDeclaration);
233
- prepend(object, functionDeclaration);
335
+ append(object, functionDeclaration);
234
336
  }
235
337
  };
236
338
  }
@@ -7,14 +7,16 @@ import {
7
7
  AssignmentExpression,
8
8
  Identifier,
9
9
  Node,
10
- VariableDeclaration,
11
10
  VariableDeclarator,
11
+ VariableDeclaration,
12
12
  } from "../../util/gen";
13
13
  import { clone, isForInitialize, isFunction, prepend } from "../../util/insert";
14
14
  import { ok } from "assert";
15
15
  import { ObfuscateOrder } from "../../order";
16
16
  import { getIdentifierInfo } from "../../util/identifiers";
17
17
  import { isLoop } from "../../util/compare";
18
+ import { reservedIdentifiers } from "../../constants";
19
+ import { isLexicalScope, getLexicalScope } from "../../util/scope";
18
20
 
19
21
  /**
20
22
  * Defines all the names at the top of every lexical block.
@@ -25,139 +27,114 @@ export default class MovedDeclarations extends Transform {
25
27
  }
26
28
 
27
29
  match(object, parents) {
28
- return isBlock(object) && (!parents[0] || !isLoop(parents[0]));
30
+ return isLexicalScope(object);
29
31
  }
30
32
 
31
33
  transform(object: Node, parents: Node[]) {
32
34
  return () => {
33
- var block = getBlock(object, parents);
35
+ var body = isBlock(object) ? object.body : object.consequent;
36
+ ok(Array.isArray(body));
34
37
 
35
- var varDecs: Location[] = [];
36
- var varNames = new Set<string>();
37
38
  var illegal = new Set<string>();
38
- var toReplace: [string[], Node, Node][] = [];
39
- var definingIdentifiers = new Map<string, Node>();
40
-
41
- walk(object, parents, (o: Node, p: Node[]) => {
42
- if (o.type == "Identifier" && !illegal.has(o.name)) {
43
- var info = getIdentifierInfo(o, p);
44
- if (info.spec.isDefined && definingIdentifiers.has(o.name)) {
39
+ var defined = new Set<string>();
40
+ var variableDeclarations: {
41
+ [name: string]: {
42
+ location: Location;
43
+ replace: Node;
44
+ };
45
+ } = Object.create(null);
46
+
47
+ walk(object, parents, (o, p) => {
48
+ if (o.type == "Identifier") {
49
+ if (getLexicalScope(o, p) !== object) {
45
50
  illegal.add(o.name);
46
- this.log(o.name, "is illegal due to detected being redefined");
47
- }
48
- if (info.spec.isDefined && p.find((x) => x.type == "SwitchCase")) {
49
- illegal.add(o.name);
50
- this.log(o.name, "is illegal due being in switch case");
51
- }
51
+ } else {
52
+ var info = getIdentifierInfo(o, p);
53
+ if (!info.spec.isReferenced) {
54
+ return;
55
+ }
52
56
 
53
- if (o.hidden) {
54
- illegal.add(o.name);
57
+ if (info.spec.isDefined) {
58
+ if (info.isFunctionDeclaration || info.isClassDeclaration) {
59
+ illegal.add(o.name);
60
+ } else {
61
+ if (defined.has(o.name)) {
62
+ illegal.add(o.name);
63
+ } else {
64
+ defined.add(o.name);
65
+ }
66
+ }
67
+ }
55
68
  }
56
69
  }
57
70
 
58
- var s = getBlock(o, p);
59
- if (s == block) {
71
+ if (o.type == "VariableDeclaration") {
60
72
  return () => {
61
73
  if (
62
- o.type == "VariableDeclaration" &&
63
- o.declarations.length &&
64
- o.kind !== "let" &&
65
- !o.declarations.find(
66
- (x) => x.id.type !== "Identifier" || illegal.has(x.id.name)
67
- )
74
+ o.declarations.length === 1 &&
75
+ o.declarations[0].id.type === "Identifier"
68
76
  ) {
69
- var index = block.body.indexOf(o);
70
- if (index === 0 || o.hidden) {
71
- o.declarations.forEach((x) => {
72
- illegal.add(x.id.name);
73
- });
74
- this.log(
75
- o.declarations.map((x) => x.id.name).join(", "),
76
- "is/are illegal due to already being at the top"
77
- );
77
+ var name = o.declarations[0].id.name;
78
+
79
+ // Check if duplicate
80
+ if (variableDeclarations[name] || o.kind !== "var") {
81
+ illegal.add(name);
78
82
  return;
79
83
  }
80
84
 
81
- if (isForInitialize(o, p)) {
82
- this.log(
83
- o.declarations.map((x) => x.id.name).join(", "),
84
- "is/are illegal due to being in for initializer"
85
- );
85
+ // Check if already at top
86
+ if (body[0] === o) {
87
+ illegal.add(name);
86
88
  return;
87
89
  }
88
90
 
89
- var isIllegal = false;
90
- o.declarations.forEach((x) => {
91
- if (varNames.has(x.id.name)) {
92
- illegal.add(x.id.name);
93
- isIllegal = true;
94
-
95
- this.log(
96
- x.id.name,
97
- "is illegal due to already being defined"
98
- );
99
- }
100
- });
101
-
102
- if (!isIllegal) {
103
- varDecs.push([o, p]);
104
-
105
- o.declarations.forEach((x) => {
106
- ok(x.id.name);
107
- varNames.add(x.id.name);
108
-
109
- definingIdentifiers.set(x.id.name, x.id);
110
- });
111
-
112
- // Change this line to assignment expressions
113
-
114
- var assignmentExpressions = o.declarations.map((x) =>
115
- AssignmentExpression(
116
- "=",
117
- clone(x.id),
118
- clone(x.init) || Identifier("undefined")
119
- )
120
- );
121
-
122
- ok(assignmentExpressions.length, "Should be at least 1");
123
-
124
- var value: Node = SequenceExpression(assignmentExpressions);
125
-
126
- value = ExpressionStatement(value);
127
-
128
- toReplace.push([
129
- o.declarations.map((x) => x.id.name),
130
- o,
131
- value,
132
- ]);
91
+ var replace: Node = AssignmentExpression(
92
+ "=",
93
+ Identifier(name),
94
+ o.declarations[0].init || Identifier("undefined")
95
+ );
96
+
97
+ var forType = isForInitialize(o, p);
98
+ if (forType === "left-hand") {
99
+ replace = Identifier(name);
100
+ } else if (!forType) {
101
+ replace = ExpressionStatement(replace);
133
102
  }
103
+ variableDeclarations[name] = {
104
+ location: [o, p],
105
+ replace: replace,
106
+ };
134
107
  }
135
108
  };
136
109
  }
137
110
  });
138
111
 
139
112
  illegal.forEach((name) => {
140
- varNames.delete(name);
113
+ delete variableDeclarations[name];
141
114
  });
142
115
 
143
- toReplace.forEach((x) => {
144
- if (!x[0].find((x) => illegal.has(x))) {
145
- this.replace(x[1], x[2]);
146
- }
147
- });
116
+ var movingNames = Object.keys(variableDeclarations);
148
117
 
149
- // Define the names in this block as 1 variable declaration
150
- if (varNames.size > 0) {
151
- this.log("Moved", varNames);
118
+ if (movingNames.length === 0) {
119
+ return;
120
+ }
152
121
 
153
- var variableDeclaration = VariableDeclaration(
154
- Array.from(varNames).map((x) => {
155
- return VariableDeclarator(x);
156
- })
157
- );
122
+ var variableDeclaration = VariableDeclaration(
123
+ movingNames.map((name) => {
124
+ return VariableDeclarator(name);
125
+ })
126
+ );
158
127
 
159
- prepend(block, variableDeclaration);
128
+ if (object.type == "Program") {
129
+ prepend(object, variableDeclaration);
130
+ } else {
131
+ body.unshift(variableDeclaration);
160
132
  }
133
+
134
+ movingNames.forEach((name) => {
135
+ var { location, replace } = variableDeclarations[name];
136
+ this.replace(location[0], replace);
137
+ });
161
138
  };
162
139
  }
163
140
  }
@@ -15,91 +15,7 @@ import { isValidIdentifier } from "../../util/compare";
15
15
  import Transform from "../transform";
16
16
  import { reservedIdentifiers } from "../../constants";
17
17
  import { ComputeProbabilityMap } from "../../probability";
18
-
19
- /**
20
- * Keeps track of what identifiers are defined and referenced in each context.
21
- */
22
- export class VariableAnalysis extends Transform {
23
- /**
24
- * Node being the context.
25
- */
26
- defined: Map<Node, Set<string>>;
27
- references: Map<Node, Set<string>>;
28
-
29
- constructor(o) {
30
- super(o);
31
-
32
- this.defined = new Map();
33
- this.references = new Map();
34
- }
35
-
36
- match(object, parents) {
37
- return isContext(object);
38
- }
39
-
40
- transform(object, parents) {
41
- walk(object, parents, (o, p) => {
42
- if (o.type == "Identifier") {
43
- var name = o.name;
44
- ok(typeof name === "string");
45
- if (!isValidIdentifier(name)) {
46
- return;
47
- }
48
-
49
- if (reservedIdentifiers.has(name)) {
50
- return;
51
- }
52
- if (this.options.globalVariables.has(name)) {
53
- return;
54
- }
55
-
56
- var info = getIdentifierInfo(o, p);
57
- if (!info.spec.isReferenced) {
58
- return;
59
- }
60
-
61
- if (info.spec.isExported) {
62
- return;
63
- }
64
-
65
- var definingContexts = info.spec.isDefined
66
- ? [getDefiningContext(o, p)]
67
- : [getVarContext(o, p), getLexContext(o, p)];
68
-
69
- ok(definingContexts.length);
70
-
71
- var isDefined = info.spec.isDefined;
72
- definingContexts.forEach((definingContext) => {
73
- ok(
74
- isContext(definingContext),
75
- `${definingContext.type} is not a context`
76
- );
77
-
78
- if (isDefined) {
79
- // Add to defined Map
80
- if (!this.defined.has(definingContext)) {
81
- this.defined.set(definingContext, new Set());
82
- }
83
- this.defined.get(definingContext).add(name);
84
- this.references.has(definingContext) &&
85
- this.references.get(definingContext).delete(name);
86
- } else {
87
- // Add to references Map
88
- if (
89
- !this.defined.has(definingContext) ||
90
- !this.defined.get(definingContext).has(name)
91
- ) {
92
- if (!this.references.has(definingContext)) {
93
- this.references.set(definingContext, new Set());
94
- }
95
- this.references.get(definingContext).add(name);
96
- }
97
- }
98
- });
99
- }
100
- });
101
- }
102
- }
18
+ import VariableAnalysis from "./variableAnalysis";
103
19
 
104
20
  /**
105
21
  * Rename variables to randomly generated names.
@@ -123,7 +39,9 @@ export default class RenameVariables extends Transform {
123
39
  super(o, ObfuscateOrder.RenameVariables);
124
40
 
125
41
  this.changed = new Map();
126
- this.before.push((this.variableAnalysis = new VariableAnalysis(o)));
42
+
43
+ this.variableAnalysis = new VariableAnalysis(o);
44
+ this.before.push(this.variableAnalysis);
127
45
  this.gen = this.getGenerator();
128
46
  this.generated = [];
129
47
  }
@@ -204,16 +122,23 @@ export default class RenameVariables extends Transform {
204
122
  isGlobal
205
123
  )
206
124
  ) {
207
- if (possible.size) {
208
- var first = possible.values().next().value;
209
- possible.delete(first);
210
- newNames[name] = first;
211
- } else {
212
- // Fix 1. Use `generateIdentifier` over `gen.generate()` so Integrity can get unique variable names
213
- var g = this.generateIdentifier();
214
- newNames[name] = g;
215
- this.generated.push(g);
216
- }
125
+ // Fix 2. Ensure global names aren't overridden
126
+ var newName;
127
+ do {
128
+ if (possible.size) {
129
+ var first = possible.values().next().value;
130
+ possible.delete(first);
131
+ newName = first;
132
+ } else {
133
+ // Fix 1. Use `generateIdentifier` over `gen.generate()` so Integrity can get unique variable names
134
+ var g = this.generateIdentifier();
135
+
136
+ newName = g;
137
+ this.generated.push(g);
138
+ }
139
+ } while (this.variableAnalysis.globals.has(newName));
140
+
141
+ newNames[name] = newName;
217
142
  } else {
218
143
  newNames[name] = name;
219
144
  }