js-confuser 1.2.2 → 1.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/CHANGELOG.md +132 -0
  2. package/README.md +4 -1
  3. package/dist/parser.js +1 -2
  4. package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +482 -91
  5. package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +4 -0
  6. package/dist/transforms/controlFlowFlattening/{switchCaseObfucation.js → switchCaseObfuscation.js} +2 -2
  7. package/dist/transforms/deadCode.js +1 -1
  8. package/dist/transforms/dispatcher.js +7 -6
  9. package/dist/transforms/eval.js +1 -1
  10. package/dist/transforms/extraction/duplicateLiteralsRemoval.js +4 -2
  11. package/dist/transforms/hideInitializingCode.js +4 -1
  12. package/dist/transforms/identifier/globalConcealing.js +18 -8
  13. package/dist/transforms/identifier/variableAnalysis.js +1 -1
  14. package/dist/transforms/label.js +11 -2
  15. package/dist/transforms/lock/antiDebug.js +32 -13
  16. package/dist/transforms/lock/lock.js +3 -3
  17. package/dist/transforms/minify.js +2 -2
  18. package/dist/transforms/opaquePredicates.js +4 -2
  19. package/dist/transforms/preparation/preparation.js +8 -0
  20. package/dist/transforms/renameLabels.js +17 -3
  21. package/dist/transforms/rgf.js +8 -3
  22. package/dist/transforms/stack.js +1 -1
  23. package/dist/transforms/string/encoding.js +74 -0
  24. package/dist/transforms/string/stringCompression.js +6 -2
  25. package/dist/transforms/string/stringConcealing.js +1 -1
  26. package/dist/transforms/string/stringSplitting.js +6 -0
  27. package/dist/traverse.js +0 -34
  28. package/dist/util/gen.js +3 -1
  29. package/dist/util/identifiers.js +8 -18
  30. package/dist/util/insert.js +4 -38
  31. package/package.json +2 -2
  32. package/src/options.ts +3 -3
  33. package/src/parser.ts +1 -2
  34. package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +735 -134
  35. package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +6 -0
  36. package/src/transforms/controlFlowFlattening/{switchCaseObfucation.ts → switchCaseObfuscation.ts} +6 -2
  37. package/src/transforms/deadCode.ts +8 -0
  38. package/src/transforms/dispatcher.ts +16 -6
  39. package/src/transforms/eval.ts +2 -1
  40. package/src/transforms/extraction/duplicateLiteralsRemoval.ts +40 -5
  41. package/src/transforms/hideInitializingCode.ts +432 -425
  42. package/src/transforms/identifier/globalConcealing.ts +102 -38
  43. package/src/transforms/identifier/variableAnalysis.ts +1 -1
  44. package/src/transforms/label.ts +20 -2
  45. package/src/transforms/lock/antiDebug.ts +69 -33
  46. package/src/transforms/lock/lock.ts +4 -5
  47. package/src/transforms/minify.ts +2 -1
  48. package/src/transforms/opaquePredicates.ts +25 -3
  49. package/src/transforms/preparation/preparation.ts +8 -1
  50. package/src/transforms/renameLabels.ts +26 -3
  51. package/src/transforms/rgf.ts +6 -1
  52. package/src/transforms/stack.ts +2 -1
  53. package/src/transforms/string/encoding.ts +107 -1
  54. package/src/transforms/string/stringCompression.ts +28 -3
  55. package/src/transforms/string/stringConcealing.ts +2 -0
  56. package/src/transforms/string/stringSplitting.ts +11 -0
  57. package/src/transforms/transform.ts +1 -2
  58. package/src/traverse.ts +0 -30
  59. package/src/util/gen.ts +5 -3
  60. package/src/util/identifiers.ts +18 -19
  61. package/src/util/insert.ts +10 -76
  62. package/src/util/scope.ts +9 -9
  63. package/test/{transforms/compare.test.ts → compare.test.ts} +2 -2
  64. package/test/index.test.ts +109 -1
  65. package/test/templates/template.test.ts +14 -0
  66. package/test/transforms/controlFlowFlattening/controlFlowFlattening.test.ts +392 -10
  67. package/test/transforms/dispatcher.test.ts +30 -0
  68. package/test/transforms/eval.test.ts +28 -0
  69. package/test/transforms/flatten.test.ts +28 -0
  70. package/test/transforms/hideInitializingCode.test.ts +336 -336
  71. package/test/transforms/identifier/renameVariables.test.ts +31 -0
  72. package/test/transforms/lock/antiDebug.test.ts +43 -0
  73. package/test/transforms/renameLabels.test.ts +33 -0
  74. package/test/transforms/rgf.test.ts +29 -0
  75. package/test/transforms/string/stringSplitting.test.ts +33 -0
  76. package/test/util/identifiers.test.ts +105 -17
  77. package/dist/util/expr.js +0 -60
  78. package/src/util/expr.ts +0 -56
@@ -1,425 +1,432 @@
1
- import { reservedIdentifiers } from "../constants";
2
- import { ObfuscateOrder } from "../order";
3
- import { walk } from "../traverse";
4
- import {
5
- AssignmentExpression,
6
- BinaryExpression,
7
- BreakStatement,
8
- CallExpression,
9
- ConditionalExpression,
10
- ExpressionStatement,
11
- FunctionDeclaration,
12
- FunctionExpression,
13
- Identifier,
14
- Literal,
15
- MemberExpression,
16
- ReturnStatement,
17
- SequenceExpression,
18
- SwitchCase,
19
- SwitchStatement,
20
- ThisExpression,
21
- UnaryExpression,
22
- VariableDeclaration,
23
- VariableDeclarator,
24
- } from "../util/gen";
25
- import { getIdentifierInfo, validateChain } from "../util/identifiers";
26
- import { getVarContext, isForInitialize, isFunction } from "../util/insert";
27
- import { choice, getRandomInteger, shuffle } from "../util/random";
28
- import Transform from "./transform";
29
-
30
- export default class HideInitializingCode extends Transform {
31
- constructor(o) {
32
- super(o, ObfuscateOrder.HideInitializingCode);
33
- }
34
-
35
- match(object, parents) {
36
- return object.type == "Program";
37
- }
38
-
39
- transform(object, parents) {
40
- return () => {
41
- var body = object.body;
42
- var hasExport = false;
43
-
44
- var stmts = [];
45
- var functions = [];
46
- var exportTypes = new Set([
47
- "ExportNamedDeclaration",
48
- "ExportSpecifier",
49
- "ExportDefaultDeclaration",
50
- "ExportAllDeclaration",
51
- ]);
52
-
53
- var sampledNames = new Set<string>();
54
-
55
- body.forEach((stmt) => {
56
- if (stmt.type == "FunctionDeclaration") {
57
- functions.push(stmt);
58
- if (stmt.id) {
59
- sampledNames.add(stmt.id.name);
60
- }
61
- } else if (exportTypes.has(stmt.type)) {
62
- hasExport = true;
63
- } else {
64
- stmts.push(stmt);
65
- }
66
- });
67
-
68
- if (hasExport) {
69
- return;
70
- }
71
-
72
- var definedNames = new Set<string>();
73
-
74
- const findNames = (o, p) => {
75
- validateChain(o, p);
76
- var context = getVarContext(o, p);
77
- walk(o, p, (oo, pp) => {
78
- if (
79
- oo.type == "Identifier" &&
80
- !reservedIdentifiers.has(oo.name) &&
81
- !this.options.globalVariables.has(oo.name)
82
- ) {
83
- var info = getIdentifierInfo(oo, pp);
84
- if (
85
- info.spec.isReferenced &&
86
- info.spec.isDefined &&
87
- getVarContext(oo, pp) === context
88
- ) {
89
- definedNames.add(oo.name);
90
- }
91
- }
92
- });
93
- };
94
-
95
- walk(object, [], (o, p) => {
96
- if (o.type == "VariableDeclaration" || o.type == "ClassDeclaration") {
97
- if (p.find((x) => isFunction(x))) {
98
- return;
99
- }
100
- if (o.type == "VariableDeclaration") {
101
- return () => {
102
- var exprs = [];
103
- var fi = isForInitialize(o, p);
104
- o.declarations.forEach((declarator) => {
105
- findNames(declarator.id, [declarator, o.declarations, o, ...p]);
106
- if (fi === "left-hand") {
107
- exprs.push({ ...declarator.id });
108
- } else {
109
- exprs.push(
110
- AssignmentExpression(
111
- "=",
112
- declarator.id,
113
- declarator.init || Identifier("undefined")
114
- )
115
- );
116
- }
117
- });
118
-
119
- if (fi) {
120
- this.replace(
121
- o,
122
- exprs.length > 1 ? SequenceExpression(exprs) : exprs[0]
123
- );
124
- } else {
125
- this.replace(o, ExpressionStatement(SequenceExpression(exprs)));
126
- }
127
- };
128
- } else if (o.type == "ClassDeclaration") {
129
- if (o.id.name) {
130
- definedNames.add(o.id.name);
131
-
132
- this.replace(
133
- o,
134
- ExpressionStatement(
135
- AssignmentExpression("=", Identifier(o.id.name), {
136
- ...o,
137
- type: "ClassExpression",
138
- })
139
- )
140
- );
141
- }
142
- }
143
- }
144
- });
145
-
146
- var addNodes = [];
147
- if (definedNames.size) {
148
- addNodes.push(
149
- VariableDeclaration(
150
- Array.from(definedNames).map((name) => {
151
- return VariableDeclarator(name);
152
- })
153
- )
154
- );
155
- }
156
-
157
- var deadValues: { [name: string]: number } = Object.create(null);
158
- Array(getRandomInteger(1, 20))
159
- .fill(0)
160
- .forEach(() => {
161
- var name = this.getPlaceholder();
162
- var value = getRandomInteger(-250, 250);
163
- addNodes.push(
164
- VariableDeclaration(VariableDeclarator(name, Literal(value)))
165
- );
166
-
167
- deadValues[name] = value;
168
- sampledNames.add(name);
169
- });
170
-
171
- var map = new Map<string, { [input: number]: number }>();
172
- var fnsToMake = getRandomInteger(1, 5);
173
-
174
- function numberLiteral(num: number, depth = 1) {
175
- if (depth > 6 || Math.random() > 0.8 / depth) {
176
- return Literal(num);
177
- }
178
-
179
- function ternaryCall(
180
- name: string,
181
- param: number = getRandomInteger(-250, 250)
182
- ) {
183
- return ConditionalExpression(
184
- BinaryExpression(
185
- "==",
186
- UnaryExpression("typeof", Identifier(name)),
187
- Literal("function")
188
- ),
189
- CallExpression(Identifier(name), [numberLiteral(param, depth + 1)]),
190
- Identifier(name)
191
- );
192
- }
193
-
194
- if (Math.random() > 0.5) {
195
- var fnName = choice(Array.from(map.keys()));
196
- if (fnName) {
197
- var inputOutputs = map.get(fnName);
198
- var randomInput = choice(Object.keys(inputOutputs));
199
- var outputValue = inputOutputs[randomInput];
200
- var parsed = parseFloat(randomInput);
201
-
202
- return BinaryExpression(
203
- "-",
204
-
205
- ternaryCall(fnName, parsed),
206
- numberLiteral(outputValue - num, depth + 1)
207
- );
208
- }
209
- }
210
-
211
- var deadValueName = choice(Object.keys(deadValues));
212
- var actualValue = deadValues[deadValueName];
213
-
214
- if (Math.random() > 0.5) {
215
- return BinaryExpression(
216
- "+",
217
- numberLiteral(num - actualValue, depth + 1),
218
- ternaryCall(deadValueName)
219
- );
220
- }
221
-
222
- return BinaryExpression(
223
- "-",
224
- ternaryCall(deadValueName),
225
- numberLiteral(actualValue - num, depth + 1)
226
- );
227
- }
228
-
229
- for (var i = 0; i < fnsToMake; i++) {
230
- var name = this.getPlaceholder();
231
- var testShift = getRandomInteger(-250, 250);
232
- var returnShift = getRandomInteger(-250, 250);
233
-
234
- var inputs = getRandomInteger(2, 5);
235
- var used = new Set<number>();
236
- var uniqueNumbersNeeded = inputs * 2;
237
- for (var j = 0; j < uniqueNumbersNeeded; j++) {
238
- var num;
239
- var k = 0;
240
- do {
241
- num = getRandomInteger(-250, 250 + k * 100);
242
- k++;
243
- } while (used.has(num));
244
-
245
- used.add(num);
246
- }
247
-
248
- var inputOutput = Object.create(null);
249
- var array: number[] = Array.from(used);
250
- for (var j = 0; j < array.length; j += 2) {
251
- inputOutput[array[j]] = array[j + 1];
252
- }
253
-
254
- var cases = Object.keys(inputOutput).map((input) => {
255
- var parsed = parseFloat(input);
256
-
257
- return SwitchCase(numberLiteral(parsed + testShift), [
258
- ExpressionStatement(
259
- AssignmentExpression(
260
- "=",
261
- Identifier("input"),
262
- numberLiteral(inputOutput[input] - returnShift)
263
- )
264
- ),
265
- BreakStatement(),
266
- ]);
267
- });
268
-
269
- var functionExpression = FunctionExpression(
270
- [Identifier("testShift"), Identifier("returnShift")],
271
- [
272
- ReturnStatement(
273
- FunctionExpression(
274
- [Identifier("input")],
275
- [
276
- SwitchStatement(
277
- BinaryExpression(
278
- "+",
279
- Identifier("input"),
280
- Identifier("testShift")
281
- ),
282
- cases
283
- ),
284
-
285
- ReturnStatement(
286
- BinaryExpression(
287
- "+",
288
- Identifier("input"),
289
- Identifier("returnShift")
290
- )
291
- ),
292
- ]
293
- )
294
- ),
295
- ]
296
- );
297
-
298
- var variableDeclaration = VariableDeclaration(
299
- VariableDeclarator(
300
- name,
301
- CallExpression(functionExpression, [
302
- numberLiteral(testShift),
303
- numberLiteral(returnShift),
304
- ])
305
- )
306
- );
307
- addNodes.push(variableDeclaration);
308
-
309
- map.set(name, inputOutput);
310
- sampledNames.add(name);
311
- }
312
-
313
- var deadNameArray = Object.keys(deadValues);
314
- var sampledArray = Array.from(sampledNames);
315
-
316
- var check = getRandomInteger(-250, 250);
317
-
318
- var initName = "init" + this.getPlaceholder();
319
-
320
- // Entangle number literals
321
- var made = 1; // Limit frequency
322
- walk(stmts, [], (o, p) => {
323
- if (
324
- o.type == "Literal" &&
325
- typeof o.value === "number" &&
326
- Math.floor(o.value) === o.value &&
327
- Math.abs(o.value) < 100_000 &&
328
- Math.random() < 4 / made
329
- ) {
330
- made++;
331
- return () => {
332
- this.replaceIdentifierOrLiteral(o, numberLiteral(o.value), p);
333
- };
334
- }
335
- });
336
-
337
- // Create the new function
338
- addNodes.push(FunctionDeclaration(initName, [], [...stmts]));
339
-
340
- function truePredicate() {
341
- return BinaryExpression(
342
- ">",
343
- Literal(600 + getRandomInteger(200, 800)),
344
- Literal(400 - getRandomInteger(0, 600))
345
- );
346
- }
347
- function falsePredicate() {
348
- return BinaryExpression(
349
- ">",
350
- Literal(400 - getRandomInteger(0, 600)),
351
- Literal(600 + getRandomInteger(200, 800))
352
- );
353
- }
354
-
355
- function safeCallExpression(name, param: number) {
356
- return ConditionalExpression(
357
- BinaryExpression(
358
- "==",
359
- UnaryExpression("typeof", Identifier(name)),
360
- Literal("function")
361
- ),
362
- CallExpression(
363
- MemberExpression(Identifier(name), Identifier("call"), false),
364
- [ThisExpression(), numberLiteral(param)]
365
- ),
366
- Identifier(name)
367
- );
368
- }
369
-
370
- function ternaryHell(expr, depth = 1) {
371
- if (!depth || depth > 5 || Math.random() > 0.99 / (depth / 2)) {
372
- return expr;
373
- }
374
-
375
- var deadCode = safeCallExpression(
376
- choice(sampledArray),
377
- getRandomInteger(-250, 250)
378
- );
379
-
380
- if (Math.random() > 0.5) {
381
- return ConditionalExpression(
382
- truePredicate(),
383
- ternaryHell(expr, depth + 1),
384
- ternaryHell(deadCode, depth + 1)
385
- );
386
- }
387
-
388
- return ConditionalExpression(
389
- falsePredicate(),
390
- ternaryHell(deadCode, depth + 1),
391
- ternaryHell(expr, depth + 1)
392
- );
393
- }
394
-
395
- // Array of random ternary expressions
396
- var concealedCall = [];
397
-
398
- // Add 'dead calls', these expression don't call anything
399
- Array(getRandomInteger(2, 8))
400
- .fill(0)
401
- .forEach(() => {
402
- concealedCall.push(
403
- ExpressionStatement(
404
- ternaryHell(
405
- safeCallExpression(
406
- choice(deadNameArray),
407
- getRandomInteger(-250, 250)
408
- )
409
- )
410
- )
411
- );
412
- });
413
-
414
- // The real call to the 'init' function
415
- concealedCall.push(
416
- ExpressionStatement(ternaryHell(safeCallExpression(initName, check)))
417
- );
418
-
419
- shuffle(concealedCall);
420
- shuffle(functions);
421
-
422
- object.body = [...addNodes, ...functions, ...concealedCall];
423
- };
424
- }
425
- }
1
+ import { reservedIdentifiers } from "../constants";
2
+ import { ObfuscateOrder } from "../order";
3
+ import { walk } from "../traverse";
4
+ import {
5
+ AssignmentExpression,
6
+ BinaryExpression,
7
+ BreakStatement,
8
+ CallExpression,
9
+ ConditionalExpression,
10
+ ExpressionStatement,
11
+ FunctionDeclaration,
12
+ FunctionExpression,
13
+ Identifier,
14
+ Literal,
15
+ MemberExpression,
16
+ ReturnStatement,
17
+ SequenceExpression,
18
+ SwitchCase,
19
+ SwitchStatement,
20
+ ThisExpression,
21
+ UnaryExpression,
22
+ VariableDeclaration,
23
+ VariableDeclarator,
24
+ } from "../util/gen";
25
+ import { getIdentifierInfo, validateChain } from "../util/identifiers";
26
+ import { getVarContext, isForInitialize, isFunction } from "../util/insert";
27
+ import { choice, getRandomInteger, shuffle } from "../util/random";
28
+ import Transform from "./transform";
29
+
30
+ export default class HideInitializingCode extends Transform {
31
+ constructor(o) {
32
+ super(o, ObfuscateOrder.HideInitializingCode);
33
+ }
34
+
35
+ match(object, parents) {
36
+ return object.type == "Program";
37
+ }
38
+
39
+ transform(object, parents) {
40
+ return () => {
41
+ var body = object.body;
42
+ var hasExport = false;
43
+
44
+ var stmts = [];
45
+ var functions = [];
46
+ var exportTypes = new Set([
47
+ "ExportNamedDeclaration",
48
+ "ExportSpecifier",
49
+ "ExportDefaultDeclaration",
50
+ "ExportAllDeclaration",
51
+ ]);
52
+
53
+ var sampledNames = new Set<string>();
54
+
55
+ body.forEach((stmt) => {
56
+ if (stmt.type == "FunctionDeclaration") {
57
+ functions.push(stmt);
58
+ if (stmt.id) {
59
+ sampledNames.add(stmt.id.name);
60
+ }
61
+ } else if (exportTypes.has(stmt.type)) {
62
+ hasExport = true;
63
+ } else {
64
+ stmts.push(stmt);
65
+ }
66
+ });
67
+
68
+ if (hasExport) {
69
+ return;
70
+ }
71
+
72
+ var definedNames = new Set<string>();
73
+
74
+ const findNames = (o, p) => {
75
+ validateChain(o, p);
76
+ var context = getVarContext(o, p);
77
+ walk(o, p, (oo, pp) => {
78
+ if (
79
+ oo.type == "Identifier" &&
80
+ !reservedIdentifiers.has(oo.name) &&
81
+ !this.options.globalVariables.has(oo.name)
82
+ ) {
83
+ var info = getIdentifierInfo(oo, pp);
84
+ if (
85
+ info.spec.isReferenced &&
86
+ info.spec.isDefined &&
87
+ getVarContext(oo, pp) === context
88
+ ) {
89
+ definedNames.add(oo.name);
90
+ }
91
+ }
92
+ });
93
+ };
94
+
95
+ walk(object, [], (o, p) => {
96
+ if (o.type == "VariableDeclaration" || o.type == "ClassDeclaration") {
97
+ if (p.find((x) => isFunction(x))) {
98
+ return;
99
+ }
100
+ if (o.type == "VariableDeclaration") {
101
+ return () => {
102
+ var exprs = [];
103
+ var fi = isForInitialize(o, p);
104
+ o.declarations.forEach((declarator) => {
105
+ findNames(declarator.id, [declarator, o.declarations, o, ...p]);
106
+ if (fi === "left-hand") {
107
+ exprs.push({ ...declarator.id });
108
+ } else {
109
+ exprs.push(
110
+ AssignmentExpression(
111
+ "=",
112
+ declarator.id,
113
+ declarator.init || Identifier("undefined")
114
+ )
115
+ );
116
+ }
117
+ });
118
+
119
+ if (fi) {
120
+ this.replace(
121
+ o,
122
+ exprs.length > 1 ? SequenceExpression(exprs) : exprs[0]
123
+ );
124
+ } else {
125
+ this.replace(o, ExpressionStatement(SequenceExpression(exprs)));
126
+ }
127
+ };
128
+ } else if (o.type == "ClassDeclaration") {
129
+ if (o.id.name) {
130
+ definedNames.add(o.id.name);
131
+
132
+ this.replace(
133
+ o,
134
+ ExpressionStatement(
135
+ AssignmentExpression("=", Identifier(o.id.name), {
136
+ ...o,
137
+ type: "ClassExpression",
138
+ })
139
+ )
140
+ );
141
+ }
142
+ }
143
+ }
144
+ });
145
+
146
+ var addNodes = [];
147
+ if (definedNames.size) {
148
+ addNodes.push(
149
+ VariableDeclaration(
150
+ Array.from(definedNames).map((name) => {
151
+ return VariableDeclarator(name);
152
+ })
153
+ )
154
+ );
155
+ }
156
+
157
+ var deadValues: { [name: string]: number } = Object.create(null);
158
+ Array(getRandomInteger(1, 20))
159
+ .fill(0)
160
+ .forEach(() => {
161
+ var name = this.getPlaceholder();
162
+ var value = getRandomInteger(-250, 250);
163
+ addNodes.push(
164
+ VariableDeclaration(VariableDeclarator(name, Literal(value)))
165
+ );
166
+
167
+ deadValues[name] = value;
168
+ sampledNames.add(name);
169
+ });
170
+
171
+ var map = new Map<string, { [input: number]: number }>();
172
+ var fnsToMake = getRandomInteger(1, 5);
173
+
174
+ var numberLiteralsMade = 1;
175
+ function numberLiteral(num: number, depth = 1) {
176
+ if (
177
+ depth > 6 ||
178
+ Math.random() > 0.8 / depth ||
179
+ Math.random() > 80 / numberLiteralsMade
180
+ ) {
181
+ return Literal(num);
182
+ }
183
+
184
+ numberLiteralsMade++;
185
+
186
+ function ternaryCall(
187
+ name: string,
188
+ param: number = getRandomInteger(-250, 250)
189
+ ) {
190
+ return ConditionalExpression(
191
+ BinaryExpression(
192
+ "==",
193
+ UnaryExpression("typeof", Identifier(name)),
194
+ Literal("function")
195
+ ),
196
+ CallExpression(Identifier(name), [numberLiteral(param, depth + 1)]),
197
+ Identifier(name)
198
+ );
199
+ }
200
+
201
+ if (Math.random() > 0.5) {
202
+ var fnName = choice(Array.from(map.keys()));
203
+ if (fnName) {
204
+ var inputOutputs = map.get(fnName);
205
+ var randomInput = choice(Object.keys(inputOutputs));
206
+ var outputValue = inputOutputs[randomInput];
207
+ var parsed = parseFloat(randomInput);
208
+
209
+ return BinaryExpression(
210
+ "-",
211
+
212
+ ternaryCall(fnName, parsed),
213
+ numberLiteral(outputValue - num, depth + 1)
214
+ );
215
+ }
216
+ }
217
+
218
+ var deadValueName = choice(Object.keys(deadValues));
219
+ var actualValue = deadValues[deadValueName];
220
+
221
+ if (Math.random() > 0.5) {
222
+ return BinaryExpression(
223
+ "+",
224
+ numberLiteral(num - actualValue, depth + 1),
225
+ ternaryCall(deadValueName)
226
+ );
227
+ }
228
+
229
+ return BinaryExpression(
230
+ "-",
231
+ ternaryCall(deadValueName),
232
+ numberLiteral(actualValue - num, depth + 1)
233
+ );
234
+ }
235
+
236
+ for (var i = 0; i < fnsToMake; i++) {
237
+ var name = this.getPlaceholder();
238
+ var testShift = getRandomInteger(-250, 250);
239
+ var returnShift = getRandomInteger(-250, 250);
240
+
241
+ var inputs = getRandomInteger(2, 5);
242
+ var used = new Set<number>();
243
+ var uniqueNumbersNeeded = inputs * 2;
244
+ for (var j = 0; j < uniqueNumbersNeeded; j++) {
245
+ var num;
246
+ var k = 0;
247
+ do {
248
+ num = getRandomInteger(-250, 250 + k * 100);
249
+ k++;
250
+ } while (used.has(num));
251
+
252
+ used.add(num);
253
+ }
254
+
255
+ var inputOutput = Object.create(null);
256
+ var array: number[] = Array.from(used);
257
+ for (var j = 0; j < array.length; j += 2) {
258
+ inputOutput[array[j]] = array[j + 1];
259
+ }
260
+
261
+ var cases = Object.keys(inputOutput).map((input) => {
262
+ var parsed = parseFloat(input);
263
+
264
+ return SwitchCase(numberLiteral(parsed + testShift), [
265
+ ExpressionStatement(
266
+ AssignmentExpression(
267
+ "=",
268
+ Identifier("input"),
269
+ numberLiteral(inputOutput[input] - returnShift)
270
+ )
271
+ ),
272
+ BreakStatement(),
273
+ ]);
274
+ });
275
+
276
+ var functionExpression = FunctionExpression(
277
+ [Identifier("testShift"), Identifier("returnShift")],
278
+ [
279
+ ReturnStatement(
280
+ FunctionExpression(
281
+ [Identifier("input")],
282
+ [
283
+ SwitchStatement(
284
+ BinaryExpression(
285
+ "+",
286
+ Identifier("input"),
287
+ Identifier("testShift")
288
+ ),
289
+ cases
290
+ ),
291
+
292
+ ReturnStatement(
293
+ BinaryExpression(
294
+ "+",
295
+ Identifier("input"),
296
+ Identifier("returnShift")
297
+ )
298
+ ),
299
+ ]
300
+ )
301
+ ),
302
+ ]
303
+ );
304
+
305
+ var variableDeclaration = VariableDeclaration(
306
+ VariableDeclarator(
307
+ name,
308
+ CallExpression(functionExpression, [
309
+ numberLiteral(testShift),
310
+ numberLiteral(returnShift),
311
+ ])
312
+ )
313
+ );
314
+ addNodes.push(variableDeclaration);
315
+
316
+ map.set(name, inputOutput);
317
+ sampledNames.add(name);
318
+ }
319
+
320
+ var deadNameArray = Object.keys(deadValues);
321
+ var sampledArray = Array.from(sampledNames);
322
+
323
+ var check = getRandomInteger(-250, 250);
324
+
325
+ var initName = "init" + this.getPlaceholder();
326
+
327
+ // Entangle number literals
328
+ var made = 1; // Limit frequency
329
+ walk(stmts, [], (o, p) => {
330
+ if (
331
+ o.type == "Literal" &&
332
+ typeof o.value === "number" &&
333
+ Math.floor(o.value) === o.value &&
334
+ Math.abs(o.value) < 100_000 &&
335
+ Math.random() < 4 / made
336
+ ) {
337
+ made++;
338
+ return () => {
339
+ this.replaceIdentifierOrLiteral(o, numberLiteral(o.value), p);
340
+ };
341
+ }
342
+ });
343
+
344
+ // Create the new function
345
+ addNodes.push(FunctionDeclaration(initName, [], [...stmts]));
346
+
347
+ function truePredicate() {
348
+ return BinaryExpression(
349
+ ">",
350
+ Literal(600 + getRandomInteger(200, 800)),
351
+ Literal(400 - getRandomInteger(0, 600))
352
+ );
353
+ }
354
+ function falsePredicate() {
355
+ return BinaryExpression(
356
+ ">",
357
+ Literal(400 - getRandomInteger(0, 600)),
358
+ Literal(600 + getRandomInteger(200, 800))
359
+ );
360
+ }
361
+
362
+ function safeCallExpression(name, param: number) {
363
+ return ConditionalExpression(
364
+ BinaryExpression(
365
+ "==",
366
+ UnaryExpression("typeof", Identifier(name)),
367
+ Literal("function")
368
+ ),
369
+ CallExpression(
370
+ MemberExpression(Identifier(name), Identifier("call"), false),
371
+ [ThisExpression(), numberLiteral(param)]
372
+ ),
373
+ Identifier(name)
374
+ );
375
+ }
376
+
377
+ function ternaryHell(expr, depth = 1) {
378
+ if (!depth || depth > 5 || Math.random() > 0.99 / (depth / 2)) {
379
+ return expr;
380
+ }
381
+
382
+ var deadCode = safeCallExpression(
383
+ choice(sampledArray),
384
+ getRandomInteger(-250, 250)
385
+ );
386
+
387
+ if (Math.random() > 0.5) {
388
+ return ConditionalExpression(
389
+ truePredicate(),
390
+ ternaryHell(expr, depth + 1),
391
+ ternaryHell(deadCode, depth + 1)
392
+ );
393
+ }
394
+
395
+ return ConditionalExpression(
396
+ falsePredicate(),
397
+ ternaryHell(deadCode, depth + 1),
398
+ ternaryHell(expr, depth + 1)
399
+ );
400
+ }
401
+
402
+ // Array of random ternary expressions
403
+ var concealedCall = [];
404
+
405
+ // Add 'dead calls', these expression don't call anything
406
+ Array(getRandomInteger(2, 8))
407
+ .fill(0)
408
+ .forEach(() => {
409
+ concealedCall.push(
410
+ ExpressionStatement(
411
+ ternaryHell(
412
+ safeCallExpression(
413
+ choice(deadNameArray),
414
+ getRandomInteger(-250, 250)
415
+ )
416
+ )
417
+ )
418
+ );
419
+ });
420
+
421
+ // The real call to the 'init' function
422
+ concealedCall.push(
423
+ ExpressionStatement(ternaryHell(safeCallExpression(initName, check)))
424
+ );
425
+
426
+ shuffle(concealedCall);
427
+ shuffle(functions);
428
+
429
+ object.body = [...addNodes, ...functions, ...concealedCall];
430
+ };
431
+ }
432
+ }