js-confuser 1.7.0 → 1.7.2

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 (128) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/README.md +12 -29
  3. package/dist/compiler.js +2 -8
  4. package/dist/constants.js +17 -10
  5. package/dist/index.js +7 -30
  6. package/dist/obfuscator.js +15 -62
  7. package/dist/options.js +21 -38
  8. package/dist/order.js +4 -7
  9. package/dist/parser.js +5 -13
  10. package/dist/precedence.js +6 -8
  11. package/dist/presets.js +4 -6
  12. package/dist/probability.js +13 -24
  13. package/dist/templates/bufferToString.js +100 -5
  14. package/dist/templates/crash.js +51 -9
  15. package/dist/templates/es5.js +125 -6
  16. package/dist/templates/functionLength.js +24 -6
  17. package/dist/templates/globals.js +9 -0
  18. package/dist/templates/template.js +71 -30
  19. package/dist/transforms/antiTooling.js +26 -22
  20. package/dist/transforms/calculator.js +18 -54
  21. package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +236 -333
  22. package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +46 -25
  23. package/dist/transforms/deadCode.js +528 -27
  24. package/dist/transforms/dispatcher.js +110 -108
  25. package/dist/transforms/es5/antiClass.js +70 -44
  26. package/dist/transforms/es5/antiDestructuring.js +14 -38
  27. package/dist/transforms/es5/antiES6Object.js +39 -48
  28. package/dist/transforms/es5/antiSpreadOperator.js +5 -14
  29. package/dist/transforms/es5/antiTemplate.js +10 -19
  30. package/dist/transforms/es5/es5.js +7 -40
  31. package/dist/transforms/extraction/classExtraction.js +83 -0
  32. package/dist/transforms/extraction/duplicateLiteralsRemoval.js +45 -79
  33. package/dist/transforms/extraction/objectExtraction.js +27 -54
  34. package/dist/transforms/finalizer.js +6 -20
  35. package/dist/transforms/flatten.js +51 -99
  36. package/dist/transforms/identifier/globalAnalysis.js +8 -26
  37. package/dist/transforms/identifier/globalConcealing.js +35 -54
  38. package/dist/transforms/identifier/movedDeclarations.js +66 -38
  39. package/dist/transforms/identifier/renameVariables.js +29 -68
  40. package/dist/transforms/identifier/variableAnalysis.js +21 -48
  41. package/dist/transforms/lock/antiDebug.js +20 -25
  42. package/dist/transforms/lock/integrity.js +48 -47
  43. package/dist/transforms/lock/lock.js +62 -113
  44. package/dist/transforms/minify.js +77 -108
  45. package/dist/transforms/opaquePredicates.js +11 -48
  46. package/dist/transforms/preparation.js +17 -50
  47. package/dist/transforms/renameLabels.js +5 -22
  48. package/dist/transforms/rgf.js +98 -66
  49. package/dist/transforms/shuffle.js +41 -46
  50. package/dist/transforms/stack.js +35 -98
  51. package/dist/transforms/string/encoding.js +73 -27
  52. package/dist/transforms/string/stringCompression.js +44 -68
  53. package/dist/transforms/string/stringConcealing.js +125 -134
  54. package/dist/transforms/string/stringEncoding.js +6 -26
  55. package/dist/transforms/string/stringSplitting.js +5 -30
  56. package/dist/transforms/transform.js +50 -100
  57. package/dist/traverse.js +11 -18
  58. package/dist/util/compare.js +27 -29
  59. package/dist/util/gen.js +32 -86
  60. package/dist/util/guard.js +0 -1
  61. package/dist/util/identifiers.js +11 -74
  62. package/dist/util/insert.js +27 -77
  63. package/dist/util/math.js +0 -3
  64. package/dist/util/object.js +3 -7
  65. package/dist/util/random.js +5 -36
  66. package/dist/util/scope.js +6 -3
  67. package/docs/ControlFlowFlattening.md +1 -1
  68. package/docs/ES5.md +197 -0
  69. package/package.json +3 -3
  70. package/src/constants.ts +12 -0
  71. package/src/options.ts +13 -0
  72. package/src/order.ts +2 -2
  73. package/src/templates/bufferToString.ts +49 -11
  74. package/src/templates/functionLength.ts +21 -3
  75. package/src/templates/globals.ts +3 -0
  76. package/src/templates/template.ts +85 -25
  77. package/src/transforms/antiTooling.ts +33 -11
  78. package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +2 -2
  79. package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +46 -10
  80. package/src/transforms/deadCode.ts +0 -16
  81. package/src/transforms/dispatcher.ts +101 -69
  82. package/src/transforms/es5/antiClass.ts +10 -1
  83. package/src/transforms/extraction/classExtraction.ts +168 -0
  84. package/src/transforms/extraction/duplicateLiteralsRemoval.ts +13 -10
  85. package/src/transforms/extraction/objectExtraction.ts +7 -14
  86. package/src/transforms/flatten.ts +20 -5
  87. package/src/transforms/identifier/globalConcealing.ts +29 -65
  88. package/src/transforms/identifier/movedDeclarations.ts +90 -24
  89. package/src/transforms/minify.ts +27 -12
  90. package/src/transforms/rgf.ts +103 -5
  91. package/src/transforms/stack.ts +12 -3
  92. package/src/transforms/string/encoding.ts +85 -51
  93. package/src/transforms/string/stringCompression.ts +5 -8
  94. package/src/transforms/string/stringConcealing.ts +139 -113
  95. package/src/transforms/string/stringEncoding.ts +1 -2
  96. package/src/transforms/string/stringSplitting.ts +1 -2
  97. package/src/transforms/transform.ts +30 -1
  98. package/src/util/compare.ts +39 -5
  99. package/src/util/gen.ts +10 -3
  100. package/src/util/identifiers.ts +6 -3
  101. package/src/util/insert.ts +17 -0
  102. package/src/util/scope.ts +14 -2
  103. package/test/code/Cash.test.ts +10 -4
  104. package/test/code/StrictMode.src.js +65 -0
  105. package/test/code/StrictMode.test.js +37 -0
  106. package/test/compare.test.ts +62 -2
  107. package/test/options.test.ts +111 -55
  108. package/test/transforms/controlFlowFlattening/expressionObfuscation.test.ts +37 -18
  109. package/test/transforms/dispatcher.test.ts +82 -0
  110. package/test/transforms/extraction/classExtraction.test.ts +86 -0
  111. package/test/transforms/extraction/duplicateLiteralsRemoval.test.ts +29 -8
  112. package/test/transforms/extraction/objectExtraction.test.ts +37 -15
  113. package/test/transforms/identifier/globalConcealing.test.ts +42 -2
  114. package/test/transforms/identifier/movedDeclarations.test.ts +61 -0
  115. package/test/transforms/lock/integrity.test.ts +24 -0
  116. package/test/transforms/minify.test.ts +37 -0
  117. package/test/transforms/rgf.test.ts +50 -0
  118. package/test/util/identifiers.test.ts +21 -0
  119. package/dist/transforms/controlFlowFlattening/choiceFlowObfuscation.js +0 -62
  120. package/dist/transforms/controlFlowFlattening/controlFlowObfuscation.js +0 -159
  121. package/dist/transforms/controlFlowFlattening/switchCaseObfuscation.js +0 -106
  122. package/dist/transforms/eval.js +0 -84
  123. package/dist/transforms/hexadecimalNumbers.js +0 -63
  124. package/dist/transforms/hideInitializingCode.js +0 -270
  125. package/dist/transforms/identifier/nameRecycling.js +0 -218
  126. package/dist/transforms/label.js +0 -67
  127. package/dist/transforms/preparation/nameConflicts.js +0 -116
  128. package/dist/transforms/preparation/preparation.js +0 -188
@@ -4,40 +4,25 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
-
8
7
  var _assert = require("assert");
9
-
10
8
  var _order = require("../../order");
11
-
12
9
  var _probability = require("../../probability");
13
-
14
10
  var _template = _interopRequireDefault(require("../../templates/template"));
15
-
16
11
  var _traverse = require("../../traverse");
17
-
18
12
  var _gen = require("../../util/gen");
19
-
20
13
  var _identifiers = require("../../util/identifiers");
21
-
22
14
  var _insert = require("../../util/insert");
23
-
24
15
  var _random = require("../../util/random");
25
-
26
16
  var _transform = _interopRequireDefault(require("../transform"));
27
-
28
17
  var _expressionObfuscation = _interopRequireDefault(require("./expressionObfuscation"));
29
-
30
- var _stringConcealing = require("../string/stringConcealing");
31
-
32
18
  var _constants = require("../../constants");
33
-
34
19
  var _compare = require("../../util/compare");
35
-
36
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
37
-
38
- function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
39
-
20
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
21
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
22
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
23
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
40
24
  const flattenStructures = new Set(["IfStatement", "ForStatement", "WhileStatement", "DoWhileStatement"]);
25
+
41
26
  /**
42
27
  * A chunk represents a small segment of code
43
28
  */
@@ -56,131 +41,113 @@ const flattenStructures = new Set(["IfStatement", "ForStatement", "WhileStatemen
56
41
  * - 3. The while loop continues until the the state variable is the end state.
57
42
  */
58
43
  class ControlFlowFlattening extends _transform.default {
59
- // in Debug mode, the output is much easier to read
60
- // Flatten if-statements, for-loops, etc
61
- // var control = { str1, num1 }
62
- // 50 => state + X
63
- // true => state == X
64
- // console => (state == X ? console : _)
65
- // Tries to outline entire chunks
66
- // Tries to outline expressions found in chunks
67
- // case s != 49 && s - 10:
68
- // case 100: case 490: case 510: ...
69
- // add fakes chunks of code
70
- // predicate ? REAL : FAKE
71
- // s=NEXT_STATE,flag=true,break
72
- // Limit amount of mangling
73
- // Amount of blocks changed by Control Flow Flattening
74
44
  constructor(o) {
75
45
  super(o, _order.ObfuscateOrder.ControlFlowFlattening);
76
-
46
+ // in Debug mode, the output is much easier to read
77
47
  _defineProperty(this, "isDebug", false);
78
-
79
48
  _defineProperty(this, "flattenControlStructures", true);
80
-
49
+ // Flatten if-statements, for-loops, etc
81
50
  _defineProperty(this, "addToControlObject", true);
82
-
51
+ // var control = { str1, num1 }
83
52
  _defineProperty(this, "mangleNumberLiterals", true);
84
-
53
+ // 50 => state + X
85
54
  _defineProperty(this, "mangleBooleanLiterals", true);
86
-
55
+ // true => state == X
87
56
  _defineProperty(this, "mangleIdentifiers", true);
88
-
57
+ // console => (state == X ? console : _)
89
58
  _defineProperty(this, "outlineStatements", true);
90
-
59
+ // Tries to outline entire chunks
91
60
  _defineProperty(this, "outlineExpressions", true);
92
-
61
+ // Tries to outline expressions found in chunks
93
62
  _defineProperty(this, "addComplexTest", true);
94
-
63
+ // case s != 49 && s - 10:
95
64
  _defineProperty(this, "addFakeTest", true);
96
-
65
+ // case 100: case 490: case 510: ...
97
66
  _defineProperty(this, "addDeadCode", true);
98
-
67
+ // add fakes chunks of code
99
68
  _defineProperty(this, "addOpaquePredicates", true);
100
-
69
+ // predicate ? REAL : FAKE
101
70
  _defineProperty(this, "addFlaggedLabels", true);
102
-
71
+ // s=NEXT_STATE,flag=true,break
72
+ // Limit amount of mangling
103
73
  _defineProperty(this, "mangledExpressionsMade", 0);
104
-
74
+ // Amount of blocks changed by Control Flow Flattening
105
75
  _defineProperty(this, "cffCount", 0);
106
-
107
76
  if (!this.isDebug) {
108
77
  this.before.push(new _expressionObfuscation.default(o));
109
78
  } else {
110
79
  console.warn("Debug mode enabled");
111
80
  }
112
81
  }
113
-
114
82
  match(object, parents) {
115
83
  return (0, _traverse.isBlock)(object) && (!parents[0] || !flattenStructures.has(parents[0].type)) && (!parents[1] || !flattenStructures.has(parents[1].type));
116
84
  }
117
-
118
85
  transform(object, parents) {
119
86
  var _this = this;
120
-
121
87
  // Must be at least 3 statements or more
122
88
  if (object.body.length < 3) {
123
89
  return;
124
- } // No 'let'/'const' allowed (These won't work in Switch cases!)
125
-
126
-
90
+ }
91
+ // No 'let'/'const' allowed (These won't work in Switch cases!)
127
92
  if ((0, _identifiers.containsLexicallyBoundVariables)(object, parents)) {
128
93
  return;
129
- } // Check user's threshold setting
130
-
131
-
94
+ }
95
+ // Check user's threshold setting
132
96
  if (!(0, _probability.ComputeProbabilityMap)(this.options.controlFlowFlattening, x => x)) {
133
97
  return;
134
98
  }
135
-
136
99
  var objectBody = (0, _insert.getBlockBody)(object.body);
137
-
138
100
  if (!objectBody.length) {
139
101
  return;
140
- } // Purely for naming purposes
102
+ }
141
103
 
104
+ // Purely for naming purposes
105
+ var cffIndex = this.cffCount++;
142
106
 
143
- var cffIndex = this.cffCount++; // The controlVar is an object containing:
107
+ // The controlVar is an object containing:
144
108
  // - Strings found in chunks
145
109
  // - Numbers found in chunks
146
110
  // - Helper functions to adjust the state
147
111
  // - Outlined expressions changed into functions
148
-
149
- var controlVar = this.getPlaceholder() + "_c".concat(cffIndex, "_CONTROL");
112
+ var controlVar = this.getPlaceholder() + `_c${cffIndex}_CONTROL`;
150
113
  var controlProperties = [];
151
114
  var controlConstantMap = new Map();
152
115
  var controlGen = this.getGenerator("mangled");
153
- var controlTestKey = controlGen.generate(); // This 'controlVar' can be accessed by child-nodes
116
+ var controlTestKey = controlGen.generate();
154
117
 
118
+ // This 'controlVar' can be accessed by child-nodes
155
119
  object.$controlVar = controlVar;
156
120
  object.$controlConstantMap = controlConstantMap;
157
121
  object.$controlProperties = controlProperties;
158
122
  object.$controlGen = controlGen;
159
123
  return () => {
160
- (0, _assert.ok)(Array.isArray(objectBody)); // The state variable names (and quantity)
124
+ (0, _assert.ok)(Array.isArray(objectBody));
161
125
 
162
- var stateVars = Array(this.isDebug ? 1 : (0, _random.getRandomInteger)(2, 5)).fill(0).map((_, i) => this.getPlaceholder() + "_c".concat(cffIndex, "_S").concat(i)); // How often should chunks be split up?
163
- // Percentage between 10% and 90% based on block size
126
+ // The state variable names (and quantity)
127
+ var stateVars = Array(this.isDebug ? 1 : (0, _random.getRandomInteger)(2, 5)).fill(0).map((_, i) => this.getPlaceholder() + `_c${cffIndex}_S${i}`);
164
128
 
165
- var splitPercent = Math.max(10, 90 - objectBody.length * 5); // Find functions and import declarations
129
+ // How often should chunks be split up?
130
+ // Percentage between 10% and 90% based on block size
131
+ var splitPercent = Math.max(10, 90 - objectBody.length * 5);
166
132
 
133
+ // Find functions and import declarations
167
134
  var importDeclarations = [];
168
135
  var functionDeclarationNames = new Set();
169
- var functionDeclarationValues = new Map(); // Find all parent control-nodes
136
+ var functionDeclarationValues = new Map();
170
137
 
138
+ // Find all parent control-nodes
171
139
  const allControlNodes = [object];
172
140
  parents.filter(x => x.$controlVar).forEach(node => allControlNodes.push(node));
173
-
174
141
  const addControlMapConstant = literalValue => {
175
142
  var _selectedControlConst;
176
-
177
143
  // Choose a random control node to add to
178
144
  var controlNode = (0, _random.choice)(allControlNodes);
179
145
  var selectedControlVar = controlNode.$controlVar;
180
146
  var selectedControlConstantMap = controlNode.$controlConstantMap;
181
147
  var selectedControlProperties = controlNode.$controlProperties;
182
- var key = (_selectedControlConst = selectedControlConstantMap.get(literalValue)) === null || _selectedControlConst === void 0 ? void 0 : _selectedControlConst.key; // Not found, create
148
+ var key = (_selectedControlConst = selectedControlConstantMap.get(literalValue)) === null || _selectedControlConst === void 0 ? void 0 : _selectedControlConst.key;
183
149
 
150
+ // Not found, create
184
151
  if (!key) {
185
152
  key = controlNode.$controlGen.generate();
186
153
  selectedControlConstantMap.set(literalValue, {
@@ -188,63 +155,59 @@ class ControlFlowFlattening extends _transform.default {
188
155
  });
189
156
  selectedControlProperties.push((0, _gen.Property)((0, _gen.Literal)(key), (0, _gen.Literal)(literalValue), false));
190
157
  }
191
-
192
158
  return getControlMember(key, selectedControlVar);
193
- }; // Helper function to easily make control object accessors
194
-
159
+ };
195
160
 
161
+ // Helper function to easily make control object accessors
196
162
  const getControlMember = function (key) {
197
163
  let objectName = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : controlVar;
198
164
  return (0, _gen.MemberExpression)((0, _gen.Identifier)(objectName), (0, _gen.Literal)(key), true);
199
- }; // This function recursively calls itself to flatten and split up code into 'chunks'
200
-
165
+ };
201
166
 
167
+ // This function recursively calls itself to flatten and split up code into 'chunks'
202
168
  const flattenBody = (body, startingLabel) => {
203
169
  var chunks = [];
204
170
  var currentBody = [];
205
- var currentLabel = startingLabel; // This function ends the current chunk being created ('currentBody')
171
+ var currentLabel = startingLabel;
206
172
 
173
+ // This function ends the current chunk being created ('currentBody')
207
174
  const finishCurrentChunk = function (pointingLabel, newLabel) {
208
175
  let addGotoStatement = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
209
-
210
176
  if (!newLabel) {
211
177
  newLabel = _this.getPlaceholder();
212
178
  }
213
-
214
179
  if (!pointingLabel) {
215
180
  pointingLabel = newLabel;
216
181
  }
217
-
218
182
  if (addGotoStatement) {
219
183
  currentBody.push({
220
184
  type: "GotoStatement",
221
185
  label: pointingLabel
222
186
  });
223
187
  }
224
-
225
188
  chunks.push({
226
189
  label: currentLabel,
227
190
  body: [...currentBody]
228
- }); // Random chance of this chunk being flagged (First label cannot be flagged)
191
+ });
229
192
 
193
+ // Random chance of this chunk being flagged (First label cannot be flagged)
230
194
  if (!_this.isDebug && _this.addFlaggedLabels && currentLabel !== startLabel && (0, _random.chance)(25)) {
231
195
  flaggedLabels[currentLabel] = {
232
196
  flagKey: controlGen.generate(),
233
197
  flagValue: (0, _random.choice)([true, false])
234
198
  };
235
199
  }
236
-
237
200
  (0, _traverse.walk)(currentBody, [], (o, p) => {
238
201
  if (o.type === "Literal" && !_this.isDebug) {
239
202
  // Add strings to the control object
240
- if (_this.addToControlObject && typeof o.value === "string" && o.value.length >= 3 && o.value.length <= 100 && !(0, _stringConcealing.isModuleSource)(o, p) && !(0, _compare.isDirective)(o, p) && !o.regex && (0, _random.chance)(50 - controlConstantMap.size - _this.mangledExpressionsMade / 100)) {
203
+ if (_this.addToControlObject && typeof o.value === "string" && o.value.length >= 3 && o.value.length <= 100 && !(0, _compare.isModuleSource)(o, p) && !(0, _compare.isDirective)(o, p) && !o.regex && (0, _random.chance)(50 - controlConstantMap.size - _this.mangledExpressionsMade / 100)) {
241
204
  return () => {
242
205
  _this.replaceIdentifierOrLiteral(o, addControlMapConstant(o.value), p);
243
206
  };
244
- } // Add numbers to the control object
245
-
207
+ }
246
208
 
247
- if (_this.addToControlObject && typeof o.value === "number" && Math.floor(o.value) === o.value && Math.abs(o.value) < 100000 && (0, _random.chance)(50 - controlConstantMap.size - _this.mangledExpressionsMade / 100)) {
209
+ // Add numbers to the control object
210
+ if (_this.addToControlObject && typeof o.value === "number" && Math.floor(o.value) === o.value && Math.abs(o.value) < 100_000 && (0, _random.chance)(50 - controlConstantMap.size - _this.mangledExpressionsMade / 100)) {
248
211
  return () => {
249
212
  _this.replaceIdentifierOrLiteral(o, addControlMapConstant(o.value), p);
250
213
  };
@@ -254,11 +217,10 @@ class ControlFlowFlattening extends _transform.default {
254
217
  currentLabel = newLabel;
255
218
  currentBody = [];
256
219
  };
257
-
258
220
  if (body !== objectBody) {
259
221
  // This code is nested. Move function declarations up
260
- var newBody = [];
261
222
 
223
+ var newBody = [];
262
224
  for (var stmt of body) {
263
225
  if (stmt.type === "FunctionDeclaration") {
264
226
  newBody.unshift(stmt);
@@ -266,10 +228,8 @@ class ControlFlowFlattening extends _transform.default {
266
228
  newBody.push(stmt);
267
229
  }
268
230
  }
269
-
270
231
  body = newBody;
271
232
  }
272
-
273
233
  body.forEach((stmt, i) => {
274
234
  if (stmt.type === "ImportDeclaration") {
275
235
  // The 'importDeclarations' hold statements that are required to be left untouched at the top of the block
@@ -280,14 +240,12 @@ class ControlFlowFlattening extends _transform.default {
280
240
  stmt.type = "FunctionExpression";
281
241
  stmt.id = null;
282
242
  functionDeclarationNames.add(functionName);
283
-
284
243
  if (objectBody === body) {
285
244
  functionDeclarationValues.set(functionName, stmt);
286
245
  return;
287
246
  } else {
288
247
  currentBody.push((0, _gen.ExpressionStatement)((0, _gen.AssignmentExpression)("=", (0, _gen.Identifier)(functionName), stmt)));
289
248
  }
290
-
291
249
  return;
292
250
  } else if (stmt.directive) {
293
251
  if (objectBody === body) {
@@ -295,21 +253,18 @@ class ControlFlowFlattening extends _transform.default {
295
253
  } else {
296
254
  this.error(new Error("Unimplemented directive support."));
297
255
  }
298
-
299
256
  return;
300
257
  }
301
-
302
258
  if (stmt.type == "GotoStatement" && i !== body.length - 1) {
303
259
  finishCurrentChunk(stmt.label);
304
260
  return;
305
- } // The Preparation transform adds labels to every Control-Flow node
306
-
261
+ }
307
262
 
263
+ // The Preparation transform adds labels to every Control-Flow node
308
264
  if (this.flattenControlStructures && stmt.type == "LabeledStatement") {
309
265
  var lbl = stmt.label.name;
310
266
  var control = stmt.body;
311
267
  var isSwitchStatement = control.type === "SwitchStatement";
312
-
313
268
  if (isSwitchStatement || (control.type == "ForStatement" || control.type == "WhileStatement" || control.type == "DoWhileStatement") && control.body.type == "BlockStatement") {
314
269
  if (isSwitchStatement) {
315
270
  if (control.cases.length == 0) {
@@ -317,7 +272,6 @@ class ControlFlowFlattening extends _transform.default {
317
272
  return;
318
273
  }
319
274
  }
320
-
321
275
  var isLoop = !isSwitchStatement;
322
276
  var supportContinueStatement = isLoop;
323
277
  var testPath = this.getPlaceholder();
@@ -325,19 +279,20 @@ class ControlFlowFlattening extends _transform.default {
325
279
  var bodyPath = this.getPlaceholder();
326
280
  var afterPath = this.getPlaceholder();
327
281
  var possible = true;
328
- var toReplace = []; // Find all break; and continue; statements and change them into 'GotoStatement's
282
+ var toReplace = [];
329
283
 
284
+ // Find all break; and continue; statements and change them into 'GotoStatement's
330
285
  (0, _traverse.walk)(control.body || control.cases, [], (o, p) => {
331
286
  if (o.type === "BreakStatement" || o.type === "ContinueStatement") {
332
287
  var allowedLabels = new Set(p.filter(x => x.type === "LabeledStatement" && x.body.type === "SwitchStatement").map(x => x.label.name));
333
288
  var isUnsupportedContinue = !supportContinueStatement && o.type === "ContinueStatement";
334
- var isInvalidLabel = !o.label || o.label.name !== lbl && !allowedLabels.has(o.label.name); // This seems like the best solution:
289
+ var isInvalidLabel = !o.label || o.label.name !== lbl && !allowedLabels.has(o.label.name);
335
290
 
291
+ // This seems like the best solution:
336
292
  if (isUnsupportedContinue || isInvalidLabel) {
337
293
  possible = false;
338
294
  return "EXIT";
339
295
  }
340
-
341
296
  if (o.label.name === lbl) {
342
297
  return () => {
343
298
  toReplace.push([o, {
@@ -348,24 +303,21 @@ class ControlFlowFlattening extends _transform.default {
348
303
  }
349
304
  }
350
305
  });
351
-
352
306
  if (!possible) {
353
307
  currentBody.push(stmt);
354
308
  return;
355
309
  }
356
-
357
310
  toReplace.forEach(v => this.replace(v[0], v[1]));
358
-
359
311
  if (isSwitchStatement) {
360
312
  var switchDiscriminantName = this.getPlaceholder() + "_switchD"; // Stores the value of the discriminant
361
-
362
313
  var switchTestName = this.getPlaceholder() + "_switchT"; // Set to true when a Switch case is matched
363
314
 
364
315
  currentBody.push((0, _gen.VariableDeclaration)((0, _gen.VariableDeclarator)(switchDiscriminantName, control.discriminant)));
365
- currentBody.push((0, _gen.VariableDeclaration)((0, _gen.VariableDeclarator)(switchTestName, (0, _gen.Literal)(false)))); // case labels are:
316
+ currentBody.push((0, _gen.VariableDeclaration)((0, _gen.VariableDeclarator)(switchTestName, (0, _gen.Literal)(false))));
317
+
318
+ // case labels are:
366
319
  // `${caseLabelPrefix}_test_${index}`
367
320
  // `${caseLabelPrefix}_entry_${index}`
368
-
369
321
  var caseLabelPrefix = this.getPlaceholder();
370
322
  var defaultCaseIndex = control.cases.findIndex(x => x.test === null);
371
323
  control.cases.forEach((switchCase, i) => {
@@ -376,25 +328,25 @@ class ControlFlowFlattening extends _transform.default {
376
328
  : caseLabelPrefix + "_entry_" + (i + 1);
377
329
  var nextTestPath = i === control.cases.length - 1 ? afterPath : caseLabelPrefix + "_test_" + (i + 1);
378
330
  finishCurrentChunk(testPath, testPath, i == 0);
379
-
380
331
  if (switchCase.test) {
381
332
  // Check the case condition and goto statement
382
333
  currentBody.push((0, _gen.IfStatement)((0, _gen.BinaryExpression)("===", (0, _gen.Identifier)(switchDiscriminantName), switchCase.test), [(0, _gen.ExpressionStatement)((0, _gen.AssignmentExpression)("=", (0, _gen.Identifier)(switchTestName), (0, _gen.Literal)(true))), {
383
334
  type: "GotoStatement",
384
335
  label: entryPath
385
336
  }]));
386
- } else {// Default case: No test needed.
387
- } // If default case, on last test, if no case was matched, goto default case
388
-
337
+ } else {
338
+ // Default case: No test needed.
339
+ }
389
340
 
341
+ // If default case, on last test, if no case was matched, goto default case
390
342
  if (i === control.cases.length - 1 && defaultCaseIndex !== -1) {
391
343
  currentBody.push((0, _gen.IfStatement)((0, _gen.UnaryExpression)("!", (0, _gen.Identifier)(switchTestName)), [{
392
344
  type: "GotoStatement",
393
345
  label: caseLabelPrefix + "_entry_" + defaultCaseIndex
394
346
  }]));
395
- } // Jump to next test
396
-
347
+ }
397
348
 
349
+ // Jump to next test
398
350
  currentBody.push({
399
351
  type: "GotoStatement",
400
352
  label: nextTestPath
@@ -407,25 +359,27 @@ class ControlFlowFlattening extends _transform.default {
407
359
  finishCurrentChunk(afterPath, afterPath, false);
408
360
  return;
409
361
  } else if (isLoop) {
410
- var isPostTest = control.type == "DoWhileStatement"; // add initializing section to current chunk
362
+ var isPostTest = control.type == "DoWhileStatement";
411
363
 
364
+ // add initializing section to current chunk
412
365
  if (control.init) {
413
366
  if (control.init.type == "VariableDeclaration") {
414
367
  currentBody.push(control.init);
415
368
  } else {
416
369
  currentBody.push((0, _gen.ExpressionStatement)(control.init));
417
370
  }
418
- } // create new label called `testPath` and have current chunk point to it (goto testPath)
419
-
371
+ }
420
372
 
373
+ // create new label called `testPath` and have current chunk point to it (goto testPath)
421
374
  finishCurrentChunk(isPostTest ? bodyPath : testPath, testPath);
422
375
  currentBody.push((0, _gen.ExpressionStatement)((0, _gen.AssignmentExpression)("=", getControlMember(controlTestKey), control.test || (0, _gen.Literal)(true))));
423
376
  finishCurrentChunk();
424
377
  currentBody.push((0, _gen.IfStatement)(getControlMember(controlTestKey), [{
425
378
  type: "GotoStatement",
426
379
  label: bodyPath
427
- }])); // create new label called `bodyPath` and have test body point to afterPath (goto afterPath)
380
+ }]));
428
381
 
382
+ // create new label called `bodyPath` and have test body point to afterPath (goto afterPath)
429
383
  finishCurrentChunk(afterPath, bodyPath);
430
384
  var innerBothPath = this.getPlaceholder();
431
385
  chunks.push(...flattenBody([...control.body.body, {
@@ -433,17 +387,14 @@ class ControlFlowFlattening extends _transform.default {
433
387
  label: updatePath
434
388
  }], innerBothPath));
435
389
  finishCurrentChunk(innerBothPath, updatePath);
436
-
437
390
  if (control.update) {
438
391
  currentBody.push((0, _gen.ExpressionStatement)(control.update));
439
392
  }
440
-
441
393
  finishCurrentChunk(testPath, afterPath);
442
394
  return;
443
395
  }
444
396
  }
445
397
  }
446
-
447
398
  if (this.flattenControlStructures && stmt.type == "IfStatement" && stmt.consequent.type == "BlockStatement" && (!stmt.alternate || stmt.alternate.type == "BlockStatement")) {
448
399
  finishCurrentChunk();
449
400
  currentBody.push((0, _gen.ExpressionStatement)((0, _gen.AssignmentExpression)("=", getControlMember(controlTestKey), stmt.test)));
@@ -461,7 +412,6 @@ class ControlFlowFlattening extends _transform.default {
461
412
  type: "GotoStatement",
462
413
  label: afterPath
463
414
  }], yesPath));
464
-
465
415
  if (hasAlternate) {
466
416
  chunks.push(...flattenBody([...stmt.alternate.body, {
467
417
  type: "GotoStatement",
@@ -471,10 +421,8 @@ class ControlFlowFlattening extends _transform.default {
471
421
  } else {
472
422
  finishCurrentChunk(afterPath, afterPath);
473
423
  }
474
-
475
424
  return;
476
425
  }
477
-
478
426
  if (!currentBody.length || !(0, _random.chance)(splitPercent)) {
479
427
  currentBody.push(stmt);
480
428
  } else {
@@ -487,6 +435,7 @@ class ControlFlowFlattening extends _transform.default {
487
435
  chunks[chunks.length - 1].body.pop();
488
436
  return chunks;
489
437
  };
438
+
490
439
  /**
491
440
  * Executable code segments are broken down into `chunks` typically 1-3 statements each
492
441
  *
@@ -504,15 +453,14 @@ class ControlFlowFlattening extends _transform.default {
504
453
  * }
505
454
  * GOTO NEXT_CHUNK;
506
455
  */
456
+ const chunks = [];
507
457
 
508
-
509
- const chunks = []; // Flagged labels have addition code protecting the control state
510
-
458
+ // Flagged labels have addition code protecting the control state
511
459
  const flaggedLabels = Object.create(null);
460
+
512
461
  /**
513
462
  * label: switch(a+b+c){...break label...}
514
463
  */
515
-
516
464
  const switchLabel = this.getPlaceholder();
517
465
  const startLabel = this.getPlaceholder();
518
466
  chunks.push(...flattenBody(objectBody, startLabel));
@@ -525,15 +473,14 @@ class ControlFlowFlattening extends _transform.default {
525
473
  body: []
526
474
  });
527
475
  const endLabel = chunks[Object.keys(chunks).length - 1].label;
528
-
529
476
  if (!this.isDebug && this.addDeadCode) {
530
477
  // DEAD CODE 1/3: Add fake chunks that are never reached
531
478
  var fakeChunkCount = (0, _random.getRandomInteger)(1, 5);
532
-
533
479
  for (var i = 0; i < fakeChunkCount; i++) {
534
480
  // These chunks just jump somewhere random, they are never executed
535
481
  // so it could contain any code
536
- var fakeChunkBody = [// This a fake assignment expression
482
+ var fakeChunkBody = [
483
+ // This a fake assignment expression
537
484
  (0, _gen.ExpressionStatement)((0, _gen.AssignmentExpression)("=", (0, _gen.Identifier)((0, _random.choice)(stateVars)), (0, _gen.Literal)((0, _random.getRandomInteger)(-150, 150)))), {
538
485
  type: "GotoStatement",
539
486
  label: (0, _random.choice)(chunks).label
@@ -543,63 +490,61 @@ class ControlFlowFlattening extends _transform.default {
543
490
  body: fakeChunkBody,
544
491
  impossible: true
545
492
  });
546
- } // DEAD CODE 2/3: Add fake jumps to really mess with deobfuscators
547
-
493
+ }
548
494
 
495
+ // DEAD CODE 2/3: Add fake jumps to really mess with deobfuscators
549
496
  chunks.forEach(chunk => {
550
497
  if ((0, _random.chance)(25)) {
551
- var randomLabel = (0, _random.choice)(chunks).label; // The `false` literal will be mangled
498
+ var randomLabel = (0, _random.choice)(chunks).label;
552
499
 
500
+ // The `false` literal will be mangled
553
501
  chunk.body.unshift((0, _gen.IfStatement)((0, _gen.Literal)(false), [{
554
502
  type: "GotoStatement",
555
503
  label: randomLabel,
556
504
  impossible: true
557
505
  }]));
558
506
  }
559
- }); // DEAD CODE 3/3: Clone chunks but these chunks are never ran
507
+ });
560
508
 
509
+ // DEAD CODE 3/3: Clone chunks but these chunks are never ran
561
510
  var cloneChunkCount = (0, _random.getRandomInteger)(1, 5);
562
-
563
511
  for (var i = 0; i < cloneChunkCount; i++) {
564
512
  var randomChunk = (0, _random.choice)(chunks);
565
513
  var clonedChunk = {
566
514
  body: (0, _insert.clone)(randomChunk.body),
567
515
  label: this.getPlaceholder(),
568
516
  impossible: true
569
- }; // Don't double define functions
517
+ };
570
518
 
519
+ // Don't double define functions
571
520
  var hasDeclaration = clonedChunk.body.find(stmt => {
572
521
  return stmt.type === "FunctionDeclaration" || stmt.type === "ClassDeclaration";
573
522
  });
574
-
575
523
  if (!hasDeclaration) {
576
524
  chunks.unshift(clonedChunk);
577
525
  }
578
526
  }
579
- } // Generate a unique 'state' number for each chunk
580
-
527
+ }
581
528
 
529
+ // Generate a unique 'state' number for each chunk
582
530
  var caseSelection = new Set();
583
531
  var uniqueStatesNeeded = chunks.length;
584
-
585
532
  do {
586
533
  var newState = (0, _random.getRandomInteger)(1, chunks.length * 15);
587
-
588
534
  if (this.isDebug) {
589
535
  newState = caseSelection.size;
590
536
  }
591
-
592
537
  caseSelection.add(newState);
593
538
  } while (caseSelection.size !== uniqueStatesNeeded);
594
-
595
539
  (0, _assert.ok)(caseSelection.size == uniqueStatesNeeded);
540
+
596
541
  /**
597
542
  * The accumulated state values
598
543
  *
599
544
  * index -> total state value
600
545
  */
601
-
602
546
  var caseStates = Array.from(caseSelection);
547
+
603
548
  /**
604
549
  * The individual state values for each label
605
550
  *
@@ -607,89 +552,82 @@ class ControlFlowFlattening extends _transform.default {
607
552
  *
608
553
  * but will expand to if statements and functions when `goto statement` obfuscation is added
609
554
  */
610
-
611
555
  var labelToStates = Object.create(null);
612
556
  var lastLabel;
613
557
  Object.values(chunks).forEach((chunk, i) => {
614
558
  var state = caseStates[i];
615
559
  var stateValues = Array(stateVars.length).fill(0).map((_, i) => lastLabel && (0, _random.chance)(95) // Try to make state changes not as drastic (If last label, re-use some of it's values)
616
560
  ? labelToStates[lastLabel][i] : (0, _random.getRandomInteger)(-500, 500));
617
-
618
561
  const getCurrentState = () => {
619
562
  return stateValues.reduce((a, b) => b + a, 0);
620
563
  };
621
-
622
564
  var correctIndex = (0, _random.getRandomInteger)(0, stateValues.length);
623
565
  stateValues[correctIndex] = state - (getCurrentState() - stateValues[correctIndex]);
624
566
  labelToStates[chunk.label] = stateValues;
625
567
  lastLabel = chunk.label;
626
568
  });
627
569
  var initStateValues = [...labelToStates[startLabel]];
628
- var endState = labelToStates[endLabel].reduce((a, b) => b + a, 0); // Creates a predicate based on the state-variables and control-object properties
570
+ var endState = labelToStates[endLabel].reduce((a, b) => b + a, 0);
629
571
 
572
+ // Creates a predicate based on the state-variables and control-object properties
630
573
  const createPredicate = stateValues => {
631
574
  this.mangledExpressionsMade++;
632
575
  var index = (0, _random.getRandomInteger)(0, stateVars.length);
633
- var compareValue = (0, _random.choice)([stateValues[index], (0, _random.getRandomInteger)(-100, 100)]); // 'state equality' test
576
+ var compareValue = (0, _random.choice)([stateValues[index], (0, _random.getRandomInteger)(-100, 100)]);
634
577
 
578
+ // 'state equality' test
635
579
  var test = (0, _gen.BinaryExpression)("==", (0, _gen.Identifier)(stateVars[index]), createStateBoundNumberLiteral(compareValue, stateValues));
636
- var testValue = stateValues[index] === compareValue; // 'control' equality test
580
+ var testValue = stateValues[index] === compareValue;
637
581
 
582
+ // 'control' equality test
638
583
  if (controlConstantMap.size && (0, _random.chance)(50)) {
639
584
  var _controlConstantMap$g;
640
-
641
585
  // The controlMap maps LITERAL-values to STRING property names
642
586
  var actualValue = (0, _random.choice)(Array.from(controlConstantMap.keys()));
643
587
  var controlKey = (_controlConstantMap$g = controlConstantMap.get(actualValue)) === null || _controlConstantMap$g === void 0 ? void 0 : _controlConstantMap$g.key;
644
- var controlCompareValue = (0, _random.choice)([actualValue, stateValues[index], (0, _random.getRandomInteger)(-100, 100), controlGen.generate()]); // 'control equality' test
588
+ var controlCompareValue = (0, _random.choice)([actualValue, stateValues[index], (0, _random.getRandomInteger)(-100, 100), controlGen.generate()]);
645
589
 
590
+ // 'control equality' test
646
591
  test = (0, _gen.BinaryExpression)("==", getControlMember(controlKey), (0, _gen.Literal)(controlCompareValue));
647
- testValue = actualValue == controlCompareValue; // 'control typeof' test
592
+ testValue = actualValue == controlCompareValue;
648
593
 
594
+ // 'control typeof' test
649
595
  if ((0, _random.chance)(10)) {
650
596
  var compareTypeofValue = (0, _random.choice)(["number", "string", "object", "function", "undefined"]);
651
597
  test = (0, _gen.BinaryExpression)("==", (0, _gen.UnaryExpression)("typeof", getControlMember(controlKey)), (0, _gen.Literal)(compareTypeofValue));
652
598
  testValue = typeof actualValue === compareTypeofValue;
653
- } // 'control hasOwnProperty' test
654
-
599
+ }
655
600
 
601
+ // 'control hasOwnProperty' test
656
602
  if ((0, _random.chance)(10)) {
657
603
  var hasOwnProperty = (0, _random.choice)([controlKey, controlGen.generate()]);
658
604
  test = (0, _gen.CallExpression)((0, _gen.MemberExpression)((0, _gen.Identifier)(controlVar), (0, _gen.Literal)("hasOwnProperty"), true), [(0, _gen.Literal)(hasOwnProperty)]);
659
605
  testValue = hasOwnProperty === controlKey;
660
606
  }
661
607
  }
662
-
663
608
  return {
664
609
  test,
665
610
  testValue
666
611
  };
667
- }; // A "state-less" number literal is a Number Literal that is mangled in with the Control properties.
668
- // Example: X = CONTROL.Y + Z. These can be used anywhere because control properties are constant (unlike state variables)
669
-
612
+ };
670
613
 
614
+ // A "state-less" number literal is a Number Literal that is mangled in with the Control properties.
615
+ // Example: X = CONTROL.Y + Z. These can be used anywhere because control properties are constant (unlike state variables)
671
616
  const createStatelessNumberLiteral = function (num) {
672
617
  var _selectedControlConst2;
673
-
674
618
  let depth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
675
-
676
619
  if (!controlConstantMap.size || depth > 4 || (0, _random.chance)(75 + depth * 5 + _this.mangledExpressionsMade / 25)) {
677
620
  // Add to control constant map?
678
621
  if ((0, _random.chance)(25 - controlConstantMap.size - _this.mangledExpressionsMade / 100)) {
679
622
  return addControlMapConstant(num);
680
623
  }
681
-
682
624
  return (0, _gen.Literal)(num);
683
625
  }
684
-
685
626
  _this.mangledExpressionsMade++;
686
-
687
627
  if (controlConstantMap.has(num)) {
688
628
  var _controlConstantMap$g2;
689
-
690
629
  return getControlMember((_controlConstantMap$g2 = controlConstantMap.get(num)) === null || _controlConstantMap$g2 === void 0 ? void 0 : _controlConstantMap$g2.key);
691
630
  }
692
-
693
631
  var allControlNodes = [object];
694
632
  parents.filter(x => x.$controlVar && x.$controlConstantMap.size > 0).forEach(node => allControlNodes.push(node));
695
633
  var controlNode = (0, _random.choice)(allControlNodes);
@@ -697,7 +635,6 @@ class ControlFlowFlattening extends _transform.default {
697
635
  var selectedControlVar = controlNode.$controlVar;
698
636
  var actualValue = (0, _random.choice)(Array.from(selectedControlConstantMap.keys()));
699
637
  var controlKey = (_selectedControlConst2 = selectedControlConstantMap.get(actualValue)) === null || _selectedControlConst2 === void 0 ? void 0 : _selectedControlConst2.key;
700
-
701
638
  if (typeof actualValue === "number") {
702
639
  var difference = actualValue - num;
703
640
  return (0, _gen.BinaryExpression)("-", getControlMember(controlKey, selectedControlVar), createStatelessNumberLiteral(difference, depth + 1));
@@ -712,31 +649,29 @@ class ControlFlowFlattening extends _transform.default {
712
649
  } else {
713
650
  throw new Error("Unknown: " + typeof actualValue);
714
651
  }
715
- }; // A "state-bound" number literal is a Number Literal that is mangled in with the current state variables
716
- // Example: X = STATE + Y. This can only be used when the state-values are guaranteed to be known.
717
-
652
+ };
718
653
 
654
+ // A "state-bound" number literal is a Number Literal that is mangled in with the current state variables
655
+ // Example: X = STATE + Y. This can only be used when the state-values are guaranteed to be known.
719
656
  const createStateBoundNumberLiteral = function (num, stateValues) {
720
657
  let depth = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
721
- (0, _assert.ok)(Array.isArray(stateValues)); // Base case: After 4 depth, OR random chance
658
+ (0, _assert.ok)(Array.isArray(stateValues));
722
659
 
660
+ // Base case: After 4 depth, OR random chance
723
661
  if (depth > 4 || (0, _random.chance)(75 + depth * 5 + _this.mangledExpressionsMade / 25)) {
724
662
  // Add this number to the control object?
725
663
  // Add to control constant map?
726
664
  if ((0, _random.chance)(25 - controlConstantMap.size)) {
727
665
  return addControlMapConstant(num);
728
666
  }
729
-
730
667
  return (0, _gen.Literal)(num);
731
668
  }
732
-
733
669
  _this.mangledExpressionsMade++;
734
-
735
670
  if ((0, _random.chance)(10)) {
736
671
  return createStatelessNumberLiteral(num, depth + 1);
737
- } // Terminated predicate
738
-
672
+ }
739
673
 
674
+ // Terminated predicate
740
675
  if ((0, _random.chance)(50)) {
741
676
  var {
742
677
  test,
@@ -744,13 +679,13 @@ class ControlFlowFlattening extends _transform.default {
744
679
  } = createPredicate(stateValues);
745
680
  var alternateNode = (0, _random.choice)([(0, _gen.Literal)((0, _random.getRandomInteger)(-100, 100)), (0, _gen.Literal)(controlGen.generate()), getControlMember(controlGen.generate())]);
746
681
  return (0, _gen.ConditionalExpression)(test, testValue ? (0, _gen.Literal)(num) : alternateNode, !testValue ? (0, _gen.Literal)(num) : alternateNode);
747
- } // Recursive predicate
748
-
682
+ }
749
683
 
684
+ // Recursive predicate
750
685
  var opposing = (0, _random.getRandomInteger)(0, stateVars.length);
751
-
752
686
  if ((0, _random.chance)(10)) {
753
687
  // state > compare ? real : fake
688
+
754
689
  var compareValue = (0, _random.choice)([stateValues[opposing], (0, _random.getRandomInteger)(-150, 150)]);
755
690
  var operator = (0, _random.choice)(["<", ">", "==", "!="]);
756
691
  var answer = {
@@ -762,70 +697,63 @@ class ControlFlowFlattening extends _transform.default {
762
697
  var correct = createStateBoundNumberLiteral(num, stateValues, depth + 1);
763
698
  var incorrect = createStateBoundNumberLiteral((0, _random.getRandomInteger)(-150, 150), stateValues, depth + 1);
764
699
  return (0, _gen.ConditionalExpression)((0, _gen.BinaryExpression)(operator, createStateBoundNumberLiteral(compareValue, stateValues, depth + 1), (0, _gen.Identifier)(stateVars[opposing])), answer ? correct : incorrect, answer ? incorrect : correct);
765
- } // state + 10 = <REAL>
766
-
700
+ }
767
701
 
702
+ // state + 10 = <REAL>
768
703
  var difference = num - stateValues[opposing];
769
-
770
704
  if (difference === 0) {
771
705
  return (0, _gen.Identifier)(stateVars[opposing]);
772
706
  }
773
-
774
707
  return (0, _gen.BinaryExpression)("+", (0, _gen.Identifier)(stateVars[opposing]), createStateBoundNumberLiteral(difference, stateValues, depth + 1));
775
708
  };
776
-
777
709
  var outlinesCreated = 0;
778
-
779
710
  const isExpression = (object, parents) => {
780
711
  var fnIndex = parents.findIndex(x => (0, _insert.isFunction)(x));
781
-
782
712
  if (fnIndex != -1) {
783
713
  // This does NOT mutate
784
714
  parents = parents.slice(0, fnIndex);
785
715
  }
716
+ var assignmentIndex = parents.findIndex(x => x.type === "AssignmentExpression");
786
717
 
787
- var assignmentIndex = parents.findIndex(x => x.type === "AssignmentExpression"); // Left-hand assignment validation
788
-
718
+ // Left-hand assignment validation
789
719
  if (assignmentIndex != -1) {
790
720
  if (parents[assignmentIndex].left === (parents[assignmentIndex - 1] || object)) {
791
721
  return false;
792
722
  }
793
- } // For in/of left validation
794
-
723
+ }
795
724
 
725
+ // For in/of left validation
796
726
  var forInOfIndex = parents.findIndex(x => x.type === "ForInStatement" || x.type === "ForOfStatement");
797
-
798
727
  if (forInOfIndex != -1) {
799
728
  if (parents[forInOfIndex].left === (parents[forInOfIndex - 1] || object)) {
800
729
  return false;
801
730
  }
802
- } // Bound call-expression validation
803
-
731
+ }
804
732
 
733
+ // Bound call-expression validation
805
734
  var callExpressionIndex = parents.findIndex(x => x.type === "CallExpression");
806
-
807
735
  if (callExpressionIndex != -1) {
808
736
  if (parents[callExpressionIndex].callee == (parents[callExpressionIndex - 1] || object)) {
809
- var callee = parents[callExpressionIndex].callee; // Detected bound call expression. Not supported.
737
+ var callee = parents[callExpressionIndex].callee;
810
738
 
739
+ // Detected bound call expression. Not supported.
811
740
  if (callee.type === "MemberExpression") {
812
741
  return false;
813
742
  }
814
743
  }
815
- } // Update-expression validation:
816
-
744
+ }
817
745
 
746
+ // Update-expression validation:
818
747
  var updateExpressionIndex = parents.findIndex(x => x.type === "UpdateExpression");
819
748
  if (updateExpressionIndex !== -1) return false;
820
749
  return true;
821
- }; // This function checks if the expression or statements is possible to be outlined
822
-
750
+ };
823
751
 
752
+ // This function checks if the expression or statements is possible to be outlined
824
753
  const canOutline = (object, parents) => {
825
754
  var isIllegal = false;
826
755
  var breakStatements = [];
827
756
  var returnStatements = [];
828
-
829
757
  if (!Array.isArray(object) && !isExpression(object, parents)) {
830
758
  return {
831
759
  isIllegal: true,
@@ -833,13 +761,11 @@ class ControlFlowFlattening extends _transform.default {
833
761
  returnStatements: []
834
762
  };
835
763
  }
836
-
837
764
  (0, _traverse.walk)(object, parents, (o, p) => {
838
765
  if (o.type === "ThisExpression" || o.type === "MetaProperty" || o.type === "Super") {
839
766
  isIllegal = true;
840
767
  return "EXIT";
841
768
  }
842
-
843
769
  if (o.type === "BreakStatement") {
844
770
  // This can be safely outlined
845
771
  if (o.label && o.label.name === switchLabel) {
@@ -849,7 +775,6 @@ class ControlFlowFlattening extends _transform.default {
849
775
  return "EXIT";
850
776
  }
851
777
  }
852
-
853
778
  if ((o.type === "ContinueStatement" || o.type === "AwaitExpression" || o.type === "YieldExpression" || o.type === "ReturnStatement" || o.type === "VariableDeclaration" || o.type === "FunctionDeclaration" || o.type === "ClassDeclaration") && !p.find(x => (0, _insert.isVarContext)(x))) {
854
779
  // This can be safely outlined
855
780
  if (o.type === "ReturnStatement") {
@@ -859,7 +784,6 @@ class ControlFlowFlattening extends _transform.default {
859
784
  return "EXIT";
860
785
  }
861
786
  }
862
-
863
787
  if (o.type === "Identifier") {
864
788
  if (o.name === "arguments") {
865
789
  isIllegal = true;
@@ -873,17 +797,15 @@ class ControlFlowFlattening extends _transform.default {
873
797
  returnStatements
874
798
  };
875
799
  };
876
-
877
800
  const createOutlineFunction = (body, stateValues, label) => {
878
801
  var key = controlGen.generate();
879
802
  var functionExpression = (0, _gen.FunctionExpression)([], body);
880
-
881
803
  if (!this.options.es5 && (0, _random.chance)(50)) {
882
804
  functionExpression.type = "ArrowFunctionExpression";
883
805
  }
806
+ controlProperties.push((0, _gen.Property)((0, _gen.Literal)(key), functionExpression, false));
884
807
 
885
- controlProperties.push((0, _gen.Property)((0, _gen.Literal)(key), functionExpression, false)); // Add dead code to function
886
-
808
+ // Add dead code to function
887
809
  if (!this.isDebug && (0, _random.chance)(25)) {
888
810
  var {
889
811
  test,
@@ -894,16 +816,13 @@ class ControlFlowFlattening extends _transform.default {
894
816
  var alternate = [(0, _gen.ReturnStatement)((0, _random.choice)([(0, _gen.BinaryExpression)("==", (0, _gen.Identifier)((0, _random.choice)(stateVars)), (0, _gen.Literal)((0, _random.getRandomInteger)(-100, 100))), (0, _gen.Literal)(controlGen.generate()), (0, _gen.Identifier)("arguments"), (0, _gen.Identifier)((0, _random.choice)(stateVars)), (0, _gen.Identifier)(controlVar), (0, _gen.CallExpression)(getControlMember(controlGen.generate()), [])]))];
895
817
  functionExpression.body.body.unshift((0, _gen.IfStatement)(testValue ? (0, _gen.UnaryExpression)("!", (0, _gen.Identifier)(deadCodeVar)) : (0, _gen.Identifier)(deadCodeVar), alternate));
896
818
  }
897
-
898
819
  outlinesCreated++;
899
820
  return key;
900
821
  };
901
-
902
822
  const attemptOutlineStatements = (statements, parentBlock, stateValues, label) => {
903
823
  if (this.isDebug || !this.outlineStatements || (0, _random.chance)(75 + outlinesCreated - this.mangledExpressionsMade / 25)) {
904
824
  return;
905
825
  }
906
-
907
826
  var index = parentBlock.indexOf(statements[0]);
908
827
  if (index === -1) return;
909
828
  var outlineInfo = canOutline(statements, parentBlock);
@@ -918,12 +837,12 @@ class ControlFlowFlattening extends _transform.default {
918
837
  let [returnStatement, p] = _ref2;
919
838
  var argument = returnStatement.argument || (0, _gen.Identifier)("undefined");
920
839
  this.replace(returnStatement, (0, _gen.ReturnStatement)((0, _gen.ObjectExpression)([(0, _gen.Property)((0, _gen.Literal)(returnFlag), argument, false)])));
921
- }); // Outline these statements!
840
+ });
922
841
 
842
+ // Outline these statements!
923
843
  var key = createOutlineFunction((0, _insert.clone)(statements), stateValues, label);
924
844
  var callExpression = (0, _gen.CallExpression)(getControlMember(key), []);
925
845
  var newStatements = [];
926
-
927
846
  if (outlineInfo.breakStatements.length === 0 && outlineInfo.returnStatements.length === 0) {
928
847
  newStatements.push((0, _gen.ExpressionStatement)(callExpression));
929
848
  } else if (outlineInfo.returnStatements.length === 0) {
@@ -931,34 +850,29 @@ class ControlFlowFlattening extends _transform.default {
931
850
  } else {
932
851
  var tempVar = this.getPlaceholder();
933
852
  newStatements.push((0, _gen.VariableDeclaration)((0, _gen.VariableDeclarator)(tempVar, callExpression)));
934
-
935
853
  const t = str => (0, _template.default)(str).single().expression;
854
+ newStatements.push((0, _gen.IfStatement)(t(`${tempVar} === "${breakFlag}"`), [(0, _gen.BreakStatement)(switchLabel)], [(0, _gen.IfStatement)(t(`typeof ${tempVar} == "object"`), [(0, _gen.ReturnStatement)(t(`${tempVar}["${returnFlag}"]`))])]));
855
+ }
936
856
 
937
- newStatements.push((0, _gen.IfStatement)(t("".concat(tempVar, " === \"").concat(breakFlag, "\"")), [(0, _gen.BreakStatement)(switchLabel)], [(0, _gen.IfStatement)(t("typeof ".concat(tempVar, " == \"object\"")), [(0, _gen.ReturnStatement)(t("".concat(tempVar, "[\"").concat(returnFlag, "\"]")))])]));
938
- } // Remove the original statements from the block and replace it with the call expression
939
-
940
-
857
+ // Remove the original statements from the block and replace it with the call expression
941
858
  parentBlock.splice(index, statements.length, ...newStatements);
942
859
  };
943
-
944
860
  const attemptOutlineExpression = (expression, expressionParents, stateValues, label) => {
945
861
  if (this.isDebug || !this.outlineExpressions || (0, _random.chance)(75 + outlinesCreated - this.mangledExpressionsMade / 25)) {
946
862
  return;
947
863
  }
948
-
949
864
  var outlineInfo = canOutline(expression, expressionParents);
950
- if (outlineInfo.isIllegal || outlineInfo.breakStatements.length || outlineInfo.returnStatements.length) return; // Outline this expression!
865
+ if (outlineInfo.isIllegal || outlineInfo.breakStatements.length || outlineInfo.returnStatements.length) return;
951
866
 
867
+ // Outline this expression!
952
868
  var key = createOutlineFunction([(0, _gen.ReturnStatement)((0, _insert.clone)(expression))], stateValues, label);
953
869
  var callExpression = (0, _gen.CallExpression)(getControlMember(key), []);
954
870
  this.replaceIdentifierOrLiteral(expression, callExpression, expressionParents);
955
871
  };
956
-
957
872
  const createTransitionExpression = (index, add, mutatingStateValues, label) => {
958
873
  var beforeStateValues = [...mutatingStateValues];
959
874
  var newValue = mutatingStateValues[index] + add;
960
875
  var expr = null;
961
-
962
876
  if (this.isDebug) {
963
877
  // state = NEW_STATE
964
878
  expr = (0, _gen.AssignmentExpression)("=", (0, _gen.Identifier)(stateVars[index]), (0, _gen.Literal)(newValue));
@@ -974,23 +888,20 @@ class ControlFlowFlattening extends _transform.default {
974
888
  mutatingStateValues[index] = double;
975
889
  expr = (0, _gen.SequenceExpression)([first, (0, _gen.AssignmentExpression)("-=", (0, _gen.Identifier)(stateVars[index]), createStateBoundNumberLiteral(diff, mutatingStateValues))]);
976
890
  }
891
+ mutatingStateValues[index] = newValue;
977
892
 
978
- mutatingStateValues[index] = newValue; // These are lower quality outlines vs. the entire transition outline
979
-
893
+ // These are lower quality outlines vs. the entire transition outline
980
894
  if ((0, _random.chance)(50)) {
981
895
  attemptOutlineExpression(expr, [], [...beforeStateValues], label);
982
896
  }
983
-
984
897
  return expr;
985
898
  };
986
-
987
899
  var cases = [];
988
900
  chunks.forEach((chunk, i) => {
989
901
  // skip last case, its empty and never ran
990
902
  if (chunk.label === endLabel) {
991
903
  return;
992
904
  }
993
-
994
905
  (0, _assert.ok)(labelToStates[chunk.label]);
995
906
  var state = caseStates[i];
996
907
  var staticStateValues = [...labelToStates[chunk.label]];
@@ -1000,95 +911,98 @@ class ControlFlowFlattening extends _transform.default {
1000
911
  // This mangles certain literals with the state variables
1001
912
  // Ex: A number literal (50) changed to a expression (stateVar + 40), when stateVar = 10
1002
913
  if (!this.isDebug && o.type === "Literal" && !p.find(x => (0, _insert.isVarContext)(x))) {
1003
- if (typeof o.value === "number" && Math.floor(o.value) === o.value && // Only whole numbers
1004
- Math.abs(o.value) < 100000 && // Hard-coded limit
914
+ if (typeof o.value === "number" && Math.floor(o.value) === o.value &&
915
+ // Only whole numbers
916
+ Math.abs(o.value) < 100_000 &&
917
+ // Hard-coded limit
1005
918
  this.mangleNumberLiterals && (0, _random.chance)(50 - this.mangledExpressionsMade / 100)) {
1006
919
  // 50 -> state1 - 10, when state1 = 60. The result is still 50
920
+
1007
921
  return () => {
1008
922
  this.replaceIdentifierOrLiteral(o, createStateBoundNumberLiteral(o.value, staticStateValues), p);
1009
923
  };
1010
924
  }
1011
-
1012
925
  if (typeof o.value === "boolean" && this.mangleBooleanLiterals && (0, _random.chance)(50 - this.mangledExpressionsMade / 100)) {
1013
926
  // true -> state1 == 10, when state1 = 10. The result is still true
927
+
1014
928
  // Choose a random state var to compare again
1015
929
  var index = (0, _random.getRandomInteger)(0, stateVars.length);
1016
- var compareValue = staticStateValues[index]; // When false, always choose a different number, so the expression always equals false
930
+ var compareValue = staticStateValues[index];
1017
931
 
932
+ // When false, always choose a different number, so the expression always equals false
1018
933
  while (!o.value && compareValue === staticStateValues[index]) {
1019
934
  compareValue = (0, _random.getRandomInteger)(-150, 150);
1020
935
  }
1021
-
1022
936
  var mangledExpression = (0, _gen.BinaryExpression)("==", (0, _gen.Identifier)(stateVars[index]), createStateBoundNumberLiteral(compareValue, staticStateValues));
1023
937
  return () => {
1024
938
  this.replaceIdentifierOrLiteral(o, mangledExpression, p);
1025
939
  attemptOutlineExpression(o, p, staticStateValues, chunk.label);
1026
940
  };
1027
941
  }
1028
- } // Mangle certain referenced identifiers
1029
- // console.log("hi") -> (x ? console : window).log("hi"), when is x true. The result is the same
1030
-
942
+ }
1031
943
 
1032
- if (!this.isDebug && o.type === "Identifier" && this.mangleIdentifiers && (0, _random.chance)(50 - this.mangledExpressionsMade / 100) && !p.find(x => (0, _insert.isVarContext)(x))) {
944
+ // Mangle certain referenced identifiers
945
+ // console.log("hi") -> (x ? console : window).log("hi"), when is x true. The result is the same
946
+ if (!this.isDebug && o.type === "Identifier" && this.mangleIdentifiers && !_constants.reservedIdentifiers.has(o.name) && (0, _random.chance)(50 - this.mangledExpressionsMade / 100) && !p.find(x => (0, _insert.isVarContext)(x))) {
1033
947
  // ONLY referenced identifiers (like actual variable names) can be changed
1034
948
  var info = (0, _identifiers.getIdentifierInfo)(o, p);
1035
-
1036
949
  if (!info.spec.isReferenced || info.spec.isDefined || info.spec.isModified || info.spec.isExported) {
1037
950
  return;
1038
- } // TYPEOF expression check
1039
-
951
+ }
1040
952
 
953
+ // TYPEOF expression check
1041
954
  if (p[0] && p[0].type === "UnaryExpression" && p[0].operator === "typeof" && p[0].argument === o) {
1042
955
  return;
1043
- } // Update expression check
1044
-
956
+ }
1045
957
 
958
+ // Update expression check
1046
959
  if (p[0] && p[0].type === "UpdateExpression") {
1047
960
  return;
1048
- } // FOR-in/of initializer check
1049
-
961
+ }
1050
962
 
963
+ // FOR-in/of initializer check
1051
964
  if ((0, _insert.isForInitialize)(o, p) === "left-hand") {
1052
965
  return;
1053
966
  }
1054
-
1055
967
  var {
1056
968
  test,
1057
969
  testValue
1058
- } = createPredicate(staticStateValues); // test && real
970
+ } = createPredicate(staticStateValues);
1059
971
 
1060
- var mangledExpression = (0, _gen.LogicalExpression)(testValue ? "&&" : "||", test, (0, _gen.Identifier)(o.name)); // control.fake = real
972
+ // test && real
973
+ var mangledExpression = (0, _gen.LogicalExpression)(testValue ? "&&" : "||", test, (0, _gen.Identifier)(o.name));
1061
974
 
975
+ // control.fake = real
1062
976
  if ((0, _random.chance)(50)) {
1063
977
  mangledExpression = (0, _gen.AssignmentExpression)("=", getControlMember(controlGen.generate()), (0, _gen.Identifier)(o.name));
1064
- } // test ? real : fake
1065
-
978
+ }
1066
979
 
980
+ // test ? real : fake
1067
981
  if ((0, _random.chance)(50)) {
1068
- var alternateName = (0, _random.choice)([controlVar, ...stateVars, ...this.options.globalVariables, ..._constants.reservedIdentifiers]); // Don't use 'arguments'
982
+ var alternateName = (0, _random.choice)([controlVar, ...stateVars, ...this.options.globalVariables, ..._constants.reservedIdentifiers]);
1069
983
 
984
+ // Don't use 'arguments'
1070
985
  if (alternateName === "arguments") alternateName = "undefined";
1071
986
  mangledExpression = (0, _gen.ConditionalExpression)(test, (0, _gen.Identifier)(testValue ? o.name : alternateName), (0, _gen.Identifier)(!testValue ? o.name : alternateName));
1072
987
  }
1073
-
1074
988
  return () => {
1075
989
  this.replaceIdentifierOrLiteral(o, mangledExpression, p);
1076
990
  };
1077
- } // Function outlining: bring out certain expressions
1078
-
991
+ }
1079
992
 
1080
- if (!this.isDebug && o.type && ["BinaryExpression", "LogicalExpression", "CallExpression", "AssignmentExpression", "MemberExpression", "ObjectExpression", "ConditionalExpression"].includes(o.type) && !(0, _random.chance)(p.length * 5) && // The further down the tree the lower quality of expression
993
+ // Function outlining: bring out certain expressions
994
+ if (!this.isDebug && o.type && ["BinaryExpression", "LogicalExpression", "CallExpression", "AssignmentExpression", "MemberExpression", "ObjectExpression", "ConditionalExpression"].includes(o.type) && !(0, _random.chance)(p.length * 5) &&
995
+ // The further down the tree the lower quality of expression
1081
996
  !p.find(x => (0, _insert.isContext)(x) || x.$outlining)) {
1082
997
  o.$outlining = true;
1083
998
  return () => {
1084
999
  attemptOutlineExpression(o, p, staticStateValues, chunk.label);
1085
1000
  };
1086
- } // Opaque predicates: If Statements, Conditional Statements, Switch Case test
1087
-
1001
+ }
1088
1002
 
1003
+ // Opaque predicates: If Statements, Conditional Statements, Switch Case test
1089
1004
  if (!this.isDebug && this.addOpaquePredicates && p[0] && (0, _random.chance)(50 - outlinesCreated - this.mangledExpressionsMade / 100)) {
1090
1005
  var isTestExpression = p[0].type == "IfStatement" && p[0].test === o || p[0].type === "ConditionalExpression" && p[0].test === o || p[0].type === "SwitchCase" && p[0].test === o;
1091
-
1092
1006
  if (isTestExpression && !p.find(x => (0, _insert.isContext)(x))) {
1093
1007
  return () => {
1094
1008
  var {
@@ -1099,27 +1013,24 @@ class ControlFlowFlattening extends _transform.default {
1099
1013
  };
1100
1014
  }
1101
1015
  }
1102
-
1103
1016
  if (o.type == "StateIdentifier") {
1104
1017
  return () => {
1105
1018
  (0, _assert.ok)(labelToStates[o.label]);
1106
1019
  this.replace(o, (0, _gen.ArrayExpression)(labelToStates[o.label].map(_gen.Literal)));
1107
1020
  };
1108
1021
  }
1109
-
1110
1022
  if (o.type == "GotoStatement") {
1111
1023
  return () => {
1112
1024
  var blockIndex = p.findIndex(node => (0, _traverse.isBlock)(node) || node.type === "SwitchCase");
1113
-
1114
1025
  if (blockIndex === -1) {
1115
1026
  var index = chunk.body.indexOf(stmt);
1116
- (0, _assert.ok)(index != -1); // Top level: Insert break statement in the chunk body
1117
- // This is OKAY because this forEach uses a cloned version of the body `[...chunk.body]`
1027
+ (0, _assert.ok)(index != -1);
1118
1028
 
1029
+ // Top level: Insert break statement in the chunk body
1030
+ // This is OKAY because this forEach uses a cloned version of the body `[...chunk.body]`
1119
1031
  chunk.body.splice(index + 1, 0, (0, _gen.BreakStatement)(switchLabel));
1120
1032
  } else {
1121
1033
  var block = p[blockIndex];
1122
-
1123
1034
  if (block.type === "SwitchCase") {
1124
1035
  // Handle switch case break placement (Important!)
1125
1036
  block.consequent.splice(block.consequent.indexOf(p[blockIndex - 2] || o) + 1, 0, (0, _gen.BreakStatement)(switchLabel));
@@ -1130,28 +1041,26 @@ class ControlFlowFlattening extends _transform.default {
1130
1041
  block.body.splice(childIndex + 1, 0, (0, _gen.BreakStatement)(switchLabel));
1131
1042
  }
1132
1043
  }
1133
-
1134
1044
  if (!o.impossible) {
1135
1045
  potentialBranches.add(o.label);
1136
1046
  }
1137
-
1138
1047
  var mutatingStateValues = [...labelToStates[chunk.label]];
1139
1048
  var nextStateValues = labelToStates[o.label];
1140
1049
  (0, _assert.ok)(nextStateValues, o.label);
1141
1050
  var transitionExpressions = [];
1142
-
1143
1051
  for (var stateValueIndex = 0; stateValueIndex < stateVars.length; stateValueIndex++) {
1144
- var diff = nextStateValues[stateValueIndex] - mutatingStateValues[stateValueIndex]; // Only add if state value changed
1145
- // If pointing to itself then always add to ensure SequenceExpression isn't empty
1052
+ var diff = nextStateValues[stateValueIndex] - mutatingStateValues[stateValueIndex];
1146
1053
 
1054
+ // Only add if state value changed
1055
+ // If pointing to itself then always add to ensure SequenceExpression isn't empty
1147
1056
  if (diff !== 0 || o.label === chunk.label) {
1148
1057
  transitionExpressions.push(createTransitionExpression(stateValueIndex, diff, mutatingStateValues, chunk.label));
1149
1058
  }
1150
1059
  }
1151
-
1152
1060
  (0, _assert.ok)(transitionExpressions.length !== 0);
1153
- var sequenceExpression = (0, _gen.SequenceExpression)(transitionExpressions); // Check if flagged and additional code here
1061
+ var sequenceExpression = (0, _gen.SequenceExpression)(transitionExpressions);
1154
1062
 
1063
+ // Check if flagged and additional code here
1155
1064
  if (typeof flaggedLabels[o.label] === "object") {
1156
1065
  var {
1157
1066
  flagKey,
@@ -1159,7 +1068,6 @@ class ControlFlowFlattening extends _transform.default {
1159
1068
  } = flaggedLabels[o.label];
1160
1069
  sequenceExpression.expressions.push((0, _gen.AssignmentExpression)("=", getControlMember(flagKey), (0, _gen.Literal)(flagValue)));
1161
1070
  }
1162
-
1163
1071
  attemptOutlineExpression(sequenceExpression, [], staticStateValues, chunk.label);
1164
1072
  this.replace(o, (0, _gen.ExpressionStatement)(sequenceExpression));
1165
1073
  };
@@ -1167,14 +1075,13 @@ class ControlFlowFlattening extends _transform.default {
1167
1075
  });
1168
1076
  });
1169
1077
  attemptOutlineStatements(chunk.body, chunk.body, staticStateValues, chunk.label);
1170
-
1171
- if (!chunk.impossible) {// FUTURE OBFUSCATION IDEA: Update controlObject based on 'potentialBranches' code
1078
+ if (!chunk.impossible) {
1079
+ // FUTURE OBFUSCATION IDEA: Update controlObject based on 'potentialBranches' code
1172
1080
  // This idea would require a lot of work but would make some seriously effective obfuscation
1173
1081
  // for protecting the data. In 'inactive' states the data could be overwritten to fake values
1174
1082
  // And in the 'active' state the data would brought back just in time. This would require the controlObject
1175
1083
  // state to be known in all chunks
1176
1084
  }
1177
-
1178
1085
  var caseObject = {
1179
1086
  body: chunk.body,
1180
1087
  state: state,
@@ -1182,84 +1089,77 @@ class ControlFlowFlattening extends _transform.default {
1182
1089
  };
1183
1090
  cases.push(caseObject);
1184
1091
  });
1185
-
1186
1092
  if (!this.isDebug && this.addDeadCode) {
1187
1093
  // Add fake control object updates
1188
1094
  chunks.forEach(chunk => {
1189
1095
  if ((0, _random.chance)(10)) {
1190
1096
  // These deadCode variants can NOT break the state/control variables
1191
1097
  // They are executed!
1192
- var deadCodeChoices = [(0, _gen.ExpressionStatement)((0, _gen.AssignmentExpression)("=", getControlMember(controlGen.generate()), (0, _gen.Literal)(controlGen.generate()))), (0, _gen.ExpressionStatement)((0, _gen.UnaryExpression)("delete", getControlMember(controlGen.generate())))]; // These deadCode variants can make breaking changes
1193
- // because they are never ran
1098
+ var deadCodeChoices = [(0, _gen.ExpressionStatement)((0, _gen.AssignmentExpression)("=", getControlMember(controlGen.generate()), (0, _gen.Literal)(controlGen.generate()))), (0, _gen.ExpressionStatement)((0, _gen.UnaryExpression)("delete", getControlMember(controlGen.generate())))];
1194
1099
 
1100
+ // These deadCode variants can make breaking changes
1101
+ // because they are never ran
1195
1102
  if (chunk.impossible) {
1196
1103
  var randomControlKey = (0, _random.choice)(controlProperties.map(prop => {
1197
1104
  var _prop$key;
1198
-
1199
1105
  return (_prop$key = prop.key) === null || _prop$key === void 0 ? void 0 : _prop$key.value;
1200
1106
  }).filter(x => x && typeof x === "string")) || controlGen.generate();
1201
1107
  deadCodeChoices = deadCodeChoices.concat([(0, _gen.ExpressionStatement)((0, _gen.AssignmentExpression)("=", (0, _gen.Identifier)(controlVar), (0, _gen.Literal)(false))), (0, _gen.ExpressionStatement)((0, _gen.AssignmentExpression)("=", (0, _gen.Identifier)(controlVar), (0, _gen.Identifier)("undefined"))), (0, _gen.ExpressionStatement)((0, _gen.AssignmentExpression)("=", getControlMember(randomControlKey), (0, _gen.Identifier)("undefined"))), (0, _gen.ExpressionStatement)((0, _gen.UnaryExpression)("delete", getControlMember(randomControlKey)))]);
1202
1108
  }
1203
-
1204
1109
  chunk.body.unshift((0, _random.choice)(deadCodeChoices));
1205
1110
  }
1206
1111
  });
1207
1112
  }
1208
-
1209
1113
  if (!this.isDebug) {
1210
1114
  (0, _random.shuffle)(cases);
1211
1115
  (0, _random.shuffle)(controlProperties);
1212
1116
  }
1213
-
1214
- var discriminant = (0, _template.default)("".concat(stateVars.join("+"))).single().expression;
1215
- objectBody.length = 0; // Perverse position of import declarations
1216
-
1117
+ var discriminant = (0, _template.default)(`${stateVars.join("+")}`).single().expression;
1118
+ objectBody.length = 0;
1119
+ // Perverse position of import declarations
1217
1120
  for (var importDeclaration of importDeclarations) {
1218
1121
  objectBody.push(importDeclaration);
1219
- } // As well as functions are brought up
1220
-
1122
+ }
1221
1123
 
1124
+ // As well as functions are brought up
1222
1125
  for (var functionName of functionDeclarationNames) {
1223
1126
  objectBody.push((0, _gen.VariableDeclaration)((0, _gen.VariableDeclarator)(functionName, functionDeclarationValues.get(functionName))));
1224
1127
  }
1225
-
1226
1128
  var defaultCaseIndex = (0, _random.getRandomInteger)(0, cases.length);
1227
1129
  var switchCases = [];
1228
1130
  cases.forEach((caseObject, i) => {
1229
1131
  var _caseObject$body$0$la;
1230
-
1231
1132
  // Empty case OR single break statement is skipped
1232
1133
  if (caseObject.body.length === 0 || caseObject.body.length === 1 && caseObject.body[0].type === "BreakStatement" && ((_caseObject$body$0$la = caseObject.body[0].label) === null || _caseObject$body$0$la === void 0 ? void 0 : _caseObject$body$0$la.name) === switchLabel) return;
1233
1134
  var test = (0, _gen.Literal)(caseObject.state);
1234
- var isEligibleForOutlining = false; // Check if Control Map has this value
1135
+ var isEligibleForOutlining = false;
1235
1136
 
1137
+ // Check if Control Map has this value
1236
1138
  if (!this.isDebug && controlConstantMap.has(caseObject.state)) {
1237
1139
  var _controlConstantMap$g3;
1238
-
1239
1140
  test = getControlMember((_controlConstantMap$g3 = controlConstantMap.get(caseObject.state)) === null || _controlConstantMap$g3 === void 0 ? void 0 : _controlConstantMap$g3.key);
1240
- } // Create complex test expressions for each switch case
1241
-
1141
+ }
1242
1142
 
1143
+ // Create complex test expressions for each switch case
1243
1144
  if (!this.isDebug && this.addComplexTest && (0, _random.chance)(25)) {
1244
- isEligibleForOutlining = true; // case STATE+X:
1145
+ isEligibleForOutlining = true;
1245
1146
 
1147
+ // case STATE+X:
1246
1148
  var stateVarIndex = (0, _random.getRandomInteger)(0, stateVars.length);
1247
1149
  var stateValues = labelToStates[caseObject.label];
1248
1150
  var difference = stateValues[stateVarIndex] - caseObject.state;
1249
1151
  var conditionNodes = [];
1250
- var alreadyConditionedItems = new Set(); // This code finds clash conditions and adds them to 'conditionNodes' array
1152
+ var alreadyConditionedItems = new Set();
1251
1153
 
1154
+ // This code finds clash conditions and adds them to 'conditionNodes' array
1252
1155
  Object.keys(labelToStates).forEach(label => {
1253
1156
  if (label !== caseObject.label) {
1254
1157
  var labelStates = labelToStates[label];
1255
1158
  var totalState = labelStates.reduce((a, b) => a + b, 0);
1256
-
1257
1159
  if (totalState === labelStates[stateVarIndex] - difference) {
1258
1160
  var differentIndex = labelStates.findIndex((v, i) => v !== stateValues[i]);
1259
-
1260
1161
  if (differentIndex !== -1) {
1261
1162
  var expressionAsString = stateVars[differentIndex] + "!=" + labelStates[differentIndex];
1262
-
1263
1163
  if (!alreadyConditionedItems.has(expressionAsString)) {
1264
1164
  alreadyConditionedItems.add(expressionAsString);
1265
1165
  conditionNodes.push((0, _gen.BinaryExpression)("!=", (0, _gen.Identifier)(stateVars[differentIndex]), (0, _gen.Literal)(labelStates[differentIndex])));
@@ -1269,16 +1169,18 @@ class ControlFlowFlattening extends _transform.default {
1269
1169
  }
1270
1170
  }
1271
1171
  }
1272
- }); // case STATE!=Y && STATE+X
1172
+ });
1273
1173
 
1274
- test = (0, _gen.BinaryExpression)("-", (0, _gen.Identifier)(stateVars[stateVarIndex]), (0, _gen.Literal)(difference)); // Use the 'conditionNodes' to not cause state clashing issues
1174
+ // case STATE!=Y && STATE+X
1175
+ test = (0, _gen.BinaryExpression)("-", (0, _gen.Identifier)(stateVars[stateVarIndex]), (0, _gen.Literal)(difference));
1275
1176
 
1177
+ // Use the 'conditionNodes' to not cause state clashing issues
1276
1178
  conditionNodes.forEach(conditionNode => {
1277
1179
  test = (0, _gen.LogicalExpression)("&&", conditionNode, test);
1278
1180
  });
1279
- } // A 'flagged' label has addition 'flagKey' that gets switched before jumped to
1280
-
1181
+ }
1281
1182
 
1183
+ // A 'flagged' label has addition 'flagKey' that gets switched before jumped to
1282
1184
  if (flaggedLabels[caseObject.label]) {
1283
1185
  isEligibleForOutlining = true;
1284
1186
  var {
@@ -1286,93 +1188,94 @@ class ControlFlowFlattening extends _transform.default {
1286
1188
  flagValue
1287
1189
  } = flaggedLabels[caseObject.label];
1288
1190
  var alternateNum;
1289
-
1290
1191
  do {
1291
1192
  alternateNum = (0, _random.getRandomInteger)(-1000, 1000 + chunks.length);
1292
1193
  } while (caseSelection.has(alternateNum));
1194
+ var alternate = (0, _gen.Literal)(alternateNum);
1293
1195
 
1294
- var alternate = (0, _gen.Literal)(alternateNum); // case FLAG ? <REAL> : <FAKE>:
1295
-
1196
+ // case FLAG ? <REAL> : <FAKE>:
1296
1197
  test = (0, _gen.ConditionalExpression)(getControlMember(flagKey), flagValue ? test : alternate, !flagValue ? test : alternate);
1297
- } // Outline this switch case test
1298
-
1198
+ }
1299
1199
 
1200
+ // Outline this switch case test
1300
1201
  if (!this.isDebug && this.outlineExpressions && isEligibleForOutlining && (0, _random.chance)(75 - outlinesCreated - this.mangledExpressionsMade / 25)) {
1301
- this.mangledExpressionsMade++; // Selected a random parent node (or this node) to insert this function in
1202
+ this.mangledExpressionsMade++;
1302
1203
 
1204
+ // Selected a random parent node (or this node) to insert this function in
1303
1205
  var selectedControlNode = (0, _random.choice)(allControlNodes);
1304
1206
  var selectedControlProperties = selectedControlNode.$controlProperties;
1305
1207
  var selectedControlVar = selectedControlNode.$controlVar;
1306
1208
  var selectedControlGen = selectedControlNode.$controlGen;
1307
- var fnKey = selectedControlGen.generate(); // Pass in the:
1209
+ var fnKey = selectedControlGen.generate();
1210
+
1211
+ // Pass in the:
1308
1212
  // - controlVar for 'flagged labels' code check
1309
1213
  // - stateVars for 'complex test expressions'
1310
1214
  // (Check which identifiers are actually needed)
1311
-
1312
1215
  var argumentList = [],
1313
- watchingFor = new Set([controlVar, ...stateVars]);
1216
+ watchingFor = new Set([controlVar, ...stateVars]);
1314
1217
  (0, _traverse.walk)(test, [], (o, p) => {
1315
1218
  if (o.type === "Identifier" && watchingFor.has(o.name)) {
1316
1219
  watchingFor.delete(o.name);
1317
1220
  argumentList.push((0, _gen.Identifier)(o.name));
1318
1221
  }
1319
1222
  });
1320
- selectedControlProperties.push((0, _gen.Property)((0, _gen.Literal)(fnKey), (0, _gen.FunctionExpression)(argumentList, [(0, _gen.ReturnStatement)(test)]), true)); // case control.a(control, s1, s2):
1223
+ selectedControlProperties.push((0, _gen.Property)((0, _gen.Literal)(fnKey), (0, _gen.FunctionExpression)(argumentList, [(0, _gen.ReturnStatement)(test)]), true));
1321
1224
 
1225
+ // case control.a(control, s1, s2):
1322
1226
  test = (0, _gen.CallExpression)(getControlMember(fnKey, selectedControlVar), (0, _insert.clone)(argumentList));
1323
- } // One random case gets to be default
1324
-
1227
+ }
1325
1228
 
1229
+ // One random case gets to be default
1326
1230
  if (!this.isDebug && i === defaultCaseIndex) test = null;
1327
1231
  var testArray = [test];
1328
-
1329
1232
  if (!this.isDebug && this.addFakeTest && (0, _random.chance)(50)) {
1330
1233
  // Add fake test
1331
1234
  // case <FAKE>:
1332
1235
  // case <REAL>:
1333
1236
  // case <FAKE>:
1334
1237
  var fakeTestCount = (0, _random.getRandomInteger)(1, 4);
1335
-
1336
1238
  for (var i = 0; i < fakeTestCount; i++) {
1337
1239
  // Create a fake test number that doesn't interfere with the actual states
1338
1240
  var fakeTestNum;
1339
-
1340
1241
  do {
1341
1242
  fakeTestNum = (0, _random.getRandomInteger)(1, 1000 + caseSelection.size);
1342
- } while (caseSelection.has(fakeTestNum)); // Add this fake test
1343
-
1243
+ } while (caseSelection.has(fakeTestNum));
1344
1244
 
1245
+ // Add this fake test
1345
1246
  testArray.push((0, _gen.Literal)(fakeTestNum));
1346
1247
  }
1347
-
1348
1248
  (0, _random.shuffle)(testArray);
1349
1249
  }
1350
-
1351
1250
  testArray.forEach((test, i) => {
1352
1251
  var body = i === testArray.length - 1 ? caseObject.body : [];
1353
1252
  switchCases.push((0, _gen.SwitchCase)(test, body));
1354
1253
  });
1355
- }); // switch(state) { case ... }
1254
+ });
1356
1255
 
1256
+ // switch(state) { case ... }
1357
1257
  var switchStatement = (0, _gen.SwitchStatement)(discriminant, switchCases);
1358
- var declarations = []; // var state = START_STATE
1258
+ var declarations = [];
1359
1259
 
1260
+ // var state = START_STATE
1360
1261
  declarations.push(...stateVars.map((stateVar, i) => {
1361
1262
  return (0, _gen.VariableDeclarator)(stateVar, (0, _gen.Literal)(initStateValues[i]));
1362
- })); // var control = { strings, numbers, outlined functions, etc... }
1263
+ }));
1363
1264
 
1265
+ // var control = { strings, numbers, outlined functions, etc... }
1364
1266
  var objectExpression = (0, _gen.ObjectExpression)(controlProperties);
1365
1267
  declarations.push((0, _gen.VariableDeclarator)(controlVar, objectExpression));
1366
- objectBody.push( // Use individual variable declarations instead so Stack can apply
1367
- ...declarations.map(declaration => (0, _gen.VariableDeclaration)(declaration, "var"))); // while (state != END_STATE) {...}
1268
+ objectBody.push(
1269
+ // Use individual variable declarations instead so Stack can apply
1270
+ ...declarations.map(declaration => (0, _gen.VariableDeclaration)(declaration, "var")));
1368
1271
 
1272
+ // while (state != END_STATE) {...}
1369
1273
  var whileTest = (0, _gen.BinaryExpression)("!=", (0, _insert.clone)(discriminant), (0, _gen.Literal)(endState));
1370
- objectBody.push((0, _gen.WhileStatement)(whileTest, [(0, _gen.LabeledStatement)(switchLabel, switchStatement)])); // mark this object for switch case obfuscation
1274
+ objectBody.push((0, _gen.WhileStatement)(whileTest, [(0, _gen.LabeledStatement)(switchLabel, switchStatement)]));
1371
1275
 
1276
+ // mark this object for switch case obfuscation
1372
1277
  switchStatement.$controlFlowFlattening = true;
1373
1278
  };
1374
1279
  }
1375
-
1376
1280
  }
1377
-
1378
1281
  exports.default = ControlFlowFlattening;