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
@@ -1,10 +1,11 @@
1
1
  import { readFileSync, writeFileSync } from "fs";
2
2
  import { join } from "path";
3
3
  import JsConfuser from "../../src/index";
4
+ import { ObfuscateOptions } from "../../src/options";
4
5
 
5
6
  var SOURCE_JS = readFileSync(join(__dirname, "./Dynamic.src.js"), "utf-8");
6
7
 
7
- it("works on High Preset", async () => {
8
+ test.concurrent("Variant #1: Dynamic.src.js on High Preset", async () => {
8
9
  // `input` is an embedded variable, therefore globalConcealing must be turned off
9
10
  var output = await JsConfuser(SOURCE_JS, {
10
11
  target: "browser",
@@ -22,19 +23,20 @@ it("works on High Preset", async () => {
22
23
  expect(value).toStrictEqual(1738.1738);
23
24
  });
24
25
 
25
- it("work when doubly obfuscated with High Preset", async () => {
26
- // `input` is an embedded variable, therefore globalConcealing must be turned off
27
- var output = await JsConfuser(SOURCE_JS, {
26
+ test.concurrent("Variant #2: Dynamic.src.js on 2x High Preset", async () => {
27
+ var options: ObfuscateOptions = {
28
28
  target: "node",
29
29
  preset: "high",
30
30
  globalConcealing: false,
31
- });
31
+ };
32
32
 
33
- var doublyObfuscated = await JsConfuser(output, {
34
- target: "node",
35
- preset: "high",
36
- globalConcealing: false,
37
- });
33
+ var output = await JsConfuser(SOURCE_JS, options);
34
+
35
+ // writeFileSync("./dev.error.1.js", output, "utf-8");
36
+
37
+ var doublyObfuscated = await JsConfuser(output, options);
38
+
39
+ // writeFileSync("./dev.error.2.js", doublyObfuscated, "utf-8");
38
40
 
39
41
  var value = "never_called";
40
42
  function input(x) {
@@ -1,3 +1,5 @@
1
+ "use strict";
2
+
1
3
  // Variant #1 Using `let`
2
4
  let myVariable = 1;
3
5
 
@@ -87,3 +89,147 @@ for (
87
89
  var TEST_OUTPUT = myFunction();
88
90
 
89
91
  expect(TEST_OUTPUT).toStrictEqual(12);
92
+
93
+ function noLexicalVariables() {
94
+ // Variant #13 For-in statement
95
+ var object = { 100: true, "-87": true, 1000: false };
96
+ var sumOfKeys = 0;
97
+ for (var propertyName in object) {
98
+ if (object[propertyName] === true) {
99
+ sumOfKeys += parseInt(propertyName);
100
+ }
101
+ }
102
+
103
+ expect(sumOfKeys).toStrictEqual(13);
104
+
105
+ // Variant #14 For-of statement
106
+ var values = [10, 20, 30, 40, -86];
107
+ var sumOfValues = 0;
108
+ for (var value of values) {
109
+ sumOfValues += value;
110
+ }
111
+
112
+ expect(sumOfValues).toStrictEqual(14);
113
+ }
114
+
115
+ noLexicalVariables();
116
+
117
+ function useStrictFunction() {
118
+ "use strict";
119
+
120
+ function testThis() {
121
+ // Ensure 'this' behaves like strict mode
122
+ function fun() {
123
+ return this;
124
+ }
125
+
126
+ expect(fun() === undefined).toStrictEqual(true);
127
+ expect(fun.call(2) === 2).toStrictEqual(true);
128
+ expect(fun.apply(null) === null).toStrictEqual(true);
129
+ expect(fun.call(undefined) === undefined).toStrictEqual(true);
130
+ expect(fun.bind(true)() === true).toStrictEqual(true);
131
+ }
132
+
133
+ testThis();
134
+
135
+ function testArguments() {
136
+ // Ensure arguments behaves like strict-mode
137
+ expect(() => useStrictFunction.arguments).toThrow();
138
+ expect(() => useStrictFunction.caller).toThrow();
139
+ expect(() => arguments.callee).toThrow();
140
+ }
141
+
142
+ testArguments();
143
+
144
+ function testEval() {
145
+ var __NO_JS_CONFUSER_RENAME__myOuterVariable = "Initial Value";
146
+
147
+ // Eval will not leak names
148
+ eval("var __NO_JS_CONFUSER_RENAME__myOuterVariable = 'Incorrect Value';");
149
+
150
+ expect(__NO_JS_CONFUSER_RENAME__myOuterVariable).toStrictEqual(
151
+ "Initial Value"
152
+ );
153
+ }
154
+
155
+ testEval();
156
+ }
157
+
158
+ useStrictFunction();
159
+
160
+ function labeledBreaksAndContinues() {
161
+ var flag = true;
162
+
163
+ label_1: for (var i = 0; i < 20; i++) {
164
+ b: switch (i) {
165
+ case 15:
166
+ c: do {
167
+ if (i !== 15) {
168
+ break c;
169
+ }
170
+ flag = true;
171
+
172
+ break label_1;
173
+
174
+ var fillerVar1;
175
+ var fillerVar2;
176
+ var fillerVar3;
177
+ } while (i == 15);
178
+
179
+ break;
180
+
181
+ case 10:
182
+ continue label_1;
183
+
184
+ default:
185
+ flag = false;
186
+ break b;
187
+ }
188
+
189
+ var fillerVar1;
190
+ var fillerVar2;
191
+ var fillerVar3;
192
+ }
193
+
194
+ var fillerVar1;
195
+ var fillerVar2;
196
+ var fillerVar3;
197
+
198
+ if (flag) {
199
+ return i;
200
+ }
201
+ }
202
+
203
+ var variant15 = labeledBreaksAndContinues();
204
+ expect(variant15).toStrictEqual(15);
205
+
206
+ // Variant #16: Function.length property
207
+ var variant16 = function (
208
+ n1,
209
+ n2,
210
+ n3,
211
+ n4,
212
+ n5,
213
+ n6,
214
+ n7,
215
+ n8,
216
+ n9,
217
+ n10,
218
+ n11,
219
+ n12,
220
+ n13,
221
+ n14,
222
+ n15,
223
+ n16
224
+ ) {
225
+ var _ = true;
226
+ };
227
+
228
+ expect(variant16.length).toStrictEqual(16);
229
+
230
+ // Set 'ranAllTest' to TRUE
231
+ ranAllTest = true;
232
+
233
+ function countermeasures() {
234
+ throw new Error("Countermeasures function called.");
235
+ }
@@ -4,13 +4,39 @@ import JsConfuser from "../../src/index";
4
4
 
5
5
  var ES6_JS = readFileSync(join(__dirname, "./ES6.src.js"), "utf-8");
6
6
 
7
- it("works with ES6 code on High Preset", async () => {
7
+ test.concurrent("Variant #1: ES6 code on High Preset", async () => {
8
8
  var output = await JsConfuser(ES6_JS, {
9
9
  target: "node",
10
10
  preset: "high",
11
11
  });
12
12
 
13
- (global as any).expect = expect;
13
+ // Ensure 'use strict' directive is preserved
14
+ expect(output.startsWith("'use strict'")).toStrictEqual(true);
14
15
 
16
+ var ranAllTest = false;
15
17
  eval(output);
18
+
19
+ // 'ranAllTest' is set to TRUE by the evaluated code
20
+ expect(ranAllTest).toStrictEqual(true);
16
21
  });
22
+
23
+ test.concurrent(
24
+ "Variant #2: ES6 code on High Preset + RGF + Self Defending",
25
+ async () => {
26
+ var output = await JsConfuser(ES6_JS, {
27
+ target: "node",
28
+ preset: "high",
29
+ rgf: true,
30
+ lock: {
31
+ selfDefending: true,
32
+ countermeasures: "countermeasures",
33
+ },
34
+ });
35
+
36
+ var ranAllTest = false;
37
+ eval(output);
38
+
39
+ // 'ranAllTest' is set to TRUE by the evaluated code
40
+ expect(ranAllTest).toStrictEqual(true);
41
+ }
42
+ );
@@ -227,7 +227,8 @@ describe("debugObfuscation", () => {
227
227
  var output = await debugObfuscation(
228
228
  `console.log(1)`,
229
229
  { target: "node", preset: "low" },
230
- callback
230
+ callback,
231
+ require("perf_hooks").performance
231
232
  );
232
233
 
233
234
  expect(typeof output).toStrictEqual("object");
@@ -0,0 +1,44 @@
1
+ import { isProbabilityMapProbable } from "../src/probability";
2
+
3
+ describe("isProbabilityMapProbable", function () {
4
+ test("Variant #1: True examples", function () {
5
+ expect(isProbabilityMapProbable(true)).toStrictEqual(true);
6
+ expect(isProbabilityMapProbable(1)).toStrictEqual(true);
7
+ expect(isProbabilityMapProbable(0.1)).toStrictEqual(true);
8
+
9
+ expect(
10
+ isProbabilityMapProbable({
11
+ mode: 1,
12
+ })
13
+ ).toStrictEqual(true);
14
+
15
+ expect(isProbabilityMapProbable(["mode"])).toStrictEqual(true);
16
+
17
+ // Function are always true
18
+ expect(isProbabilityMapProbable(() => true)).toStrictEqual(true);
19
+ expect(isProbabilityMapProbable(() => false)).toStrictEqual(true);
20
+ });
21
+
22
+ test("Variant #2: False examples", function () {
23
+ expect(isProbabilityMapProbable(false)).toStrictEqual(false);
24
+ expect(isProbabilityMapProbable(0)).toStrictEqual(false);
25
+ expect(isProbabilityMapProbable(undefined)).toStrictEqual(false);
26
+ expect(isProbabilityMapProbable(null)).toStrictEqual(false);
27
+
28
+ expect(isProbabilityMapProbable([false])).toStrictEqual(false);
29
+ });
30
+
31
+ test("Variant #3: Invalid examples", function () {
32
+ // Invalid percentage
33
+ expect(() => isProbabilityMapProbable(1.1)).toThrow();
34
+ expect(() => isProbabilityMapProbable(50)).toThrow();
35
+ expect(() => isProbabilityMapProbable(-0.1)).toThrow();
36
+ expect(() => isProbabilityMapProbable(NaN)).toThrow();
37
+
38
+ // Empty object
39
+ expect(() => isProbabilityMapProbable({})).toThrow();
40
+
41
+ // Empty array
42
+ expect(() => isProbabilityMapProbable([])).toThrow();
43
+ });
44
+ });
@@ -3,7 +3,7 @@ import Template from "../../src/templates/template";
3
3
  describe("Template", () => {
4
4
  test("Variant #1: Error when invalid code passed in", () => {
5
5
  var _consoleError = console.error;
6
- console.error = null;
6
+ console.error = () => {};
7
7
 
8
8
  expect(() => {
9
9
  Template(`#&!#Ylet{}class)--1]?|:!@#`).compile();
@@ -28,3 +28,25 @@ test("Variant #1: Don't break Symbols", async () => {
28
28
  }
29
29
  }
30
30
  });
31
+
32
+ test("Variant #2: Join expressions into sequence expressions", async () => {
33
+ var output = await JsConfuser(
34
+ `
35
+ TEST_OUTPUT = 0;
36
+ TEST_OUTPUT++;
37
+ TEST_OUTPUT++;
38
+ TEST_OUTPUT++;
39
+ if(TEST_OUTPUT > 0) {
40
+ TEST_OUTPUT *= 2;
41
+ }
42
+ `,
43
+ { target: "node", renameVariables: true }
44
+ );
45
+
46
+ expect(output).toContain("(TEST_OUTPUT=0,TEST_OUTPUT++");
47
+
48
+ var TEST_OUTPUT;
49
+ eval(output);
50
+
51
+ expect(TEST_OUTPUT).toStrictEqual(6);
52
+ });
@@ -36,3 +36,43 @@ it("should execute property with complex operations", async () => {
36
36
 
37
37
  expect(value).toStrictEqual(5618);
38
38
  });
39
+
40
+ it("should apply to unary operators", async () => {
41
+ var code = `
42
+ var one = +1;
43
+ var negativeOne = -one;
44
+
45
+ var trueValue = true;
46
+ var falseValue = !trueValue;
47
+
48
+ TEST_OUTPUT = typeof (1, falseValue) === "boolean" && negativeOne === ~~-1 && void 0 === undefined;
49
+ `;
50
+
51
+ var output = await JsConfuser(code, { target: "node", calculator: true });
52
+
53
+ expect(output).toContain("_calc");
54
+ expect(output).not.toContain("+1");
55
+ expect(output).not.toContain("-one");
56
+ expect(output).not.toContain("typeof(1,falseValue)");
57
+ expect(output).not.toContain("void 0");
58
+
59
+ var TEST_OUTPUT = true;
60
+ eval(output);
61
+
62
+ expect(TEST_OUTPUT).toStrictEqual(true);
63
+ });
64
+
65
+ it("should not break typeof expressions", async () => {
66
+ var code = `
67
+ TEST_OUTPUT = typeof nonExistentVariable === "undefined";
68
+ `;
69
+
70
+ var output = await JsConfuser(code, { target: "node", calculator: true });
71
+
72
+ expect(output).not.toContain("_calc");
73
+
74
+ var TEST_OUTPUT;
75
+ eval(output);
76
+
77
+ expect(TEST_OUTPUT).toStrictEqual(true);
78
+ });