js-confuser 1.5.8 → 1.6.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 (139) hide show
  1. package/.github/workflows/node.js.yml +2 -2
  2. package/CHANGELOG.md +69 -0
  3. package/README.md +143 -7
  4. package/dist/index.js +33 -4
  5. package/dist/obfuscator.js +30 -31
  6. package/dist/options.js +4 -5
  7. package/dist/order.js +4 -6
  8. package/dist/probability.js +2 -4
  9. package/dist/templates/bufferToString.js +13 -0
  10. package/dist/templates/crash.js +2 -2
  11. package/dist/templates/es5.js +18 -0
  12. package/dist/transforms/antiTooling.js +1 -1
  13. package/dist/transforms/calculator.js +77 -21
  14. package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +980 -367
  15. package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +8 -3
  16. package/dist/transforms/controlFlowFlattening/switchCaseObfuscation.js +25 -26
  17. package/dist/transforms/deadCode.js +33 -25
  18. package/dist/transforms/dispatcher.js +7 -6
  19. package/dist/transforms/es5/antiClass.js +6 -2
  20. package/dist/transforms/es5/antiDestructuring.js +3 -1
  21. package/dist/transforms/es5/es5.js +31 -34
  22. package/dist/transforms/eval.js +11 -0
  23. package/dist/transforms/extraction/duplicateLiteralsRemoval.js +8 -5
  24. package/dist/transforms/extraction/objectExtraction.js +6 -1
  25. package/dist/transforms/finalizer.js +82 -0
  26. package/dist/transforms/flatten.js +82 -55
  27. package/dist/transforms/hexadecimalNumbers.js +34 -9
  28. package/dist/transforms/identifier/globalAnalysis.js +88 -0
  29. package/dist/transforms/identifier/globalConcealing.js +10 -83
  30. package/dist/transforms/identifier/movedDeclarations.js +2 -8
  31. package/dist/transforms/identifier/renameVariables.js +39 -27
  32. package/dist/transforms/identifier/variableAnalysis.js +58 -62
  33. package/dist/transforms/minify.js +80 -61
  34. package/dist/transforms/opaquePredicates.js +1 -1
  35. package/dist/transforms/preparation/preparation.js +2 -2
  36. package/dist/transforms/preparation.js +231 -0
  37. package/dist/transforms/renameLabels.js +1 -1
  38. package/dist/transforms/rgf.js +4 -5
  39. package/dist/transforms/stack.js +87 -26
  40. package/dist/transforms/string/encoding.js +150 -179
  41. package/dist/transforms/string/stringCompression.js +14 -15
  42. package/dist/transforms/string/stringConcealing.js +25 -8
  43. package/dist/transforms/string/stringEncoding.js +13 -24
  44. package/dist/transforms/transform.js +11 -18
  45. package/dist/traverse.js +24 -18
  46. package/dist/util/compare.js +2 -2
  47. package/dist/util/gen.js +15 -0
  48. package/dist/util/insert.js +31 -7
  49. package/dist/util/random.js +15 -0
  50. package/package.json +5 -5
  51. package/src/index.ts +57 -19
  52. package/src/obfuscator.ts +26 -29
  53. package/src/options.ts +17 -21
  54. package/src/order.ts +4 -8
  55. package/src/probability.ts +2 -3
  56. package/src/templates/bufferToString.ts +68 -0
  57. package/src/templates/crash.ts +5 -9
  58. package/src/templates/es5.ts +131 -0
  59. package/src/transforms/antiTooling.ts +1 -1
  60. package/src/transforms/calculator.ts +122 -59
  61. package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +1583 -571
  62. package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +18 -3
  63. package/src/transforms/deadCode.ts +383 -26
  64. package/src/transforms/dispatcher.ts +8 -6
  65. package/src/transforms/es5/antiClass.ts +10 -1
  66. package/src/transforms/es5/antiDestructuring.ts +3 -1
  67. package/src/transforms/es5/es5.ts +32 -77
  68. package/src/transforms/eval.ts +18 -0
  69. package/src/transforms/extraction/duplicateLiteralsRemoval.ts +9 -6
  70. package/src/transforms/extraction/objectExtraction.ts +12 -5
  71. package/src/transforms/finalizer.ts +75 -0
  72. package/src/transforms/flatten.ts +194 -151
  73. package/src/transforms/identifier/globalAnalysis.ts +85 -0
  74. package/src/transforms/identifier/globalConcealing.ts +14 -103
  75. package/src/transforms/identifier/movedDeclarations.ts +4 -11
  76. package/src/transforms/identifier/renameVariables.ts +37 -30
  77. package/src/transforms/identifier/variableAnalysis.ts +66 -73
  78. package/src/transforms/minify.ts +116 -77
  79. package/src/transforms/opaquePredicates.ts +2 -2
  80. package/src/transforms/preparation.ts +238 -0
  81. package/src/transforms/renameLabels.ts +2 -2
  82. package/src/transforms/rgf.ts +6 -7
  83. package/src/transforms/stack.ts +97 -37
  84. package/src/transforms/string/encoding.ts +115 -212
  85. package/src/transforms/string/stringCompression.ts +27 -18
  86. package/src/transforms/string/stringConcealing.ts +41 -11
  87. package/src/transforms/string/stringEncoding.ts +18 -18
  88. package/src/transforms/transform.ts +15 -21
  89. package/src/traverse.ts +24 -12
  90. package/src/types.ts +11 -2
  91. package/src/util/compare.ts +2 -2
  92. package/src/util/gen.ts +21 -1
  93. package/src/util/insert.ts +49 -9
  94. package/src/util/random.ts +13 -0
  95. package/test/code/Cash.test.ts +1 -1
  96. package/test/code/Dynamic.test.ts +12 -10
  97. package/test/code/ES6.src.js +136 -0
  98. package/test/code/ES6.test.ts +28 -2
  99. package/test/code/NewFeatures.test.ts +19 -0
  100. package/test/index.test.ts +15 -2
  101. package/test/probability.test.ts +44 -0
  102. package/test/templates/template.test.ts +1 -1
  103. package/test/transforms/antiTooling.test.ts +52 -0
  104. package/test/transforms/calculator.test.ts +40 -0
  105. package/test/transforms/controlFlowFlattening/controlFlowFlattening.test.ts +713 -149
  106. package/test/transforms/controlFlowFlattening/expressionObfuscation.test.ts +173 -0
  107. package/test/transforms/deadCode.test.ts +66 -15
  108. package/test/transforms/dispatcher.test.ts +44 -1
  109. package/test/transforms/es5/antiClass.test.ts +33 -0
  110. package/test/transforms/es5/antiDestructuring.test.ts +16 -0
  111. package/test/transforms/eval.test.ts +53 -0
  112. package/test/transforms/extraction/objectExtraction.test.ts +21 -0
  113. package/test/transforms/flatten.test.ts +195 -3
  114. package/test/transforms/identifier/movedDeclarations.test.ts +27 -0
  115. package/test/transforms/identifier/renameVariables.test.ts +108 -0
  116. package/test/transforms/lock/antiDebug.test.ts +2 -2
  117. package/test/transforms/minify.test.ts +151 -0
  118. package/test/transforms/preparation.test.ts +157 -0
  119. package/test/transforms/rgf.test.ts +56 -29
  120. package/test/transforms/stack.test.ts +91 -21
  121. package/test/transforms/string/stringCompression.test.ts +39 -0
  122. package/test/transforms/string/stringConcealing.test.ts +115 -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/compare.test.ts +23 -1
  127. package/src/transforms/controlFlowFlattening/choiceFlowObfuscation.ts +0 -87
  128. package/src/transforms/controlFlowFlattening/controlFlowObfuscation.ts +0 -203
  129. package/src/transforms/controlFlowFlattening/switchCaseObfuscation.ts +0 -130
  130. package/src/transforms/hexadecimalNumbers.ts +0 -31
  131. package/src/transforms/hideInitializingCode.ts +0 -432
  132. package/src/transforms/label.ts +0 -64
  133. package/src/transforms/preparation/nameConflicts.ts +0 -102
  134. package/src/transforms/preparation/preparation.ts +0 -176
  135. package/test/transforms/controlFlowFlattening/controlFlowObfuscation.test.ts +0 -101
  136. package/test/transforms/controlFlowFlattening/switchCaseObfuscation.test.ts +0 -120
  137. package/test/transforms/hideInitializingCode.test.ts +0 -336
  138. package/test/transforms/preparation/nameConflicts.test.ts +0 -52
  139. package/test/transforms/preparation/preparation.test.ts +0 -62
@@ -1,14 +1,6 @@
1
1
  import Template from "./template";
2
2
 
3
3
  export const CrashTemplate1 = Template(`
4
- try {
5
- if(typeof process !== "undefined") {
6
- Math.random() > 0.5 && process && process.exit();
7
- }
8
- } catch ( e ) {
9
-
10
- }
11
-
12
4
  var {var} = "a";
13
5
  while(1){
14
6
  {var} = {var} += "a"; //add as much as the browser can handle
@@ -17,12 +9,16 @@ while(1){
17
9
 
18
10
  export const CrashTemplate2 = Template(`
19
11
  while(true) {
20
- for(var {var} = 99; {var} == {var}; {var} *= {var}) {
12
+ var {var} = 99;
13
+ for({var} = 99; {var} == {var}; {var} *= {var}) {
21
14
  !{var} && console.log({var});
22
15
  if ({var} <= 10){
23
16
  break;
24
17
  }
25
18
  };
19
+ if({var} === 100) {
20
+ {var}--
21
+ }
26
22
  };`);
27
23
 
28
24
  export const CrashTemplate3 = Template(`
@@ -0,0 +1,131 @@
1
+ import Template from "./template";
2
+
3
+ /**
4
+ * Provides ES5 polyfills for Array methods
5
+ *
6
+ * Source: https://vanillajstoolkit.com/polyfills/
7
+ */
8
+ export const ES5Template = Template(`
9
+ if (!Array.prototype.forEach) {
10
+ Array.prototype.forEach = function forEach (callback, thisArg) {
11
+ if (typeof callback !== 'function') {
12
+ throw new TypeError(callback + ' is not a function');
13
+ }
14
+ var array = this;
15
+ thisArg = thisArg || this;
16
+ for (var i = 0, l = array.length; i !== l; ++i) {
17
+ callback.call(thisArg, array[i], i, array);
18
+ }
19
+ };
20
+ }
21
+ if (!Array.prototype.filter)
22
+ Array.prototype.filter = function(func, thisArg) {
23
+ 'use strict';
24
+ if ( ! ((typeof func === 'Function' || typeof func === 'function') && this) )
25
+ throw new TypeError();
26
+
27
+ var len = this.length >>> 0,
28
+ res = new Array(len), // preallocate array
29
+ t = this, c = 0, i = -1;
30
+ if (thisArg === undefined)
31
+ while (++i !== len)
32
+ // checks to see if the key was set
33
+ if (i in this)
34
+ if (func(t[i], i, t))
35
+ res[c++] = t[i];
36
+ else
37
+ while (++i !== len)
38
+ // checks to see if the key was set
39
+ if (i in this)
40
+ if (func.call(thisArg, t[i], i, t))
41
+ res[c++] = t[i];
42
+
43
+ res.length = c; // shrink down array to proper size
44
+ return res;
45
+ };
46
+ if (!Array.prototype.map) {
47
+ Array.prototype.map = function(callback, thisArg) {
48
+ var T, A, k;
49
+
50
+ if (this == null) {
51
+ throw new TypeError('this is null or not defined');
52
+ }
53
+
54
+ // 1. Let O be the result of calling ToObject passing the |this|
55
+ // value as the argument.
56
+ var O = Object(this);
57
+
58
+ // 2. Let lenValue be the result of calling the Get internal
59
+ // method of O with the argument "length".
60
+ // 3. Let len be ToUint32(lenValue).
61
+ var len = O.length >>> 0;
62
+
63
+ // 4. If IsCallable(callback) is false, throw a TypeError exception.
64
+ // See: http://es5.github.com/#x9.11
65
+ if (typeof callback !== 'function') {
66
+ throw new TypeError(callback + ' is not a function');
67
+ }
68
+
69
+ // 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
70
+ if (arguments.length > 1) {
71
+ T = arguments[1];
72
+ }
73
+
74
+ // 6. Let A be a new array created as if by the expression new Array(len)
75
+ // where Array is the standard built-in constructor with that name and
76
+ // len is the value of len.
77
+ A = new Array(len);
78
+
79
+ // 7. Let k be 0
80
+ k = 0;
81
+
82
+ // 8. Repeat, while k < len
83
+ while (k < len) {
84
+
85
+ var kValue, mappedValue;
86
+
87
+ // a. Let Pk be ToString(k).
88
+ // This is implicit for LHS operands of the in operator
89
+ // b. Let kPresent be the result of calling the HasProperty internal
90
+ // method of O with argument Pk.
91
+ // This step can be combined with c
92
+ // c. If kPresent is true, then
93
+ if (k in O) {
94
+
95
+ // i. Let kValue be the result of calling the Get internal
96
+ // method of O with argument Pk.
97
+ kValue = O[k];
98
+
99
+ // ii. Let mappedValue be the result of calling the Call internal
100
+ // method of callback with T as the this value and argument
101
+ // list containing kValue, k, and O.
102
+ mappedValue = callback.call(T, kValue, k, O);
103
+
104
+ // iii. Call the DefineOwnProperty internal method of A with arguments
105
+ // Pk, Property Descriptor
106
+ // { Value: mappedValue,
107
+ // Writable: true,
108
+ // Enumerable: true,
109
+ // Configurable: true },
110
+ // and false.
111
+
112
+ // In browsers that support Object.defineProperty, use the following:
113
+ // Object.defineProperty(A, k, {
114
+ // value: mappedValue,
115
+ // writable: true,
116
+ // enumerable: true,
117
+ // configurable: true
118
+ // });
119
+
120
+ // For best browser support, use the following:
121
+ A[k] = mappedValue;
122
+ }
123
+ // d. Increase k by 1.
124
+ k++;
125
+ }
126
+
127
+ // 9. return A
128
+ return A;
129
+ };
130
+ }
131
+ `);
@@ -45,7 +45,7 @@ export default class AntiTooling extends Transform {
45
45
  exprs[0],
46
46
  ExpressionStatement(
47
47
  UnaryExpression(
48
- choice(["typeof", "void", "~", "!", "+"]),
48
+ choice(["typeof", "void", "!"]),
49
49
  SequenceExpression(flattened)
50
50
  )
51
51
  )
@@ -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
  }