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
@@ -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
- }
@@ -28,6 +28,24 @@ export default class Eval extends Transform {
28
28
  }
29
29
 
30
30
  transform(object, parents) {
31
+ // Don't apply to getter/setters or class methods
32
+ if (parents[0]) {
33
+ if (
34
+ parents[0].type === "MethodDefinition" &&
35
+ parents[0].value === object
36
+ ) {
37
+ return;
38
+ }
39
+
40
+ if (
41
+ parents[0].type === "Property" &&
42
+ parents[0].value === object &&
43
+ (parents[0].kind !== "init" || parents[0].method)
44
+ ) {
45
+ return;
46
+ }
47
+ }
48
+
31
49
  if (
32
50
  !ComputeProbabilityMap(
33
51
  this.options.eval,
@@ -28,7 +28,7 @@ import { ObfuscateOrder } from "../../order";
28
28
  import { isModuleSource } from "../string/stringConcealing";
29
29
  import { ComputeProbabilityMap } from "../../probability";
30
30
  import { ok } from "assert";
31
- import { choice, getRandomInteger } from "../../util/random";
31
+ import { chance, choice, getRandomInteger } from "../../util/random";
32
32
 
33
33
  /**
34
34
  * [Duplicate Literals Removal](https://docs.jscrambler.com/code-integrity/documentation/transformations/duplicate-literals-removal) replaces duplicate literals with a variable name.
@@ -159,7 +159,7 @@ export default class DuplicateLiteralsRemoval extends Transform {
159
159
  var body = [];
160
160
  var thisShift = getRandomInteger(-250, 250);
161
161
  // the name of the getter
162
- getterName = this.getPlaceholder();
162
+ getterName = this.getPlaceholder() + "_dLR_" + this.fnGetters.size;
163
163
 
164
164
  if (basedOn) {
165
165
  var shift = this.fnShifts.get(basedOn);
@@ -233,6 +233,9 @@ export default class DuplicateLiteralsRemoval extends Transform {
233
233
  return;
234
234
  }
235
235
 
236
+ // HARD CODED LIMIT of 10,000 (after 1,000 elements)
237
+ if (this.map.size > 1000 && !chance(this.map.size / 100)) return;
238
+
236
239
  if (
237
240
  this.arrayName &&
238
241
  parents[0].object &&
@@ -268,20 +271,20 @@ export default class DuplicateLiteralsRemoval extends Transform {
268
271
  this.arrayExpression = ArrayExpression([]);
269
272
  }
270
273
 
271
- var first = this.first.get(value);
272
- if (first) {
274
+ var firstLocation = this.first.get(value);
275
+ if (firstLocation) {
273
276
  this.first.set(value, null);
274
277
  var index = this.map.size;
275
278
 
276
279
  ok(!this.map.has(value));
277
280
  this.map.set(value, index);
278
281
 
279
- this.toCaller(first[0], first[1], index);
280
-
281
282
  var pushing = clone(object);
282
283
  this.arrayExpression.elements.push(pushing);
283
284
 
284
285
  ok(this.arrayExpression.elements[index] === pushing);
286
+
287
+ this.toCaller(firstLocation[0], firstLocation[1], index);
285
288
  }
286
289
 
287
290
  var index = this.map.get(value);
@@ -100,11 +100,18 @@ export default class ObjectExtraction extends Transform {
100
100
  );
101
101
 
102
102
  if (nonInitOrComputed) {
103
- this.log(
104
- name +
105
- " has non-init/computed property: " +
106
- nonInitOrComputed.key.name || nonInitOrComputed.key.value
107
- );
103
+ if (nonInitOrComputed.key) {
104
+ this.log(
105
+ name +
106
+ " has non-init/computed property: " +
107
+ nonInitOrComputed.key.name || nonInitOrComputed.key.value
108
+ );
109
+ } else {
110
+ this.log(
111
+ name + " has spread-element or other type of property"
112
+ );
113
+ }
114
+
108
115
  illegal.add(name);
109
116
  return;
110
117
  } else {
@@ -0,0 +1,75 @@
1
+ import { ObfuscateOrder } from "../order";
2
+ import { ExitCallback } from "../traverse";
3
+ import { Identifier, Node } from "../util/gen";
4
+ import StringEncoding from "./string/stringEncoding";
5
+ import Transform from "./transform";
6
+
7
+ /**
8
+ * The Finalizer is the last transformation before the code is ready to be generated.
9
+ *
10
+ * Hexadecimal numbers:
11
+ * - Convert integer literals into `Identifier` nodes with the name being a hexadecimal number
12
+ *
13
+ * BigInt support:
14
+ * - Convert BigInt literals into `Identifier` nodes with the name being the raw BigInt string value + "n"
15
+ *
16
+ * String Encoding:
17
+ * - Convert String literals into `Identifier` nodes with the name being a unicode escaped string
18
+ */
19
+ export default class Finalizer extends Transform {
20
+ stringEncoding: StringEncoding;
21
+
22
+ constructor(o) {
23
+ super(o, ObfuscateOrder.Finalizer);
24
+
25
+ this.stringEncoding = new StringEncoding(o);
26
+ }
27
+
28
+ isNumberLiteral(object: Node) {
29
+ return (
30
+ object.type === "Literal" &&
31
+ typeof object.value === "number" &&
32
+ Math.floor(object.value) === object.value
33
+ );
34
+ }
35
+
36
+ isBigIntLiteral(object: Node) {
37
+ return object.type === "Literal" && typeof object.value === "bigint";
38
+ }
39
+
40
+ match(object, parents) {
41
+ return object.type === "Literal";
42
+ }
43
+
44
+ transform(object: Node, parents: Node[]): void | ExitCallback {
45
+ // Hexadecimal Numbers
46
+ if (this.options.hexadecimalNumbers && this.isNumberLiteral(object)) {
47
+ return () => {
48
+ // Technically, a Literal will never be negative because it's supposed to be inside a UnaryExpression with a "-" operator.
49
+ // This code handles it regardless
50
+ var isNegative = object.value < 0;
51
+ var hex = Math.abs(object.value).toString(16);
52
+
53
+ var newStr = (isNegative ? "-" : "") + "0x" + hex;
54
+
55
+ this.replace(object, Identifier(newStr));
56
+ };
57
+ }
58
+
59
+ // BigInt support
60
+ if (this.isBigIntLiteral(object)) {
61
+ // https://github.com/MichaelXF/js-confuser/issues/79
62
+ return () => {
63
+ // Use an Identifier with the raw string
64
+ this.replace(object, Identifier(object.raw));
65
+ };
66
+ }
67
+
68
+ if (
69
+ this.options.stringEncoding &&
70
+ this.stringEncoding.match(object, parents)
71
+ ) {
72
+ return this.stringEncoding.transform(object, parents);
73
+ }
74
+ }
75
+ }