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
@@ -7,25 +7,26 @@ import {
7
7
  Identifier,
8
8
  Literal,
9
9
  BinaryExpression,
10
- LogicalExpression,
11
10
  SwitchCase,
12
11
  SwitchStatement,
13
- SequenceExpression,
14
12
  AssignmentExpression,
15
13
  VariableDeclaration,
16
14
  VariableDeclarator,
17
- ExpressionStatement,
15
+ UnaryExpression,
18
16
  } from "../util/gen";
19
17
  import { prepend } from "../util/insert";
20
- import { getBlock } from "../traverse";
21
18
  import { choice, getRandomInteger } from "../util/random";
22
19
  import { ObfuscateOrder } from "../order";
23
20
  import { ok } from "assert";
24
21
  import { OPERATOR_PRECEDENCE } from "../precedence";
25
22
  import Template from "../templates/template";
23
+ import { ComputeProbabilityMap } from "../probability";
24
+
25
+ const allowedBinaryOperators = new Set(["+", "-", "*", "/"]);
26
+ const allowedUnaryOperators = new Set(["!", "void", "typeof", "-", "~", "+"]);
26
27
 
27
28
  export default class Calculator extends Transform {
28
- gen: any;
29
+ gen: ReturnType<Transform["getGenerator"]>;
29
30
  ops: { [operator: string]: number };
30
31
  statesUsed: Set<string>;
31
32
  calculatorFn: string;
@@ -37,7 +38,7 @@ export default class Calculator extends Transform {
37
38
 
38
39
  this.ops = Object.create(null);
39
40
  this.statesUsed = new Set();
40
- this.calculatorFn = this.getPlaceholder();
41
+ this.calculatorFn = this.getPlaceholder() + "_calc";
41
42
  this.calculatorOpVar = this.getPlaceholder();
42
43
  this.calculatorSetOpFn = this.getPlaceholder();
43
44
 
@@ -55,19 +56,29 @@ export default class Calculator extends Transform {
55
56
  var rightArg = this.getPlaceholder();
56
57
  var switchCases = [];
57
58
 
58
- Object.keys(this.ops).forEach((operator) => {
59
- var code = this.ops[operator];
60
-
61
- var factory =
62
- operator == "&&" || operator == "||"
63
- ? LogicalExpression
64
- : BinaryExpression;
65
-
66
- var body = [
67
- ReturnStatement(
68
- factory(operator, Identifier(leftArg), Identifier(rightArg))
69
- ),
70
- ];
59
+ Object.keys(this.ops).forEach((opKey) => {
60
+ var [type, operator] = opKey.split("_");
61
+
62
+ var code = this.ops[opKey];
63
+ var body = [];
64
+
65
+ if (type === "Binary") {
66
+ body = [
67
+ ReturnStatement(
68
+ BinaryExpression(
69
+ operator,
70
+ Identifier(leftArg),
71
+ Identifier(rightArg)
72
+ )
73
+ ),
74
+ ];
75
+ } else if (type === "Unary") {
76
+ body = [
77
+ ReturnStatement(UnaryExpression(operator, Identifier(leftArg))),
78
+ ];
79
+ } else {
80
+ throw new Error("Unknown type: " + type);
81
+ }
71
82
 
72
83
  switchCases.push(SwitchCase(Literal(code), body));
73
84
  });
@@ -95,70 +106,122 @@ export default class Calculator extends Transform {
95
106
  }
96
107
 
97
108
  match(object: Node, parents: Node[]) {
98
- return object.type == "BinaryExpression";
109
+ return (
110
+ object.type === "BinaryExpression" || object.type === "UnaryExpression"
111
+ );
99
112
  }
100
113
 
101
114
  transform(object: Node, parents: Node[]) {
102
- var operator = object.operator;
103
- var allowedOperators = new Set(["+", "-", "*", "/"]);
104
- if (!allowedOperators.has(operator)) {
115
+ // Allow percentage
116
+ if (!ComputeProbabilityMap(this.options.calculator)) {
105
117
  return;
106
118
  }
107
119
 
108
- var myPrecedence =
109
- OPERATOR_PRECEDENCE[operator] +
110
- Object.keys(OPERATOR_PRECEDENCE).indexOf(operator) / 100;
111
- var precedences = parents.map(
112
- (x) =>
113
- x.type == "BinaryExpression" &&
114
- OPERATOR_PRECEDENCE[x.operator] +
115
- Object.keys(OPERATOR_PRECEDENCE).indexOf(x.operator) / 100
116
- );
120
+ var operator = object.operator;
117
121
 
118
- // corrupt AST
119
- if (precedences.find((x) => x >= myPrecedence)) {
120
- return;
122
+ var type;
123
+
124
+ if (object.type === "BinaryExpression") {
125
+ type = "Binary";
126
+
127
+ if (!allowedBinaryOperators.has(operator)) {
128
+ return;
129
+ }
130
+
131
+ // Additional checks to ensure complex expressions still work
132
+ var myPrecedence =
133
+ OPERATOR_PRECEDENCE[operator] +
134
+ Object.keys(OPERATOR_PRECEDENCE).indexOf(operator) / 100;
135
+ var precedences = parents.map(
136
+ (x) =>
137
+ x.type == "BinaryExpression" &&
138
+ OPERATOR_PRECEDENCE[x.operator] +
139
+ Object.keys(OPERATOR_PRECEDENCE).indexOf(x.operator) / 100
140
+ );
141
+
142
+ // corrupt AST
143
+ if (precedences.find((x) => x >= myPrecedence)) {
144
+ return;
145
+ }
146
+ if (
147
+ parents.find((x) => x.$dispatcherSkip || x.type == "BinaryExpression")
148
+ ) {
149
+ return;
150
+ }
121
151
  }
122
- if (
123
- parents.find((x) => x.$dispatcherSkip || x.type == "BinaryExpression")
124
- ) {
125
- return;
152
+
153
+ if (object.type === "UnaryExpression") {
154
+ type = "Unary";
155
+
156
+ if (!allowedUnaryOperators.has(operator)) {
157
+ return;
158
+ }
159
+
160
+ // Typeof expression fix
161
+ if (operator === "typeof" && object.argument.type === "Identifier") {
162
+ // `typeof name` is special because it can reference the variable `name` without
163
+ // throwing any errors. If changed, an error could be thrown, breaking the users code
164
+ return;
165
+ }
126
166
  }
127
167
 
128
168
  return () => {
129
- if (typeof this.ops[operator] !== "number") {
169
+ const opKey = type + "_" + operator;
170
+
171
+ if (typeof this.ops[opKey] !== "number") {
130
172
  var newState;
131
173
  do {
132
174
  newState = getRandomInteger(
133
- -1000,
134
- 1000 + Object.keys(this.ops).length * 5
175
+ -50,
176
+ 50 + Object.keys(this.ops).length * 5
135
177
  );
136
178
  } while (this.statesUsed.has(newState));
137
179
 
138
180
  ok(!isNaN(newState));
139
181
 
140
182
  this.statesUsed.add(newState);
141
- this.ops[operator] = newState;
142
- this.log(operator, `calc(${newState}, left, right)`);
183
+ this.ops[opKey] = newState;
184
+
185
+ if (type === "Binary") {
186
+ this.log(
187
+ `left ${operator} right ->`,
188
+ `${this.calculatorFn}((${newState}, left, right)`
189
+ );
190
+ } else if (type === "Unary") {
191
+ this.log(
192
+ `${operator}(argument) ->`,
193
+ `${this.calculatorFn}(${newState}, argument)`
194
+ );
195
+ }
143
196
  }
144
197
 
145
- this.replace(
146
- object,
147
- CallExpression(Identifier(this.calculatorFn), [
198
+ // The operator expression sets the operator to be used
199
+ var operatorExpression = choice([
200
+ AssignmentExpression(
201
+ "=",
202
+ Identifier(this.calculatorOpVar),
203
+ Literal(this.ops[opKey])
204
+ ),
205
+ CallExpression(Identifier(this.calculatorSetOpFn), [
206
+ Literal(this.ops[opKey]),
207
+ ]),
208
+ ]);
209
+
210
+ var newExpression;
211
+ if (type === "Binary") {
212
+ newExpression = CallExpression(Identifier(this.calculatorFn), [
148
213
  object.left,
149
214
  object.right,
150
- choice([
151
- AssignmentExpression(
152
- "=",
153
- Identifier(this.calculatorOpVar),
154
- Literal(this.ops[operator])
155
- ),
156
- CallExpression(Identifier(this.calculatorSetOpFn), [
157
- Literal(this.ops[operator]),
158
- ]),
159
- ]),
160
- ])
161
- );
215
+ operatorExpression,
216
+ ]);
217
+ } else {
218
+ newExpression = CallExpression(Identifier(this.calculatorFn), [
219
+ object.argument,
220
+ operatorExpression,
221
+ ]);
222
+ }
223
+
224
+ this.replace(object, newExpression);
162
225
  };
163
226
  }
164
227
  }