js-confuser 1.2.1 → 1.4.1

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 (94) hide show
  1. package/CHANGELOG.md +171 -0
  2. package/README.md +7 -6
  3. package/dist/options.js +5 -1
  4. package/dist/parser.js +1 -2
  5. package/dist/presets.js +2 -2
  6. package/dist/transforms/calculator.js +48 -60
  7. package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +482 -95
  8. package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +4 -0
  9. package/dist/transforms/controlFlowFlattening/{switchCaseObfucation.js → switchCaseObfuscation.js} +2 -2
  10. package/dist/transforms/deadCode.js +1 -1
  11. package/dist/transforms/dispatcher.js +14 -13
  12. package/dist/transforms/extraction/duplicateLiteralsRemoval.js +5 -10
  13. package/dist/transforms/flatten.js +5 -1
  14. package/dist/transforms/hideInitializingCode.js +17 -2
  15. package/dist/transforms/identifier/globalConcealing.js +46 -25
  16. package/dist/transforms/identifier/movedDeclarations.js +69 -68
  17. package/dist/transforms/identifier/renameVariables.js +22 -98
  18. package/dist/transforms/identifier/variableAnalysis.js +133 -0
  19. package/dist/transforms/label.js +11 -2
  20. package/dist/transforms/lock/antiDebug.js +32 -13
  21. package/dist/transforms/lock/lock.js +13 -2
  22. package/dist/transforms/minify.js +117 -120
  23. package/dist/transforms/opaquePredicates.js +4 -2
  24. package/dist/transforms/preparation/preparation.js +8 -0
  25. package/dist/transforms/renameLabels.js +17 -3
  26. package/dist/transforms/rgf.js +8 -3
  27. package/dist/transforms/shuffle.js +25 -9
  28. package/dist/transforms/stack.js +5 -9
  29. package/dist/transforms/string/encoding.js +209 -0
  30. package/dist/transforms/string/stringCompression.js +10 -10
  31. package/dist/transforms/string/stringConcealing.js +94 -65
  32. package/dist/transforms/string/stringSplitting.js +7 -7
  33. package/dist/transforms/transform.js +10 -0
  34. package/dist/traverse.js +1 -35
  35. package/dist/util/gen.js +3 -1
  36. package/dist/util/identifiers.js +9 -19
  37. package/dist/util/insert.js +6 -40
  38. package/dist/util/scope.js +17 -0
  39. package/package.json +2 -2
  40. package/src/options.ts +19 -3
  41. package/src/parser.ts +1 -2
  42. package/src/presets.ts +2 -2
  43. package/src/transforms/calculator.ts +87 -91
  44. package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +742 -142
  45. package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +6 -0
  46. package/src/transforms/controlFlowFlattening/{switchCaseObfucation.ts → switchCaseObfuscation.ts} +6 -2
  47. package/src/transforms/deadCode.ts +8 -0
  48. package/src/transforms/dispatcher.ts +29 -14
  49. package/src/transforms/extraction/duplicateLiteralsRemoval.ts +43 -19
  50. package/src/transforms/flatten.ts +15 -2
  51. package/src/transforms/hideInitializingCode.ts +432 -406
  52. package/src/transforms/identifier/globalConcealing.ts +148 -46
  53. package/src/transforms/identifier/movedDeclarations.ts +78 -101
  54. package/src/transforms/identifier/renameVariables.ts +21 -96
  55. package/src/transforms/identifier/variableAnalysis.ts +124 -0
  56. package/src/transforms/label.ts +20 -2
  57. package/src/transforms/lock/antiDebug.ts +69 -26
  58. package/src/transforms/lock/lock.ts +37 -3
  59. package/src/transforms/minify.ts +154 -130
  60. package/src/transforms/opaquePredicates.ts +25 -3
  61. package/src/transforms/preparation/preparation.ts +8 -1
  62. package/src/transforms/renameLabels.ts +26 -3
  63. package/src/transforms/rgf.ts +6 -1
  64. package/src/transforms/shuffle.ts +87 -29
  65. package/src/transforms/stack.ts +6 -8
  66. package/src/transforms/string/encoding.ts +310 -0
  67. package/src/transforms/string/stringCompression.ts +37 -24
  68. package/src/transforms/string/stringConcealing.ts +157 -160
  69. package/src/transforms/string/stringSplitting.ts +12 -8
  70. package/src/transforms/transform.ts +15 -2
  71. package/src/traverse.ts +1 -31
  72. package/src/util/gen.ts +5 -3
  73. package/src/util/identifiers.ts +20 -20
  74. package/src/util/insert.ts +12 -78
  75. package/src/util/scope.ts +9 -0
  76. package/test/{transforms/compare.test.ts → compare.test.ts} +2 -2
  77. package/test/index.test.ts +109 -1
  78. package/test/templates/template.test.ts +14 -0
  79. package/test/transforms/controlFlowFlattening/controlFlowFlattening.test.ts +392 -10
  80. package/test/transforms/dispatcher.test.ts +30 -0
  81. package/test/transforms/flatten.test.ts +28 -0
  82. package/test/transforms/hideInitializingCode.test.ts +336 -336
  83. package/test/transforms/identifier/globalConcealing.test.ts +1 -2
  84. package/test/transforms/identifier/movedDeclarations.test.ts +137 -112
  85. package/test/transforms/identifier/renameVariables.test.ts +124 -13
  86. package/test/transforms/lock/antiDebug.test.ts +43 -0
  87. package/test/transforms/lock/selfDefending.test.ts +68 -0
  88. package/test/transforms/minify.test.ts +137 -0
  89. package/test/transforms/renameLabels.test.ts +33 -0
  90. package/test/transforms/rgf.test.ts +29 -0
  91. package/test/transforms/string/stringSplitting.test.ts +33 -0
  92. package/test/util/identifiers.test.ts +105 -17
  93. package/dist/util/expr.js +0 -60
  94. package/src/util/expr.ts +0 -56
@@ -124,3 +124,140 @@ it("should work when shortening nested if-statements", async () => {
124
124
 
125
125
  expect(value).toStrictEqual(10);
126
126
  });
127
+
128
+ test("Variant #8: Shorten simple array destructuring", async () => {
129
+ // Valid
130
+ var output = await JsConfuser(`var [x] = [1]`, {
131
+ target: "node",
132
+ minify: true,
133
+ });
134
+
135
+ expect(output).toContain("var x=1");
136
+
137
+ // Invalid
138
+ var output2 = await JsConfuser(`var [x, y] = [1]`, {
139
+ target: "node",
140
+ minify: true,
141
+ });
142
+
143
+ expect(output2).toContain("var [x,y]");
144
+ });
145
+
146
+ test("Variant #9: Shorten simple object destructuring", async () => {
147
+ // Valid
148
+ var output = await JsConfuser(`var {x} = {x: 1}`, {
149
+ target: "node",
150
+ minify: true,
151
+ });
152
+
153
+ expect(output).toContain("var x=1");
154
+
155
+ // Valid
156
+ var output2 = await JsConfuser(`var {['x']: y} = {x: 1}`, {
157
+ target: "node",
158
+ minify: true,
159
+ });
160
+
161
+ expect(output2).toContain("var y=1");
162
+
163
+ // Invalid
164
+ var output3 = await JsConfuser(`var {x,y} = {x:1}`, {
165
+ target: "node",
166
+ minify: true,
167
+ });
168
+
169
+ expect(output3).toContain("var {x:x,y:y}");
170
+
171
+ // Invalid
172
+ var output4 = await JsConfuser(`var {y} = {x:1}`, {
173
+ target: "node",
174
+ minify: true,
175
+ });
176
+
177
+ expect(output4).toContain("var {y:y}");
178
+ });
179
+
180
+ test("Variant #10: Shorten booleans", async () => {
181
+ // Valid
182
+ var output = await JsConfuser(`var x = true;`, {
183
+ target: "node",
184
+ minify: true,
185
+ });
186
+
187
+ expect(output).toContain("var x=!0");
188
+
189
+ // Valid
190
+ var output2 = await JsConfuser(`var x = false`, {
191
+ target: "node",
192
+ minify: true,
193
+ });
194
+
195
+ expect(output2).toContain("var x=!1");
196
+ });
197
+
198
+ test("Variant #11: Shorten 'undefined' to 'void 0'", async () => {
199
+ // Valid
200
+ var output = await JsConfuser(`x = undefined;`, {
201
+ target: "node",
202
+ minify: true,
203
+ });
204
+
205
+ expect(output).toContain("x=void 0");
206
+
207
+ // Valid
208
+ var output2 = await JsConfuser(`var x = {undefined: 1}`, {
209
+ target: "node",
210
+ minify: true,
211
+ });
212
+
213
+ expect(output2).toContain("var x={[void 0]:1}");
214
+ });
215
+
216
+ test("Variant #11: Shorten 'Infinity' to 1/0", async () => {
217
+ // Valid
218
+ var output = await JsConfuser(`var x = Infinity;`, {
219
+ target: "node",
220
+ minify: true,
221
+ });
222
+
223
+ expect(output).toContain("var x=1/0");
224
+
225
+ // Valid
226
+ var output2 = await JsConfuser(`var x = {Infinity: 1}`, {
227
+ target: "node",
228
+ minify: true,
229
+ });
230
+
231
+ expect(output2).toContain("var x={[1/0]:1}");
232
+ });
233
+
234
+ test("Variant #12: Shorten '!false' to 'true'", async () => {
235
+ // Valid
236
+ var output = await JsConfuser(`var x = !false;`, {
237
+ target: "node",
238
+ minify: true,
239
+ });
240
+
241
+ expect(output).toContain("var x=true");
242
+ });
243
+
244
+ test("Variant #13: Shorten 'false ? a : b' to 'b'", async () => {
245
+ // Valid
246
+ var output = await JsConfuser(`var x = false ? 10 : 15;`, {
247
+ target: "node",
248
+ minify: true,
249
+ });
250
+
251
+ expect(output).toContain("var x=15");
252
+ });
253
+
254
+ test("Variant #14: Shorten 'var x = undefined' to 'var x'", async () => {
255
+ // Valid
256
+ var output = await JsConfuser(`var x = undefined`, {
257
+ target: "node",
258
+ minify: true,
259
+ });
260
+
261
+ expect(output).toContain("var x");
262
+ expect(output).not.toContain("var x=");
263
+ });
@@ -60,3 +60,36 @@ it("should not rename nested labels", async () => {
60
60
  expect(output).not.toContain("TEST_LABEL");
61
61
  expect(output).toContain(":for");
62
62
  });
63
+
64
+ it("should not remove labels on block statements", async () => {
65
+ var code = `
66
+ TEST_LABEL: {
67
+ break TEST_LABEL;
68
+ }
69
+ `;
70
+
71
+ var output = await JsConfuser(code, {
72
+ target: "browser",
73
+ objectExtraction: true,
74
+ });
75
+
76
+ expect(output).not.toContain("TEST_LABEL");
77
+ expect(output).toContain(":{");
78
+ });
79
+
80
+ it("should remove labels on block statements when the label was never used", async () => {
81
+ var code = `
82
+ TEST_LABEL: {
83
+ "";
84
+ }
85
+ `;
86
+
87
+ var output = await JsConfuser(code, {
88
+ target: "browser",
89
+ objectExtraction: true,
90
+ });
91
+
92
+ expect(output).not.toContain("TEST_LABEL");
93
+ expect(output).not.toContain(":{");
94
+ expect(output).toContain("{");
95
+ });
@@ -125,6 +125,35 @@ describe("RGF", () => {
125
125
 
126
126
  expect(value).toStrictEqual("Hello World");
127
127
  });
128
+
129
+ it("should work with hideInitializingCode enabled", async () => {
130
+ var output = await JsConfuser.obfuscate(
131
+ `
132
+ function abc(x, y){
133
+ return x + y;
134
+ }
135
+
136
+ var result = abc(10, 50);
137
+ input(console.log, result)
138
+ `,
139
+ {
140
+ target: "node",
141
+ identifierGenerator: "randomized",
142
+ hideInitializingCode: true,
143
+ rgf: true,
144
+ compact: false,
145
+ renameVariables: true,
146
+ }
147
+ );
148
+
149
+ var value = "never_called";
150
+ function input(_, valueIn) {
151
+ value = valueIn;
152
+ }
153
+
154
+ eval(output);
155
+ expect(value).toStrictEqual(60);
156
+ });
128
157
  });
129
158
 
130
159
  describe("RGF with the 'all' mode", () => {
@@ -100,3 +100,36 @@ it("should not encode constructor key", async () => {
100
100
 
101
101
  expect(TEST_VAR).toStrictEqual(100);
102
102
  });
103
+
104
+ it("should allow custom callback to exclude strings", async () => {
105
+ var code = `
106
+ var str1 = "-- Hello World --";
107
+ var str2 = "-- This String Will Not Be Split --";
108
+ var str3 = "-- This string Will Be Split --";
109
+ `;
110
+
111
+ var strings = [];
112
+ var output = await JsConfuser(code, {
113
+ target: "node",
114
+ stringSplitting: (str) => {
115
+ strings.push(str);
116
+
117
+ if (str == "-- This String Will Not Be Split --") {
118
+ return false;
119
+ }
120
+
121
+ return true;
122
+ },
123
+ });
124
+
125
+ expect(strings).toEqual([
126
+ "-- Hello World --",
127
+ "-- This String Will Not Be Split --",
128
+ "-- This string Will Be Split --",
129
+ ]);
130
+
131
+ expect(output).toContain("-- This String Will Not Be Split --");
132
+
133
+ expect(output).not.toContain("-- Hello World --");
134
+ expect(output).not.toContain("-- This string Will Be Split --");
135
+ });
@@ -1,32 +1,120 @@
1
1
  import parseJS from "../../src/parser";
2
- import { getIdentifierInfo } from "../../src/util/identifiers";
2
+ import {
3
+ getFunctionParameters,
4
+ getIdentifierInfo,
5
+ validateChain,
6
+ } from "../../src/util/identifiers";
3
7
 
4
- it("getIdentifierInfo() should determine function declarations", async () => {
5
- var tree = await parseJS(`function abc(){}`);
8
+ describe("getIdentifierInfo", () => {
9
+ test("Variant #1: Determine function declarations", async () => {
10
+ var tree = await parseJS(`function abc(){}`);
6
11
 
7
- var object = tree.body[0].id;
12
+ var object = tree.body[0].id;
8
13
 
9
- expect(object.type).toStrictEqual("Identifier");
14
+ expect(object.type).toStrictEqual("Identifier");
10
15
 
11
- var parents = [tree.body[0], tree.body, tree];
16
+ var parents = [tree.body[0], tree.body, tree];
12
17
 
13
- var info = getIdentifierInfo(object, parents as any);
18
+ var info = getIdentifierInfo(object, parents as any);
14
19
 
15
- expect(info.isFunctionDeclaration).toStrictEqual(true);
16
- expect(info.spec.isDefined).toStrictEqual(true);
20
+ expect(info.isFunctionDeclaration).toStrictEqual(true);
21
+ expect(info.spec.isDefined).toStrictEqual(true);
22
+ });
23
+
24
+ test("Variant #2: Determine labels", async () => {
25
+ var tree = await parseJS(`label: for (var i = 0; i < 0; i++ ) {}`);
26
+
27
+ var object = tree.body[0].label;
28
+
29
+ expect(object.type).toStrictEqual("Identifier");
30
+
31
+ var parents = [tree.body[0], tree.body, tree];
32
+
33
+ var info = getIdentifierInfo(object, parents as any);
34
+
35
+ expect(info.isLabel).toStrictEqual(true);
36
+ expect(info.spec.isReferenced).toStrictEqual(false);
37
+ });
38
+
39
+ test("Variant #3: Error when a non-identifier node is given", async () => {
40
+ expect(() => {
41
+ getIdentifierInfo({ type: "Literal", value: true }, []);
42
+ }).toThrow();
43
+ });
44
+ });
45
+
46
+ describe("validateChain", () => {
47
+ test("Variant #1: Error when parents is not an array", () => {
48
+ expect(() => {
49
+ validateChain({ type: "Identifier", name: "name" }, {} as any);
50
+ }).toThrow();
51
+ });
52
+
53
+ test("Variant #2: Error when object is undefined", () => {
54
+ expect(() => {
55
+ validateChain(undefined, []);
56
+ }).toThrow();
57
+ });
58
+
59
+ test("Variant #3: Error when object is not connected to direct parent", () => {
60
+ expect(() => {
61
+ validateChain({ type: "Identifier", name: "name" }, [
62
+ { type: "Program", body: [] },
63
+ ]);
64
+ }).toThrow();
65
+ });
17
66
  });
18
67
 
19
- it("getIdentifierInfo() should determine labels", async () => {
20
- var tree = await parseJS(`label: for (var i = 0; i < 0; i++ ) {}`);
68
+ describe("getFunctionParameters", () => {
69
+ test("Variant #1: Work with default values and destructuring", async () => {
70
+ var code = `function a(A=_b,{B,[_c]:C},[D]){}`;
71
+ var tree = await parseJS(code);
72
+
73
+ var object = tree.body[0];
74
+ var parents: any = [tree.body, tree];
75
+
76
+ var locations = getFunctionParameters(object, parents);
77
+ var names = locations.map((x) => x[0].name);
78
+
79
+ expect(names).toStrictEqual(["A", "B", "C", "D"]);
80
+ });
81
+
82
+ test("Variant #2: Work with spread element", async () => {
83
+ var code = `function a(...A){}`;
84
+ var tree = await parseJS(code);
85
+
86
+ var object = tree.body[0];
87
+ var parents: any = [tree.body, tree];
88
+
89
+ var locations = getFunctionParameters(object, parents);
90
+ var names = locations.map((x) => x[0].name);
91
+
92
+ expect(names).toStrictEqual(["A"]);
93
+ });
94
+
95
+ test("Variant #3: Normal parameters", async () => {
96
+ var code = `function a(A,B,C,D){}`;
97
+ var tree = await parseJS(code);
98
+
99
+ var object = tree.body[0];
100
+ var parents: any = [tree.body, tree];
101
+
102
+ var locations = getFunctionParameters(object, parents);
103
+ var names = locations.map((x) => x[0].name);
21
104
 
22
- var object = tree.body[0].label;
105
+ expect(names).toStrictEqual(["A", "B", "C", "D"]);
106
+ });
23
107
 
24
- expect(object.type).toStrictEqual("Identifier");
108
+ test("Variant #4: Default values as functions", async () => {
109
+ var code = `function a(A = function(_a){ return _a; },B = function(_a, _b = function(){return this;}){return _a + _b();},C,D){}`;
110
+ var tree = await parseJS(code);
25
111
 
26
- var parents = [tree.body[0], tree.body, tree];
112
+ var object = tree.body[0];
113
+ var parents: any = [tree.body, tree];
27
114
 
28
- var info = getIdentifierInfo(object, parents as any);
115
+ var locations = getFunctionParameters(object, parents);
116
+ var names = locations.map((x) => x[0].name);
29
117
 
30
- expect(info.isLabel).toStrictEqual(true);
31
- expect(info.spec.isReferenced).toStrictEqual(false);
118
+ expect(names).toStrictEqual(["A", "B", "C", "D"]);
119
+ });
32
120
  });
package/dist/util/expr.js DELETED
@@ -1,60 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.inverseExpression = inverseExpression;
7
-
8
- var _gen = require("./gen");
9
-
10
- var _traverse = require("../traverse");
11
-
12
- function inverseExpression(expr) {
13
- /**
14
- * !x -> x
15
- */
16
- if (expr.type == "UnaryExpression" && expr.operator == "!" && expr.prefix) {
17
- return expr.argument;
18
- }
19
-
20
- var inverseMapping = {
21
- BinaryExpression: {
22
- "<": ">=",
23
- ">": "<=",
24
- "<=": ">",
25
- ">=": "<",
26
- "==": "!=",
27
- "===": "!=",
28
- "!=": "==",
29
- "!==": "==="
30
- }
31
- };
32
-
33
- if (!inverseMapping[expr.type]) {
34
- return (0, _gen.UnaryExpression)("!", expr);
35
- }
36
-
37
- var safe = new Set(["Literal", "Identifier", "MemberExpression"]);
38
- var canInvert = true;
39
- (0, _traverse.walk)(expr, [], (object, parents) => {
40
- if (object.type) {
41
- var hasInverse = inverseMapping[object.type] && inverseMapping[object.type][object.operator];
42
-
43
- if (!safe.has(object.type) && !hasInverse) {
44
- // console.log(object.type);
45
- canInvert = false;
46
- }
47
- }
48
- });
49
-
50
- if (canInvert) {
51
- (0, _traverse.walk)(expr, [], (object, parents) => {
52
- if (object.operator) {
53
- object.operator = inverseMapping[object.type][object.operator];
54
- }
55
- });
56
- return expr;
57
- } else {
58
- return (0, _gen.UnaryExpression)("!", expr);
59
- }
60
- }
package/src/util/expr.ts DELETED
@@ -1,56 +0,0 @@
1
- import { Node, UnaryExpression } from "./gen";
2
- import { walk } from "../traverse";
3
-
4
- export function inverseExpression(expr: Node) {
5
- /**
6
- * !x -> x
7
- */
8
- if (expr.type == "UnaryExpression" && expr.operator == "!" && expr.prefix) {
9
- return expr.argument;
10
- }
11
-
12
- var inverseMapping = {
13
- BinaryExpression: {
14
- "<": ">=",
15
- ">": "<=",
16
- "<=": ">",
17
- ">=": "<",
18
- "==": "!=",
19
- "===": "!=",
20
- "!=": "==",
21
- "!==": "===",
22
- },
23
- };
24
-
25
- if (!inverseMapping[expr.type]) {
26
- return UnaryExpression("!", expr);
27
- }
28
-
29
- var safe = new Set(["Literal", "Identifier", "MemberExpression"]);
30
-
31
- var canInvert = true;
32
- walk(expr, [], (object: Node, parents: Node[]) => {
33
- if (object.type) {
34
- var hasInverse =
35
- inverseMapping[object.type] &&
36
- inverseMapping[object.type][object.operator];
37
-
38
- if (!safe.has(object.type) && !hasInverse) {
39
- // console.log(object.type);
40
- canInvert = false;
41
- }
42
- }
43
- });
44
-
45
- if (canInvert) {
46
- walk(expr, [], (object: Node, parents: Node[]) => {
47
- if (object.operator) {
48
- object.operator = inverseMapping[object.type][object.operator];
49
- }
50
- });
51
-
52
- return expr;
53
- } else {
54
- return UnaryExpression("!", expr);
55
- }
56
- }