js-confuser 1.7.1 → 1.7.3

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