js-confuser 1.5.9 → 1.7.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 (143) hide show
  1. package/.github/workflows/node.js.yml +2 -2
  2. package/CHANGELOG.md +55 -0
  3. package/README.md +346 -165
  4. package/dist/constants.js +6 -2
  5. package/dist/index.js +9 -21
  6. package/dist/obfuscator.js +19 -31
  7. package/dist/options.js +5 -5
  8. package/dist/order.js +1 -3
  9. package/dist/presets.js +6 -7
  10. package/dist/probability.js +2 -4
  11. package/dist/templates/bufferToString.js +13 -0
  12. package/dist/templates/crash.js +3 -3
  13. package/dist/templates/es5.js +18 -0
  14. package/dist/templates/functionLength.js +16 -0
  15. package/dist/transforms/calculator.js +77 -21
  16. package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +980 -367
  17. package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +4 -1
  18. package/dist/transforms/controlFlowFlattening/switchCaseObfuscation.js +25 -26
  19. package/dist/transforms/deadCode.js +33 -25
  20. package/dist/transforms/dispatcher.js +8 -4
  21. package/dist/transforms/es5/antiDestructuring.js +2 -0
  22. package/dist/transforms/es5/es5.js +31 -34
  23. package/dist/transforms/extraction/duplicateLiteralsRemoval.js +92 -58
  24. package/dist/transforms/finalizer.js +82 -0
  25. package/dist/transforms/flatten.js +229 -148
  26. package/dist/transforms/identifier/globalAnalysis.js +88 -0
  27. package/dist/transforms/identifier/globalConcealing.js +10 -83
  28. package/dist/transforms/identifier/movedDeclarations.js +35 -88
  29. package/dist/transforms/identifier/renameVariables.js +124 -59
  30. package/dist/transforms/identifier/variableAnalysis.js +58 -62
  31. package/dist/transforms/lock/lock.js +0 -37
  32. package/dist/transforms/minify.js +60 -57
  33. package/dist/transforms/opaquePredicates.js +1 -1
  34. package/dist/transforms/preparation/preparation.js +2 -2
  35. package/dist/transforms/preparation.js +231 -0
  36. package/dist/transforms/renameLabels.js +1 -1
  37. package/dist/transforms/rgf.js +139 -247
  38. package/dist/transforms/stack.js +128 -26
  39. package/dist/transforms/string/encoding.js +150 -179
  40. package/dist/transforms/string/stringCompression.js +14 -15
  41. package/dist/transforms/string/stringConcealing.js +25 -8
  42. package/dist/transforms/string/stringEncoding.js +13 -24
  43. package/dist/transforms/transform.js +12 -19
  44. package/dist/traverse.js +24 -10
  45. package/dist/util/gen.js +17 -1
  46. package/dist/util/identifiers.js +37 -3
  47. package/dist/util/insert.js +35 -4
  48. package/dist/util/random.js +15 -0
  49. package/docs/ControlFlowFlattening.md +595 -0
  50. package/{Countermeasures.md → docs/Countermeasures.md} +1 -15
  51. package/{Integrity.md → docs/Integrity.md} +2 -2
  52. package/docs/RGF.md +419 -0
  53. package/package.json +5 -5
  54. package/src/constants.ts +3 -0
  55. package/src/index.ts +2 -2
  56. package/src/obfuscator.ts +19 -31
  57. package/src/options.ts +14 -103
  58. package/src/order.ts +1 -5
  59. package/src/presets.ts +6 -7
  60. package/src/probability.ts +2 -3
  61. package/src/templates/bufferToString.ts +68 -0
  62. package/src/templates/crash.ts +15 -19
  63. package/src/templates/es5.ts +131 -0
  64. package/src/templates/functionLength.ts +14 -0
  65. package/src/transforms/calculator.ts +122 -59
  66. package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +1583 -571
  67. package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +4 -1
  68. package/src/transforms/deadCode.ts +383 -26
  69. package/src/transforms/dispatcher.ts +9 -4
  70. package/src/transforms/es5/antiDestructuring.ts +2 -0
  71. package/src/transforms/es5/es5.ts +32 -77
  72. package/src/transforms/extraction/duplicateLiteralsRemoval.ts +133 -129
  73. package/src/transforms/{hexadecimalNumbers.ts → finalizer.ts} +29 -13
  74. package/src/transforms/flatten.ts +357 -300
  75. package/src/transforms/identifier/globalAnalysis.ts +85 -0
  76. package/src/transforms/identifier/globalConcealing.ts +14 -103
  77. package/src/transforms/identifier/movedDeclarations.ts +49 -102
  78. package/src/transforms/identifier/renameVariables.ts +149 -78
  79. package/src/transforms/identifier/variableAnalysis.ts +66 -73
  80. package/src/transforms/lock/lock.ts +1 -42
  81. package/src/transforms/minify.ts +91 -75
  82. package/src/transforms/opaquePredicates.ts +2 -2
  83. package/src/transforms/preparation.ts +238 -0
  84. package/src/transforms/renameLabels.ts +2 -2
  85. package/src/transforms/rgf.ts +213 -405
  86. package/src/transforms/stack.ts +156 -36
  87. package/src/transforms/string/encoding.ts +115 -212
  88. package/src/transforms/string/stringCompression.ts +27 -18
  89. package/src/transforms/string/stringConcealing.ts +39 -9
  90. package/src/transforms/string/stringEncoding.ts +18 -18
  91. package/src/transforms/transform.ts +21 -23
  92. package/src/traverse.ts +23 -4
  93. package/src/types.ts +2 -1
  94. package/src/util/gen.ts +28 -3
  95. package/src/util/identifiers.ts +43 -2
  96. package/src/util/insert.ts +38 -3
  97. package/src/util/random.ts +13 -0
  98. package/test/code/Cash.test.ts +1 -1
  99. package/test/code/Dynamic.test.ts +12 -10
  100. package/test/code/ES6.src.js +146 -0
  101. package/test/code/ES6.test.ts +28 -2
  102. package/test/index.test.ts +2 -1
  103. package/test/probability.test.ts +44 -0
  104. package/test/templates/template.test.ts +1 -1
  105. package/test/transforms/antiTooling.test.ts +22 -0
  106. package/test/transforms/calculator.test.ts +40 -0
  107. package/test/transforms/controlFlowFlattening/controlFlowFlattening.test.ts +702 -160
  108. package/test/transforms/controlFlowFlattening/expressionObfuscation.test.ts +173 -0
  109. package/test/transforms/deadCode.test.ts +66 -15
  110. package/test/transforms/dispatcher.test.ts +20 -1
  111. package/test/transforms/es5/antiDestructuring.test.ts +16 -0
  112. package/test/transforms/flatten.test.ts +399 -86
  113. package/test/transforms/identifier/movedDeclarations.test.ts +63 -8
  114. package/test/transforms/identifier/renameVariables.test.ts +119 -0
  115. package/test/transforms/lock/antiDebug.test.ts +2 -2
  116. package/test/transforms/lock/lock.test.ts +1 -48
  117. package/test/transforms/minify.test.ts +104 -0
  118. package/test/transforms/preparation.test.ts +157 -0
  119. package/test/transforms/rgf.test.ts +261 -381
  120. package/test/transforms/stack.test.ts +143 -21
  121. package/test/transforms/string/stringCompression.test.ts +39 -0
  122. package/test/transforms/string/stringConcealing.test.ts +82 -0
  123. package/test/transforms/string/stringEncoding.test.ts +53 -2
  124. package/test/transforms/transform.test.ts +66 -0
  125. package/test/traverse.test.ts +139 -0
  126. package/test/util/identifiers.test.ts +113 -1
  127. package/test/util/insert.test.ts +57 -3
  128. package/src/transforms/controlFlowFlattening/choiceFlowObfuscation.ts +0 -87
  129. package/src/transforms/controlFlowFlattening/controlFlowObfuscation.ts +0 -203
  130. package/src/transforms/controlFlowFlattening/switchCaseObfuscation.ts +0 -130
  131. package/src/transforms/eval.ts +0 -89
  132. package/src/transforms/hideInitializingCode.ts +0 -432
  133. package/src/transforms/identifier/nameRecycling.ts +0 -280
  134. package/src/transforms/label.ts +0 -64
  135. package/src/transforms/preparation/nameConflicts.ts +0 -102
  136. package/src/transforms/preparation/preparation.ts +0 -176
  137. package/test/transforms/controlFlowFlattening/controlFlowObfuscation.test.ts +0 -101
  138. package/test/transforms/controlFlowFlattening/switchCaseObfuscation.test.ts +0 -120
  139. package/test/transforms/eval.test.ts +0 -131
  140. package/test/transforms/hideInitializingCode.test.ts +0 -336
  141. package/test/transforms/identifier/nameRecycling.test.ts +0 -205
  142. package/test/transforms/preparation/nameConflicts.test.ts +0 -52
  143. package/test/transforms/preparation/preparation.test.ts +0 -62
@@ -2,6 +2,9 @@ import { isBlock } from "../../traverse";
2
2
  import { Identifier, SequenceExpression } from "../../util/gen";
3
3
  import Transform from "../transform";
4
4
 
5
+ /**
6
+ * Expression Obfuscation runs before Control Flow Flattening
7
+ */
5
8
  export default class ExpressionObfuscation extends Transform {
6
9
  constructor(o) {
7
10
  super(o);
@@ -17,7 +20,7 @@ export default class ExpressionObfuscation extends Transform {
17
20
  var deleteExprs = [];
18
21
 
19
22
  object.body.forEach((stmt, i) => {
20
- if (stmt.type == "ExpressionStatement") {
23
+ if (stmt.type == "ExpressionStatement" && !stmt.directive) {
21
24
  var expr = stmt.expression;
22
25
 
23
26
  if (
@@ -226,6 +226,356 @@ function setCookie(cname, cvalue, exdays) {
226
226
  getHeightBalanced,
227
227
  };
228
228
  `),
229
+ Template(`
230
+ function ListNode(){}
231
+ var addTwoNumbers = function(l1, l2) {
232
+ var carry = 0;
233
+ var sum = 0;
234
+ var head = new ListNode(0);
235
+ var now = head;
236
+ var a = l1;
237
+ var b = l2;
238
+ while (a !== null || b !== null) {
239
+ sum = (a ? a.val : 0) + (b ? b.val : 0) + carry;
240
+ carry = Math.floor(sum / 10);
241
+ now.next = new ListNode(sum % 10);
242
+ now = now.next;
243
+ a = a ? a.next : null;
244
+ b = b ? b.next : null;
245
+ }
246
+ if (carry) now.next = new ListNode(carry);
247
+ return head.next;
248
+ };
249
+
250
+ console.log(addTwoNumbers)
251
+ `),
252
+ Template(`
253
+ var threeSum = function(nums) {
254
+ var len = nums.length;
255
+ var res = [];
256
+ var l = 0;
257
+ var r = 0;
258
+ nums.sort((a, b) => (a - b));
259
+ for (var i = 0; i < len; i++) {
260
+ if (i > 0 && nums[i] === nums[i - 1]) continue;
261
+ l = i + 1;
262
+ r = len - 1;
263
+ while (l < r) {
264
+ if (nums[i] + nums[l] + nums[r] < 0) {
265
+ l++;
266
+ } else if (nums[i] + nums[l] + nums[r] > 0) {
267
+ r--;
268
+ } else {
269
+ res.push([nums[i], nums[l], nums[r]]);
270
+ while (l < r && nums[l] === nums[l + 1]) l++;
271
+ while (l < r && nums[r] === nums[r - 1]) r--;
272
+ l++;
273
+ r--;
274
+ }
275
+ }
276
+ }
277
+ return res;
278
+ };
279
+ console.log(threeSum)
280
+ `),
281
+ Template(`
282
+ var combinationSum2 = function(candidates, target) {
283
+ var res = [];
284
+ var len = candidates.length;
285
+ candidates.sort((a, b) => (a - b));
286
+ dfs(res, [], 0, len, candidates, target);
287
+ return res;
288
+ };
289
+
290
+ var dfs = function (res, stack, index, len, candidates, target) {
291
+ var tmp = null;
292
+ if (target < 0) return;
293
+ if (target === 0) return res.push(stack);
294
+ for (var i = index; i < len; i++) {
295
+ if (candidates[i] > target) break;
296
+ if (i > index && candidates[i] === candidates[i - 1]) continue;
297
+ tmp = Array.from(stack);
298
+ tmp.push(candidates[i]);
299
+ dfs(res, tmp, i + 1, len, candidates, target - candidates[i]);
300
+ }
301
+ };
302
+
303
+ console.log(combinationSum2);
304
+ `),
305
+ Template(`
306
+ var isScramble = function(s1, s2) {
307
+ return helper({}, s1, s2);
308
+ };
309
+
310
+ var helper = function (dp, s1, s2) {
311
+ var map = {};
312
+
313
+ if (dp[s1 + s2] !== undefined) return dp[s1 + s2];
314
+ if (s1 === s2) return true;
315
+
316
+ for (var j = 0; j < s1.length; j++) {
317
+ if (map[s1[j]] === undefined) map[s1[j]] = 0;
318
+ if (map[s2[j]] === undefined) map[s2[j]] = 0;
319
+ map[s1[j]]++;
320
+ map[s2[j]]--;
321
+ }
322
+
323
+ for (var key in map) {
324
+ if (map[key] !== 0) {
325
+ dp[s1 + s2] = false;
326
+ return false;
327
+ }
328
+ }
329
+
330
+ for (var i = 1; i < s1.length; i++) {
331
+ if ((helper(dp, s1.substr(0, i), s2.substr(0, i))
332
+ && helper(dp, s1.substr(i), s2.substr(i))) ||
333
+ (helper(dp, s1.substr(0, i), s2.substr(s2.length - i))
334
+ && helper(dp, s1.substr(i), s2.substr(0, s2.length - i)))) {
335
+ dp[s1 + s2] = true;
336
+ return true;
337
+ }
338
+ }
339
+
340
+ dp[s1 + s2] = false;
341
+ return false;
342
+ };
343
+
344
+ console.log(isScramble);
345
+ `),
346
+ Template(`
347
+ var candy = function(ratings) {
348
+ var len = ratings.length;
349
+ var res = [];
350
+ var sum = 0;
351
+ for (var i = 0; i < len; i++) {
352
+ res.push((i !== 0 && ratings[i] > ratings[i - 1]) ? (res[i - 1] + 1) : 1);
353
+ }
354
+ for (var j = len - 1; j >= 0; j--) {
355
+ if (j !== len - 1 && ratings[j] > ratings[j + 1]) res[j] = Math.max(res[j], res[j + 1] + 1);
356
+ sum += res[j];
357
+ }
358
+ return sum;
359
+ };
360
+
361
+ console.log(candy)
362
+ `),
363
+ Template(`
364
+ var maxPoints = function(points) {
365
+ var max = 0;
366
+ var map = {};
367
+ var localMax = 0;
368
+ var samePoint = 0;
369
+ var k = 0;
370
+ var len = points.length;
371
+ for (var i = 0; i < len; i++) {
372
+ map = {};
373
+ localMax = 0;
374
+ samePoint = 1;
375
+ for (var j = i + 1; j < len; j++) {
376
+ if (points[i].x === points[j].x && points[i].y === points[j].y) {
377
+ samePoint++;
378
+ continue;
379
+ }
380
+ if (points[i].y === points[j].y) k = Number.MAX_SAFE_INTEGER;
381
+ else k = (points[i].x - points[j].x) / (points[i].y - points[j].y);
382
+ if (!map[k]) map[k] = 0;
383
+ map[k]++;
384
+ localMax = Math.max(localMax, map[k]);
385
+ }
386
+ localMax += samePoint;
387
+ max = Math.max(max, localMax);
388
+ }
389
+ return max;
390
+ };
391
+
392
+ console.log(maxPoints)
393
+ `),
394
+ Template(`
395
+ var maximumGap = function(nums) {
396
+ var len = nums.length;
397
+ if (len < 2) return 0;
398
+
399
+ var max = Math.max(...nums);
400
+ var min = Math.min(...nums);
401
+ if (max === min) return 0;
402
+
403
+ var minBuckets = Array(len - 1).fill(Number.MAX_SAFE_INTEGER);
404
+ var maxBuckets = Array(len - 1).fill(Number.MIN_SAFE_INTEGER);
405
+ var gap = Math.ceil((max - min) / (len - 1));
406
+ var index = 0;
407
+ for (var i = 0; i < len; i++) {
408
+ if (nums[i] === min || nums[i] === max) continue;
409
+ index = Math.floor((nums[i] - min) / gap);
410
+ minBuckets[index] = Math.min(minBuckets[index], nums[i]);
411
+ maxBuckets[index] = Math.max(maxBuckets[index], nums[i]);
412
+ }
413
+
414
+ var maxGap = Number.MIN_SAFE_INTEGER;
415
+ var preVal = min;
416
+ for (var j = 0; j < len - 1; j++) {
417
+ if (minBuckets[j] === Number.MAX_SAFE_INTEGER && maxBuckets[j] === Number.MIN_SAFE_INTEGER) continue;
418
+ maxGap = Math.max(maxGap, minBuckets[j] - preVal);
419
+ preVal = maxBuckets[j];
420
+ }
421
+ maxGap = Math.max(maxGap, max - preVal);
422
+
423
+ return maxGap;
424
+ };
425
+
426
+ console.log(maximumGap);
427
+ `),
428
+ Template(`
429
+ /**
430
+ * @param {number} capacity
431
+ */
432
+ var LRUCache = function(capacity) {
433
+ this.capacity = capacity;
434
+ this.length = 0;
435
+ this.map = {};
436
+ this.head = null;
437
+ this.tail = null;
438
+ };
439
+
440
+ /**
441
+ * @param {number} key
442
+ * @return {number}
443
+ */
444
+ LRUCache.prototype.get = function(key) {
445
+ var node = this.map[key];
446
+ if (node) {
447
+ this.remove(node);
448
+ this.insert(node.key, node.val);
449
+ return node.val;
450
+ } else {
451
+ return -1;
452
+ }
453
+ };
454
+
455
+ /**
456
+ * @param {number} key
457
+ * @param {number} value
458
+ * @return {void}
459
+ */
460
+ LRUCache.prototype.put = function(key, value) {
461
+ if (this.map[key]) {
462
+ this.remove(this.map[key]);
463
+ this.insert(key, value);
464
+ } else {
465
+ if (this.length === this.capacity) {
466
+ this.remove(this.head);
467
+ this.insert(key, value);
468
+ } else {
469
+ this.insert(key, value);
470
+ this.length++;
471
+ }
472
+ }
473
+ };
474
+
475
+ /**
476
+ * Your LRUCache object will be instantiated and called as such:
477
+ * var obj = Object.create(LRUCache).createNew(capacity)
478
+ * var param_1 = obj.get(key)
479
+ * obj.put(key,value)
480
+ */
481
+
482
+ LRUCache.prototype.remove = function (node) {
483
+ var prev = node.prev;
484
+ var next = node.next;
485
+ if (next) next.prev = prev;
486
+ if (prev) prev.next = next;
487
+ if (this.head === node) this.head = next;
488
+ if (this.tail === node) this.tail = prev;
489
+ delete this.map[node.key];
490
+ };
491
+
492
+ LRUCache.prototype.insert = function (key, val) {
493
+ var node = new List(key, val);
494
+ if (!this.tail) {
495
+ this.tail = node;
496
+ this.head = node;
497
+ } else {
498
+ this.tail.next = node;
499
+ node.prev = this.tail;
500
+ this.tail = node;
501
+ }
502
+ this.map[key] = node;
503
+ };
504
+
505
+ console.log(LRUCache);
506
+ `),
507
+ Template(`
508
+ var isInterleave = function(s1, s2, s3) {
509
+ var dp = {};
510
+ if (s3.length !== s1.length + s2.length) return false;
511
+ return helper(s1, s2, s3, 0, 0, 0, dp);
512
+ };
513
+
514
+ var helper = function (s1, s2, s3, i, j, k, dp) {
515
+ var res = false;
516
+
517
+ if (k >= s3.length) return true;
518
+ if (dp['' + i + j + k] !== undefined) return dp['' + i + j + k];
519
+
520
+ if (s3[k] === s1[i] && s3[k] === s2[j]) {
521
+ res = helper(s1, s2, s3, i + 1, j, k + 1, dp) || helper(s1, s2, s3, i, j + 1, k + 1, dp);
522
+ } else if (s3[k] === s1[i]) {
523
+ res = helper(s1, s2, s3, i + 1, j, k + 1, dp);
524
+ } else if (s3[k] === s2[j]) {
525
+ res = helper(s1, s2, s3, i, j + 1, k + 1, dp);
526
+ }
527
+
528
+ dp['' + i + j + k] = res;
529
+
530
+ return res;
531
+ };
532
+
533
+ console.log(isInterleave);
534
+ `),
535
+ Template(`
536
+ var solveNQueens = function(n) {
537
+ var res = [];
538
+ if (n === 1 || n >= 4) dfs(res, [], n, 0);
539
+ return res;
540
+ };
541
+
542
+ var dfs = function (res, points, n, index) {
543
+ for (var i = index; i < n; i++) {
544
+ if (points.length !== i) return;
545
+ for (var j = 0; j < n; j++) {
546
+ if (isValid(points, [i, j])) {
547
+ points.push([i, j]);
548
+ dfs(res, points, n, i + 1);
549
+ if (points.length === n) res.push(buildRes(points));
550
+ points.pop();
551
+ }
552
+ }
553
+ }
554
+ };
555
+
556
+ var buildRes = function (points) {
557
+ var res = [];
558
+ var n = points.length;
559
+ for (var i = 0; i < n; i++) {
560
+ res[i] = '';
561
+ for (var j = 0; j < n; j++) {
562
+ res[i] += (points[i][1] === j ? 'Q' : '.');
563
+ }
564
+ }
565
+ return res;
566
+ };
567
+
568
+ var isValid = function (oldPoints, newPoint) {
569
+ var len = oldPoints.length;
570
+ for (var i = 0; i < len; i++) {
571
+ if (oldPoints[i][0] === newPoint[0] || oldPoints[i][1] === newPoint[1]) return false;
572
+ if (Math.abs((oldPoints[i][0] - newPoint[0]) / (oldPoints[i][1] - newPoint[1])) === 1) return false;
573
+ }
574
+ return true;
575
+ };
576
+
577
+ console.log(solveNQueens);
578
+ `),
229
579
  ];
230
580
 
231
581
  /**
@@ -235,7 +585,6 @@ function setCookie(cname, cvalue, exdays) {
235
585
  * - Adds fake code from various samples.
236
586
  */
237
587
  export default class DeadCode extends Transform {
238
- usedNames: Set<string>;
239
588
  made: number;
240
589
 
241
590
  constructor(o) {
@@ -253,35 +602,43 @@ export default class DeadCode extends Transform {
253
602
  }
254
603
 
255
604
  transform(object: Node, parents: Node[]) {
256
- if (ComputeProbabilityMap(this.options.deadCode)) {
257
- return () => {
258
- this.made++;
259
- if (this.made > 100) {
260
- return;
261
- }
605
+ if (!ComputeProbabilityMap(this.options.deadCode)) {
606
+ return;
607
+ }
262
608
 
263
- var name = this.getPlaceholder();
264
- var variableDeclaration = VariableDeclaration(
265
- VariableDeclarator(name, Literal(false))
266
- );
609
+ // Hard-coded limit of 100 Dead Code insertions
610
+ this.made++;
611
+ if (this.made > 100) {
612
+ return;
613
+ }
614
+
615
+ return () => {
616
+ var body = getBlockBody(object);
267
617
 
268
- var body = getBlockBody(object);
269
- var index = getRandomInteger(0, body.length);
618
+ // Do not place code before Import statements or 'use strict' directives
619
+ var safeOffset = 0;
620
+ for (var node of body) {
621
+ if (node.type === "ImportDeclaration" || node.directive) safeOffset++;
622
+ else break;
623
+ }
270
624
 
271
- var template;
272
- do {
273
- template = choice(templates);
274
- } while (this.options.es5 && template.source.includes("async"));
625
+ var index = getRandomInteger(safeOffset, body.length);
275
626
 
276
- var ifStatement = IfStatement(
277
- Identifier(name),
278
- template.compile(),
279
- null
280
- );
627
+ var name = this.getPlaceholder();
628
+ var variableDeclaration = VariableDeclaration(
629
+ VariableDeclarator(name, Literal(false))
630
+ );
281
631
 
282
- body.splice(index, 0, ifStatement);
283
- prepend(object, variableDeclaration);
284
- };
285
- }
632
+ var template;
633
+ do {
634
+ template = choice(templates);
635
+ } while (this.options.es5 && template.source.includes("async"));
636
+
637
+ var ifStatement = IfStatement(Identifier(name), template.compile(), null);
638
+
639
+ body.splice(index, 0, ifStatement);
640
+
641
+ prepend(object, variableDeclaration);
642
+ };
286
643
  }
287
644
  }
@@ -68,6 +68,8 @@ import Template from "../templates/template";
68
68
  * 3. using `this`
69
69
  */
70
70
  export default class Dispatcher extends Transform {
71
+ // Debug mode preserves function names
72
+ isDebug = false;
71
73
  count: number;
72
74
 
73
75
  constructor(o) {
@@ -124,6 +126,8 @@ export default class Dispatcher extends Transform {
124
126
 
125
127
  if (context === c) {
126
128
  if (o.type == "FunctionDeclaration" && o.id.name) {
129
+ var name = o.id.name;
130
+
127
131
  if (
128
132
  o.$requiresEval ||
129
133
  o.async ||
@@ -136,8 +140,6 @@ export default class Dispatcher extends Transform {
136
140
  illegalFnNames.add(name);
137
141
  }
138
142
 
139
- var name = o.id.name;
140
-
141
143
  // If dupe, no routing
142
144
  if (functionDeclarations[name]) {
143
145
  illegalFnNames.add(name);
@@ -196,14 +198,17 @@ export default class Dispatcher extends Transform {
196
198
  // map original name->new game
197
199
  var gen = this.getGenerator();
198
200
  Object.keys(functionDeclarations).forEach((name) => {
199
- newFnNames[name] = gen.generate();
201
+ newFnNames[name] = this.isDebug
202
+ ? "_dispatcher_" + this.count + "_" + name
203
+ : gen.generate();
200
204
  });
201
205
  // set containing new name
202
206
  var set = new Set(Object.keys(newFnNames));
203
207
 
204
208
  // Only make a dispatcher function if it caught any functions
205
209
  if (set.size > 0) {
206
- var payloadArg = `$jsc_d${this.count}_payload`;
210
+ var payloadArg =
211
+ this.getPlaceholder() + "_dispatcher_" + this.count + "_payload";
207
212
 
208
213
  var dispatcherFnName =
209
214
  this.getPlaceholder() + "_dispatcher_" + this.count;
@@ -211,6 +211,8 @@ export default class AntiDestructuring extends Transform {
211
211
  exprs.push(AssignmentExpression(operator, clone(x), realm));
212
212
 
213
213
  names.add(x.name);
214
+ } else if (x.type == "MemberExpression") {
215
+ exprs.push(AssignmentExpression(operator, clone(x), realm));
214
216
  } else if (x.type == "ObjectPattern") {
215
217
  x.properties.forEach((property) => {
216
218
  recursive(
@@ -7,14 +7,10 @@ import {
7
7
  BlockStatement,
8
8
  ReturnStatement,
9
9
  CallExpression,
10
- ObjectExpression,
11
- ArrayExpression,
12
10
  ThisExpression,
13
- Property,
14
11
  } from "../../util/gen";
15
- import { clone, getBlockBody, prepend } from "../../util/insert";
16
- import { isBlock, getBlock, walk } from "../../traverse";
17
- import Template from "../../templates/template";
12
+ import { clone, prepend } from "../../util/insert";
13
+ import { isBlock, walk } from "../../traverse";
18
14
  import { ObfuscateOrder } from "../../order";
19
15
  import { ok } from "assert";
20
16
  import { reservedKeywords } from "../../constants";
@@ -23,6 +19,7 @@ import AntiTemplate from "./antiTemplate";
23
19
  import AntiClass from "./antiClass";
24
20
  import AntiES6Object from "./antiES6Object";
25
21
  import AntiSpreadOperator from "./antiSpreadOperator";
22
+ import { ES5Template } from "../../templates/es5";
26
23
 
27
24
  /**
28
25
  * `Const` and `Let` are not allowed in ES5.
@@ -96,24 +93,40 @@ export class AntiArrowFunction extends Transform {
96
93
  }
97
94
  }
98
95
 
99
- class FixedExpressions extends Transform {
96
+ /**
97
+ * The ES5 options aims to convert ES6 and up features down to ES5-compatible code.
98
+ *
99
+ * The obfuscator regularly adds ES6 code (variable destructuring, spread element, etc.)
100
+ * This transformations goal is undo only these things.
101
+ */
102
+ export default class ES5 extends Transform {
100
103
  constructor(o) {
101
- super(o);
104
+ super(o, ObfuscateOrder.ES5);
105
+
106
+ this.before.push(new AntiClass(o));
107
+ this.before.push(new AntiTemplate(o));
108
+ this.before.push(new AntiSpreadOperator(o));
109
+ this.before.push(new AntiES6Object(o));
110
+ this.before.push(new AntiArrowFunction(o));
111
+ this.before.push(new AntiDestructuring(o));
112
+ this.before.push(new AntiConstLet(o));
102
113
  }
103
114
 
104
- match(object, parents) {
105
- return true;
115
+ apply(tree: Node) {
116
+ super.apply(tree);
117
+
118
+ var nodesToAdd = ES5Template.compile();
119
+ prepend(tree, ...nodesToAdd);
106
120
  }
107
121
 
108
- transform(object, parents) {
109
- return () => {
110
- if (
111
- object.type == "ForStatement" &&
112
- object.init.type == "ExpressionStatement"
113
- ) {
114
- object.init = object.init.expression;
115
- }
122
+ // FixedExpressions
123
+ match(object: Node, parents: Node[]) {
124
+ return !!object.type;
125
+ }
116
126
 
127
+ transform(object: Node, parents: Node[]) {
128
+ return () => {
129
+ // Object.keyword -> Object["keyword"]
117
130
  if (object.type == "MemberExpression") {
118
131
  if (!object.computed && object.property.type == "Identifier") {
119
132
  if (reservedKeywords.has(object.property.name)) {
@@ -123,6 +136,7 @@ class FixedExpressions extends Transform {
123
136
  }
124
137
  }
125
138
 
139
+ // { keyword: ... } -> { "keyword": ... }
126
140
  if (object.type == "Property") {
127
141
  if (!object.computed && object.key.type == "Identifier") {
128
142
  if (reservedKeywords.has(object.key.name)) {
@@ -133,62 +147,3 @@ class FixedExpressions extends Transform {
133
147
  };
134
148
  }
135
149
  }
136
-
137
- export default class ES5 extends Transform {
138
- constructor(o) {
139
- super(o, ObfuscateOrder.ES5);
140
-
141
- this.before.push(new AntiClass(o));
142
- this.before.push(new AntiTemplate(o));
143
- this.before.push(new AntiSpreadOperator(o));
144
- this.before.push(new AntiES6Object(o));
145
- this.before.push(new AntiArrowFunction(o));
146
- this.before.push(new AntiDestructuring(o));
147
- this.before.push(new AntiConstLet(o));
148
-
149
- this.concurrent.push(new FixedExpressions(o));
150
- }
151
-
152
- match(object: Node, parents: Node[]) {
153
- return object.type == "Program";
154
- }
155
-
156
- transform(object: Node, parents: Node[]) {
157
- var block = getBlock(object, parents);
158
-
159
- getBlockBody(block).splice(
160
- 0,
161
- 0,
162
- ...Template(`
163
- !Array.prototype.forEach ? Array.prototype.forEach = function (callback, thisArg) {
164
- thisArg = thisArg;
165
- for (var i = 0; i < this.length; i++) {
166
- callback.call(thisArg, this[i], i, this);
167
- }
168
- } : 0;
169
-
170
- !Array.prototype.map ? Array.prototype.map = function (callback, thisArg) {
171
- thisArg = thisArg;
172
- var array=[];
173
- for (var i = 0; i < this.length; i++) {
174
- array.push( callback.call(thisArg, this[i], i, this) );
175
- }
176
- return array;
177
- } : 0;
178
-
179
- !Array.prototype.reduce ? Array.prototype.reduce = function(fn, initial) {
180
- var values = this;
181
- if ( typeof initial === "undefined" ) {
182
- initial = 0;
183
- }
184
-
185
- values.forEach(function(item, index){
186
- initial = fn(initial, item, index, this);
187
- });
188
-
189
- return initial;
190
- } : 0;
191
- `).compile()
192
- );
193
- }
194
- }