js-confuser 1.7.3 → 2.0.0-alpha.0

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