js-confuser 1.7.1 → 1.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/.github/workflows/node.js.yml +1 -1
  2. package/CHANGELOG.md +73 -0
  3. package/README.md +32 -31
  4. package/dist/compiler.js +2 -8
  5. package/dist/constants.js +22 -10
  6. package/dist/index.js +15 -30
  7. package/dist/obfuscator.js +15 -62
  8. package/dist/options.js +33 -40
  9. package/dist/order.js +4 -7
  10. package/dist/parser.js +5 -13
  11. package/dist/precedence.js +6 -8
  12. package/dist/presets.js +4 -6
  13. package/dist/probability.js +13 -24
  14. package/dist/templates/bufferToString.js +121 -5
  15. package/dist/templates/core.js +35 -0
  16. package/dist/templates/crash.js +22 -11
  17. package/dist/templates/es5.js +125 -6
  18. package/dist/templates/functionLength.js +24 -6
  19. package/dist/templates/globals.js +9 -0
  20. package/dist/templates/template.js +189 -43
  21. package/dist/transforms/antiTooling.js +26 -22
  22. package/dist/transforms/calculator.js +19 -55
  23. package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +242 -333
  24. package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +46 -25
  25. package/dist/transforms/deadCode.js +542 -31
  26. package/dist/transforms/dispatcher.js +112 -112
  27. package/dist/transforms/es5/antiClass.js +70 -44
  28. package/dist/transforms/es5/antiDestructuring.js +14 -38
  29. package/dist/transforms/es5/antiES6Object.js +39 -48
  30. package/dist/transforms/es5/antiSpreadOperator.js +5 -14
  31. package/dist/transforms/es5/antiTemplate.js +10 -19
  32. package/dist/transforms/es5/es5.js +7 -40
  33. package/dist/transforms/extraction/classExtraction.js +83 -0
  34. package/dist/transforms/extraction/duplicateLiteralsRemoval.js +41 -80
  35. package/dist/transforms/extraction/objectExtraction.js +24 -56
  36. package/dist/transforms/finalizer.js +6 -20
  37. package/dist/transforms/flatten.js +51 -99
  38. package/dist/transforms/identifier/globalAnalysis.js +21 -26
  39. package/dist/transforms/identifier/globalConcealing.js +72 -56
  40. package/dist/transforms/identifier/movedDeclarations.js +66 -38
  41. package/dist/transforms/identifier/renameVariables.js +36 -68
  42. package/dist/transforms/identifier/variableAnalysis.js +21 -48
  43. package/dist/transforms/lock/antiDebug.js +20 -25
  44. package/dist/transforms/lock/integrity.js +53 -52
  45. package/dist/transforms/lock/lock.js +161 -126
  46. package/dist/transforms/minify.js +77 -108
  47. package/dist/transforms/opaquePredicates.js +12 -49
  48. package/dist/transforms/preparation.js +28 -49
  49. package/dist/transforms/renameLabels.js +5 -22
  50. package/dist/transforms/rgf.js +125 -72
  51. package/dist/transforms/shuffle.js +42 -47
  52. package/dist/transforms/stack.js +41 -98
  53. package/dist/transforms/string/encoding.js +76 -27
  54. package/dist/transforms/string/stringCompression.js +75 -68
  55. package/dist/transforms/string/stringConcealing.js +127 -135
  56. package/dist/transforms/string/stringEncoding.js +6 -26
  57. package/dist/transforms/string/stringSplitting.js +5 -30
  58. package/dist/transforms/transform.js +76 -104
  59. package/dist/traverse.js +11 -18
  60. package/dist/util/compare.js +27 -29
  61. package/dist/util/gen.js +32 -86
  62. package/dist/util/guard.js +5 -1
  63. package/dist/util/identifiers.js +9 -72
  64. package/dist/util/insert.js +27 -77
  65. package/dist/util/math.js +0 -3
  66. package/dist/util/object.js +3 -7
  67. package/dist/util/random.js +31 -36
  68. package/dist/util/scope.js +6 -3
  69. package/docs/Countermeasures.md +13 -6
  70. package/docs/Integrity.md +35 -28
  71. package/docs/RGF.md +6 -1
  72. package/docs/RenameVariables.md +116 -0
  73. package/docs/TamperProtection.md +100 -0
  74. package/docs/Template.md +117 -0
  75. package/package.json +3 -3
  76. package/src/constants.ts +17 -0
  77. package/src/index.ts +7 -5
  78. package/src/options.ts +60 -7
  79. package/src/order.ts +2 -2
  80. package/src/templates/bufferToString.ts +79 -11
  81. package/src/templates/core.ts +29 -0
  82. package/src/templates/crash.ts +6 -38
  83. package/src/templates/es5.ts +1 -1
  84. package/src/templates/functionLength.ts +21 -3
  85. package/src/templates/globals.ts +3 -0
  86. package/src/templates/template.ts +205 -46
  87. package/src/transforms/antiTooling.ts +33 -11
  88. package/src/transforms/calculator.ts +4 -2
  89. package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +12 -5
  90. package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +46 -10
  91. package/src/transforms/deadCode.ts +74 -42
  92. package/src/transforms/dispatcher.ts +99 -73
  93. package/src/transforms/es5/antiClass.ts +25 -12
  94. package/src/transforms/es5/antiDestructuring.ts +1 -1
  95. package/src/transforms/es5/antiES6Object.ts +2 -2
  96. package/src/transforms/es5/antiTemplate.ts +1 -1
  97. package/src/transforms/extraction/classExtraction.ts +168 -0
  98. package/src/transforms/extraction/duplicateLiteralsRemoval.ts +11 -16
  99. package/src/transforms/extraction/objectExtraction.ts +4 -15
  100. package/src/transforms/flatten.ts +20 -5
  101. package/src/transforms/identifier/globalAnalysis.ts +18 -1
  102. package/src/transforms/identifier/globalConcealing.ts +119 -72
  103. package/src/transforms/identifier/movedDeclarations.ts +90 -24
  104. package/src/transforms/identifier/renameVariables.ts +16 -1
  105. package/src/transforms/lock/antiDebug.ts +2 -2
  106. package/src/transforms/lock/integrity.ts +13 -11
  107. package/src/transforms/lock/lock.ts +122 -30
  108. package/src/transforms/minify.ts +28 -13
  109. package/src/transforms/opaquePredicates.ts +2 -2
  110. package/src/transforms/preparation.ts +16 -0
  111. package/src/transforms/rgf.ts +139 -12
  112. package/src/transforms/shuffle.ts +3 -3
  113. package/src/transforms/stack.ts +19 -4
  114. package/src/transforms/string/encoding.ts +88 -51
  115. package/src/transforms/string/stringCompression.ts +86 -17
  116. package/src/transforms/string/stringConcealing.ts +148 -118
  117. package/src/transforms/string/stringEncoding.ts +1 -2
  118. package/src/transforms/string/stringSplitting.ts +1 -2
  119. package/src/transforms/transform.ts +63 -46
  120. package/src/types.ts +2 -0
  121. package/src/util/compare.ts +39 -5
  122. package/src/util/gen.ts +10 -3
  123. package/src/util/guard.ts +10 -0
  124. package/src/util/insert.ts +17 -0
  125. package/src/util/random.ts +81 -1
  126. package/src/util/scope.ts +14 -2
  127. package/test/code/Cash.test.ts +94 -5
  128. package/test/code/StrictMode.src.js +65 -0
  129. package/test/code/StrictMode.test.js +37 -0
  130. package/test/compare.test.ts +62 -2
  131. package/test/options.test.ts +129 -55
  132. package/test/templates/template.test.ts +211 -1
  133. package/test/transforms/controlFlowFlattening/expressionObfuscation.test.ts +37 -18
  134. package/test/transforms/dispatcher.test.ts +55 -0
  135. package/test/transforms/extraction/classExtraction.test.ts +86 -0
  136. package/test/transforms/extraction/duplicateLiteralsRemoval.test.ts +8 -0
  137. package/test/transforms/extraction/objectExtraction.test.ts +2 -0
  138. package/test/transforms/identifier/globalConcealing.test.ts +89 -0
  139. package/test/transforms/identifier/movedDeclarations.test.ts +61 -0
  140. package/test/transforms/identifier/renameVariables.test.ts +75 -1
  141. package/test/transforms/lock/tamperProtection.test.ts +336 -0
  142. package/test/transforms/minify.test.ts +37 -0
  143. package/test/transforms/rgf.test.ts +50 -0
  144. package/dist/transforms/controlFlowFlattening/choiceFlowObfuscation.js +0 -62
  145. package/dist/transforms/controlFlowFlattening/controlFlowObfuscation.js +0 -159
  146. package/dist/transforms/controlFlowFlattening/switchCaseObfuscation.js +0 -106
  147. package/dist/transforms/eval.js +0 -84
  148. package/dist/transforms/hexadecimalNumbers.js +0 -63
  149. package/dist/transforms/hideInitializingCode.js +0 -270
  150. package/dist/transforms/identifier/nameRecycling.js +0 -218
  151. package/dist/transforms/label.js +0 -67
  152. package/dist/transforms/preparation/nameConflicts.js +0 -116
  153. package/dist/transforms/preparation/preparation.js +0 -188
@@ -1,32 +1,51 @@
1
1
  import { ObfuscateOrder } from "../order";
2
+ import Template from "../templates/template";
2
3
  import { isBlock } from "../traverse";
3
4
  import {
5
+ Node,
4
6
  ExpressionStatement,
5
- SequenceExpression,
6
- UnaryExpression,
7
+ CallExpression,
8
+ Identifier,
7
9
  } from "../util/gen";
8
- import { choice } from "../util/random";
10
+ import { prepend } from "../util/insert";
9
11
  import Transform from "./transform";
10
12
 
11
13
  // JsNice.org tries to separate sequence expressions into multiple lines, this stops that.
12
14
  export default class AntiTooling extends Transform {
15
+ fnName: string;
16
+
13
17
  constructor(o) {
14
18
  super(o, ObfuscateOrder.AntiTooling);
15
19
  }
16
20
 
21
+ apply(tree: Node) {
22
+ super.apply(tree);
23
+
24
+ if (typeof this.fnName === "string") {
25
+ prepend(
26
+ tree,
27
+ new Template(`
28
+ function {fnName}(){
29
+ }
30
+ `).single({ fnName: this.fnName })
31
+ );
32
+ }
33
+ }
34
+
17
35
  match(object, parents) {
18
36
  return isBlock(object) || object.type == "SwitchCase";
19
37
  }
20
38
 
21
39
  transform(object, parents) {
22
40
  return () => {
23
- var exprs = [];
24
- var deleteExprs = [];
41
+ var exprs: Node[] = [];
42
+ var deleteExprs: Node[] = [];
25
43
 
26
- var body = object.type == "SwitchCase" ? object.consequent : object.body;
44
+ var body: Node[] =
45
+ object.type == "SwitchCase" ? object.consequent : object.body;
27
46
 
28
47
  const end = () => {
29
- function flatten(expr) {
48
+ function flatten(expr: Node) {
30
49
  if (expr.type == "ExpressionStatement") {
31
50
  flatten(expr.expression);
32
51
  } else if (expr.type == "SequenceExpression") {
@@ -41,13 +60,16 @@ export default class AntiTooling extends Transform {
41
60
 
42
61
  if (flattened.length > 1) {
43
62
  flattened[0] = { ...flattened[0] };
63
+
64
+ if (!this.fnName) {
65
+ this.fnName = this.getPlaceholder();
66
+ }
67
+
68
+ // (expr1,expr2,expr3) -> F(expr1, expr2, expr3)
44
69
  this.replace(
45
70
  exprs[0],
46
71
  ExpressionStatement(
47
- UnaryExpression(
48
- choice(["typeof", "void", "!"]),
49
- SequenceExpression(flattened)
50
- )
72
+ CallExpression(Identifier(this.fnName), [...flattened])
51
73
  )
52
74
  );
53
75
 
@@ -96,7 +96,7 @@ export default class Calculator extends Transform {
96
96
 
97
97
  prepend(
98
98
  tree,
99
- Template(`function {name}(a){
99
+ new Template(`function {name}(a){
100
100
  a = {b} + ({b}=a, 0);
101
101
  return a;
102
102
  }`).single({ name: this.calculatorSetOpFn, b: this.calculatorOpVar })
@@ -144,7 +144,9 @@ export default class Calculator extends Transform {
144
144
  return;
145
145
  }
146
146
  if (
147
- parents.find((x) => x.$dispatcherSkip || x.type == "BinaryExpression")
147
+ parents.find(
148
+ (x) => x.$multiTransformSkip || x.type == "BinaryExpression"
149
+ )
148
150
  ) {
149
151
  return;
150
152
  }
@@ -47,9 +47,9 @@ import {
47
47
  import { chance, choice, getRandomInteger, shuffle } from "../../util/random";
48
48
  import Transform from "../transform";
49
49
  import ExpressionObfuscation from "./expressionObfuscation";
50
- import { isModuleSource } from "../string/stringConcealing";
51
- import { reservedIdentifiers } from "../../constants";
52
- import { isDirective } from "../../util/compare";
50
+ import { reservedIdentifiers, variableFunctionName } from "../../constants";
51
+ import { isDirective, isModuleSource } from "../../util/compare";
52
+ import { isJSConfuserVar } from "../../util/guard";
53
53
 
54
54
  const flattenStructures = new Set([
55
55
  "IfStatement",
@@ -1367,7 +1367,7 @@ export default class ControlFlowFlattening extends Transform {
1367
1367
  VariableDeclaration(VariableDeclarator(tempVar, callExpression))
1368
1368
  );
1369
1369
 
1370
- const t = (str): Node => Template(str).single().expression;
1370
+ const t = (str): Node => new Template(str).single().expression;
1371
1371
 
1372
1372
  newStatements.push(
1373
1373
  IfStatement(
@@ -1571,6 +1571,7 @@ export default class ControlFlowFlattening extends Transform {
1571
1571
  !this.isDebug &&
1572
1572
  o.type === "Identifier" &&
1573
1573
  this.mangleIdentifiers &&
1574
+ !reservedIdentifiers.has(o.name) &&
1574
1575
  chance(50 - this.mangledExpressionsMade / 100) &&
1575
1576
  !p.find((x) => isVarContext(x))
1576
1577
  ) {
@@ -1585,6 +1586,11 @@ export default class ControlFlowFlattening extends Transform {
1585
1586
  return;
1586
1587
  }
1587
1588
 
1589
+ // Ignore __JS_CONFUSER_VAR__()
1590
+ if (isJSConfuserVar(p)) {
1591
+ return;
1592
+ }
1593
+
1588
1594
  // TYPEOF expression check
1589
1595
  if (
1590
1596
  p[0] &&
@@ -1896,7 +1902,8 @@ export default class ControlFlowFlattening extends Transform {
1896
1902
  shuffle(controlProperties);
1897
1903
  }
1898
1904
 
1899
- var discriminant = Template(`${stateVars.join("+")}`).single().expression;
1905
+ var discriminant = new Template(`${stateVars.join("+")}`).single()
1906
+ .expression;
1900
1907
 
1901
1908
  objectBody.length = 0;
1902
1909
  // Perverse position of import declarations
@@ -1,15 +1,48 @@
1
+ import { criticalFunctionTag } from "../../constants";
2
+ import Template from "../../templates/template";
1
3
  import { isBlock } from "../../traverse";
2
- import { Identifier, SequenceExpression } from "../../util/gen";
4
+ import {
5
+ CallExpression,
6
+ Identifier,
7
+ Node,
8
+ SequenceExpression,
9
+ } from "../../util/gen";
10
+ import { prepend } from "../../util/insert";
3
11
  import Transform from "../transform";
4
12
 
5
13
  /**
6
14
  * Expression Obfuscation runs before Control Flow Flattening
7
15
  */
8
16
  export default class ExpressionObfuscation extends Transform {
17
+ fnName: string;
18
+
9
19
  constructor(o) {
10
20
  super(o);
11
21
  }
12
22
 
23
+ apply(tree: Node): void {
24
+ super.apply(tree);
25
+
26
+ if (typeof this.fnName === "string") {
27
+ prepend(
28
+ tree,
29
+ new Template(`
30
+ function {fnName}(...args){
31
+ return args[args["length"] - 1]
32
+ }
33
+ `).single({ fnName: this.fnName })
34
+ );
35
+ }
36
+ }
37
+
38
+ createSequenceExpression(expressions: Node[]): Node {
39
+ if (!this.fnName) {
40
+ this.fnName = this.getPlaceholder() + criticalFunctionTag;
41
+ }
42
+
43
+ return CallExpression(Identifier(this.fnName), [...expressions]);
44
+ }
45
+
13
46
  match(object, parents) {
14
47
  return isBlock(object);
15
48
  }
@@ -54,12 +87,12 @@ export default class ExpressionObfuscation extends Transform {
54
87
  stmt.test.left.argument.type === "Identifier"
55
88
  ) // typeof is special
56
89
  ) {
57
- stmt.test.left.argument = SequenceExpression([
90
+ stmt.test.left.argument = this.createSequenceExpression([
58
91
  ...exprs,
59
92
  { ...stmt.test.left.argument },
60
93
  ]);
61
94
  } else {
62
- stmt.test.left = SequenceExpression([
95
+ stmt.test.left = this.createSequenceExpression([
63
96
  ...exprs,
64
97
  { ...stmt.test.left },
65
98
  ]);
@@ -70,12 +103,15 @@ export default class ExpressionObfuscation extends Transform {
70
103
  stmt.test.operator !== "**" &&
71
104
  stmt.test.left.left.type == "UnaryExpression"
72
105
  ) {
73
- stmt.test.left.left.argument = SequenceExpression([
106
+ stmt.test.left.left.argument = this.createSequenceExpression([
74
107
  ...exprs,
75
108
  { ...stmt.test.left.left.argument },
76
109
  ]);
77
110
  } else {
78
- stmt.test = SequenceExpression([...exprs, { ...stmt.test }]);
111
+ stmt.test = this.createSequenceExpression([
112
+ ...exprs,
113
+ { ...stmt.test },
114
+ ]);
79
115
  }
80
116
  deleteExprs.push(...exprs);
81
117
  } else if (
@@ -88,7 +124,7 @@ export default class ExpressionObfuscation extends Transform {
88
124
 
89
125
  if (init) {
90
126
  if (init.type == "VariableDeclaration") {
91
- init.declarations[0].init = SequenceExpression([
127
+ init.declarations[0].init = this.createSequenceExpression([
92
128
  ...exprs,
93
129
  {
94
130
  ...(init.declarations[0].init || Identifier("undefined")),
@@ -96,7 +132,7 @@ export default class ExpressionObfuscation extends Transform {
96
132
  ]);
97
133
  deleteExprs.push(...exprs);
98
134
  } else if (init.type == "AssignmentExpression") {
99
- init.right = SequenceExpression([
135
+ init.right = this.createSequenceExpression([
100
136
  ...exprs,
101
137
  {
102
138
  ...(init.right || Identifier("undefined")),
@@ -106,7 +142,7 @@ export default class ExpressionObfuscation extends Transform {
106
142
  }
107
143
  }
108
144
  } else if (stmt.type == "VariableDeclaration") {
109
- stmt.declarations[0].init = SequenceExpression([
145
+ stmt.declarations[0].init = this.createSequenceExpression([
110
146
  ...exprs,
111
147
  {
112
148
  ...(stmt.declarations[0].init || Identifier("undefined")),
@@ -114,13 +150,13 @@ export default class ExpressionObfuscation extends Transform {
114
150
  ]);
115
151
  deleteExprs.push(...exprs);
116
152
  } else if (stmt.type == "ThrowStatement") {
117
- stmt.argument = SequenceExpression([
153
+ stmt.argument = this.createSequenceExpression([
118
154
  ...exprs,
119
155
  { ...stmt.argument },
120
156
  ]);
121
157
  deleteExprs.push(...exprs);
122
158
  } else if (stmt.type == "ReturnStatement") {
123
- stmt.argument = SequenceExpression([
159
+ stmt.argument = this.createSequenceExpression([
124
160
  ...exprs,
125
161
  { ...(stmt.argument || Identifier("undefined")) },
126
162
  ]);
@@ -3,19 +3,24 @@ import { ComputeProbabilityMap } from "../probability";
3
3
  import Template from "../templates/template";
4
4
  import { isBlock } from "../traverse";
5
5
  import {
6
+ AssignmentExpression,
7
+ BinaryExpression,
8
+ ExpressionStatement,
6
9
  Identifier,
7
10
  IfStatement,
8
11
  Literal,
12
+ MemberExpression,
9
13
  Node,
14
+ ObjectExpression,
10
15
  VariableDeclaration,
11
16
  VariableDeclarator,
12
17
  } from "../util/gen";
13
18
  import { getBlockBody, isFunction, prepend } from "../util/insert";
14
- import { choice, getRandomInteger } from "../util/random";
19
+ import { chance, choice, getRandomInteger } from "../util/random";
15
20
  import Transform from "./transform";
16
21
 
17
22
  const templates = [
18
- Template(`
23
+ new Template(`
19
24
  function curCSS( elem, name, computed ) {
20
25
  var ret;
21
26
 
@@ -36,7 +41,7 @@ const templates = [
36
41
  ret + "" :
37
42
  ret;
38
43
  }`),
39
- Template(`
44
+ new Template(`
40
45
  function Example() {
41
46
  var state = redacted.useState(false);
42
47
  return x(
@@ -49,7 +54,7 @@ const templates = [
49
54
  );
50
55
  }`),
51
56
 
52
- Template(`
57
+ new Template(`
53
58
  const path = require('path');
54
59
  const { version } = require('../../package');
55
60
  const { version: dashboardPluginVersion } = require('@redacted/enterprise-plugin/package');
@@ -60,7 +65,7 @@ const resolveLocalRedactedPath = require('./resolve-local-redacted-path');
60
65
 
61
66
  const redactedPath = path.resolve(__dirname, '../redacted.js');`),
62
67
 
63
- Template(`
68
+ new Template(`
64
69
  module.exports = async (resolveLocalRedactedPath = ()=>{throw new Error("No redacted path provided")}) => {
65
70
  const cliParams = new Set(process.argv.slice(2));
66
71
  if (!cliParams.has('--version')) {
@@ -76,7 +81,7 @@ module.exports = async (resolveLocalRedactedPath = ()=>{throw new Error("No reda
76
81
 
77
82
  return true;
78
83
  };`),
79
- Template(`
84
+ new Template(`
80
85
  function setCookie(cname, cvalue, exdays) {
81
86
  var d = new Date();
82
87
  d.setTime(d.getTime() + (exdays*24*60*60*1000));
@@ -84,7 +89,7 @@ function setCookie(cname, cvalue, exdays) {
84
89
  document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
85
90
  }`),
86
91
 
87
- Template(`function getCookie(cname) {
92
+ new Template(`function getCookie(cname) {
88
93
  var name = cname + "=";
89
94
  var decodedCookie = decodeURIComponent(document.cookie);
90
95
  var ca = decodedCookie.split(';');
@@ -100,7 +105,7 @@ function setCookie(cname, cvalue, exdays) {
100
105
  return "";
101
106
  }`),
102
107
 
103
- Template(`function getLocalStorageValue(key, cb){
108
+ new Template(`function getLocalStorageValue(key, cb){
104
109
  if ( typeof key !== "string" ) {
105
110
  throw new Error("Invalid data key provided (not type string)")
106
111
  }
@@ -116,7 +121,7 @@ function setCookie(cname, cvalue, exdays) {
116
121
 
117
122
  cb(null, value)
118
123
  }`),
119
- Template(`
124
+ new Template(`
120
125
 
121
126
  var __ = "(c=ak(<~F$VU'9f)~><&85dBPL-module/from";
122
127
  var s = "q:function(){var ad=ad=>b(ad-29);if(!T.r[(typeof ab==ad(123)?";
@@ -124,7 +129,7 @@ function setCookie(cname, cvalue, exdays) {
124
129
 
125
130
  __.match(s + g);
126
131
  `),
127
- Template(`
132
+ new Template(`
128
133
  function vec_pack(vec) {
129
134
  return vec[1] * 67108864 + (vec[0] < 0 ? 33554432 | vec[0] : vec[0]);
130
135
  }
@@ -161,7 +166,7 @@ function setCookie(cname, cvalue, exdays) {
161
166
  console.log(vec_unpack(e)); // [4, 8]
162
167
  console.log(vec_unpack(f)); // [2, 4]
163
168
  `),
164
- Template(`
169
+ new Template(`
165
170
  function buildCharacterMap(str) {
166
171
  const characterMap = {};
167
172
 
@@ -188,10 +193,6 @@ function setCookie(cname, cvalue, exdays) {
188
193
  return true;
189
194
  }
190
195
 
191
- /**
192
- * @param {TreeNode} root
193
- * @return {boolean}
194
- */
195
196
  function isBalanced(root) {
196
197
  const height = getHeightBalanced(root);
197
198
  return height !== Infinity;
@@ -226,7 +227,7 @@ function setCookie(cname, cvalue, exdays) {
226
227
  getHeightBalanced,
227
228
  };
228
229
  `),
229
- Template(`
230
+ new Template(`
230
231
  function ListNode(){}
231
232
  var addTwoNumbers = function(l1, l2) {
232
233
  var carry = 0;
@@ -249,7 +250,7 @@ function setCookie(cname, cvalue, exdays) {
249
250
 
250
251
  console.log(addTwoNumbers)
251
252
  `),
252
- Template(`
253
+ new Template(`
253
254
  var threeSum = function(nums) {
254
255
  var len = nums.length;
255
256
  var res = [];
@@ -278,7 +279,7 @@ function setCookie(cname, cvalue, exdays) {
278
279
  };
279
280
  console.log(threeSum)
280
281
  `),
281
- Template(`
282
+ new Template(`
282
283
  var combinationSum2 = function(candidates, target) {
283
284
  var res = [];
284
285
  var len = candidates.length;
@@ -302,7 +303,7 @@ function setCookie(cname, cvalue, exdays) {
302
303
 
303
304
  console.log(combinationSum2);
304
305
  `),
305
- Template(`
306
+ new Template(`
306
307
  var isScramble = function(s1, s2) {
307
308
  return helper({}, s1, s2);
308
309
  };
@@ -343,7 +344,7 @@ function setCookie(cname, cvalue, exdays) {
343
344
 
344
345
  console.log(isScramble);
345
346
  `),
346
- Template(`
347
+ new Template(`
347
348
  var candy = function(ratings) {
348
349
  var len = ratings.length;
349
350
  var res = [];
@@ -360,7 +361,7 @@ function setCookie(cname, cvalue, exdays) {
360
361
 
361
362
  console.log(candy)
362
363
  `),
363
- Template(`
364
+ new Template(`
364
365
  var maxPoints = function(points) {
365
366
  var max = 0;
366
367
  var map = {};
@@ -391,7 +392,7 @@ function setCookie(cname, cvalue, exdays) {
391
392
 
392
393
  console.log(maxPoints)
393
394
  `),
394
- Template(`
395
+ new Template(`
395
396
  var maximumGap = function(nums) {
396
397
  var len = nums.length;
397
398
  if (len < 2) return 0;
@@ -425,10 +426,7 @@ function setCookie(cname, cvalue, exdays) {
425
426
 
426
427
  console.log(maximumGap);
427
428
  `),
428
- Template(`
429
- /**
430
- * @param {number} capacity
431
- */
429
+ new Template(`
432
430
  var LRUCache = function(capacity) {
433
431
  this.capacity = capacity;
434
432
  this.length = 0;
@@ -437,10 +435,6 @@ function setCookie(cname, cvalue, exdays) {
437
435
  this.tail = null;
438
436
  };
439
437
 
440
- /**
441
- * @param {number} key
442
- * @return {number}
443
- */
444
438
  LRUCache.prototype.get = function(key) {
445
439
  var node = this.map[key];
446
440
  if (node) {
@@ -452,11 +446,6 @@ function setCookie(cname, cvalue, exdays) {
452
446
  }
453
447
  };
454
448
 
455
- /**
456
- * @param {number} key
457
- * @param {number} value
458
- * @return {void}
459
- */
460
449
  LRUCache.prototype.put = function(key, value) {
461
450
  if (this.map[key]) {
462
451
  this.remove(this.map[key]);
@@ -504,7 +493,7 @@ function setCookie(cname, cvalue, exdays) {
504
493
 
505
494
  console.log(LRUCache);
506
495
  `),
507
- Template(`
496
+ new Template(`
508
497
  var isInterleave = function(s1, s2, s3) {
509
498
  var dp = {};
510
499
  if (s3.length !== s1.length + s2.length) return false;
@@ -532,7 +521,7 @@ function setCookie(cname, cvalue, exdays) {
532
521
 
533
522
  console.log(isInterleave);
534
523
  `),
535
- Template(`
524
+ new Template(`
536
525
  var solveNQueens = function(n) {
537
526
  var res = [];
538
527
  if (n === 1 || n >= 4) dfs(res, [], n, 0);
@@ -587,6 +576,9 @@ function setCookie(cname, cvalue, exdays) {
587
576
  export default class DeadCode extends Transform {
588
577
  made: number;
589
578
 
579
+ compareObjectName: string;
580
+ gen = this.getGenerator("randomized");
581
+
590
582
  constructor(o) {
591
583
  super(o, ObfuscateOrder.DeadCode);
592
584
 
@@ -597,7 +589,8 @@ export default class DeadCode extends Transform {
597
589
  return (
598
590
  isFunction(object) &&
599
591
  isBlock(object.body) &&
600
- !parents.find((x) => x.$dispatcherSkip)
592
+ !object.$multiTransformSkip &&
593
+ !parents.find((x) => x.$multiTransformSkip)
601
594
  );
602
595
  }
603
596
 
@@ -624,17 +617,56 @@ export default class DeadCode extends Transform {
624
617
 
625
618
  var index = getRandomInteger(safeOffset, body.length);
626
619
 
620
+ if (!this.compareObjectName) {
621
+ this.compareObjectName = this.getPlaceholder();
622
+
623
+ prepend(
624
+ parents[parents.length - 1] || object,
625
+ VariableDeclaration(
626
+ VariableDeclarator(
627
+ this.compareObjectName,
628
+ new Template(`Object["create"](null)`).single().expression
629
+ )
630
+ )
631
+ );
632
+ }
633
+
627
634
  var name = this.getPlaceholder();
628
635
  var variableDeclaration = VariableDeclaration(
629
- VariableDeclarator(name, Literal(false))
636
+ VariableDeclarator(
637
+ name,
638
+ BinaryExpression(
639
+ "in",
640
+ Literal(this.gen.generate()),
641
+ Identifier(this.compareObjectName)
642
+ )
643
+ )
630
644
  );
631
645
 
632
- var template;
646
+ var template: Template;
633
647
  do {
634
648
  template = choice(templates);
635
- } while (this.options.es5 && template.source.includes("async"));
649
+ } while (this.options.es5 && template.templates[0].includes("async"));
650
+
651
+ var nodes = template.compile();
652
+
653
+ if (chance(50)) {
654
+ nodes.unshift(
655
+ ExpressionStatement(
656
+ AssignmentExpression(
657
+ "=",
658
+ MemberExpression(
659
+ Identifier(this.compareObjectName),
660
+ Literal(this.gen.generate()),
661
+ true
662
+ ),
663
+ Literal(this.gen.generate())
664
+ )
665
+ )
666
+ );
667
+ }
636
668
 
637
- var ifStatement = IfStatement(Identifier(name), template.compile(), null);
669
+ var ifStatement = IfStatement(Identifier(name), nodes, null);
638
670
 
639
671
  body.splice(index, 0, ifStatement);
640
672