js-confuser 1.7.1 → 1.7.3
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.
- package/.github/workflows/node.js.yml +1 -1
- package/CHANGELOG.md +73 -0
- package/README.md +32 -31
- package/dist/compiler.js +2 -8
- package/dist/constants.js +22 -10
- package/dist/index.js +15 -30
- package/dist/obfuscator.js +15 -62
- package/dist/options.js +33 -40
- package/dist/order.js +4 -7
- package/dist/parser.js +5 -13
- package/dist/precedence.js +6 -8
- package/dist/presets.js +4 -6
- package/dist/probability.js +13 -24
- package/dist/templates/bufferToString.js +121 -5
- package/dist/templates/core.js +35 -0
- package/dist/templates/crash.js +22 -11
- package/dist/templates/es5.js +125 -6
- package/dist/templates/functionLength.js +24 -6
- package/dist/templates/globals.js +9 -0
- package/dist/templates/template.js +189 -43
- package/dist/transforms/antiTooling.js +26 -22
- package/dist/transforms/calculator.js +19 -55
- package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +242 -333
- package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +46 -25
- package/dist/transforms/deadCode.js +542 -31
- package/dist/transforms/dispatcher.js +112 -112
- package/dist/transforms/es5/antiClass.js +70 -44
- package/dist/transforms/es5/antiDestructuring.js +14 -38
- package/dist/transforms/es5/antiES6Object.js +39 -48
- package/dist/transforms/es5/antiSpreadOperator.js +5 -14
- package/dist/transforms/es5/antiTemplate.js +10 -19
- package/dist/transforms/es5/es5.js +7 -40
- package/dist/transforms/extraction/classExtraction.js +83 -0
- package/dist/transforms/extraction/duplicateLiteralsRemoval.js +41 -80
- package/dist/transforms/extraction/objectExtraction.js +24 -56
- package/dist/transforms/finalizer.js +6 -20
- package/dist/transforms/flatten.js +51 -99
- package/dist/transforms/identifier/globalAnalysis.js +21 -26
- package/dist/transforms/identifier/globalConcealing.js +72 -56
- package/dist/transforms/identifier/movedDeclarations.js +66 -38
- package/dist/transforms/identifier/renameVariables.js +36 -68
- package/dist/transforms/identifier/variableAnalysis.js +21 -48
- package/dist/transforms/lock/antiDebug.js +20 -25
- package/dist/transforms/lock/integrity.js +53 -52
- package/dist/transforms/lock/lock.js +161 -126
- package/dist/transforms/minify.js +77 -108
- package/dist/transforms/opaquePredicates.js +12 -49
- package/dist/transforms/preparation.js +28 -49
- package/dist/transforms/renameLabels.js +5 -22
- package/dist/transforms/rgf.js +125 -72
- package/dist/transforms/shuffle.js +42 -47
- package/dist/transforms/stack.js +41 -98
- package/dist/transforms/string/encoding.js +76 -27
- package/dist/transforms/string/stringCompression.js +75 -68
- package/dist/transforms/string/stringConcealing.js +127 -135
- package/dist/transforms/string/stringEncoding.js +6 -26
- package/dist/transforms/string/stringSplitting.js +5 -30
- package/dist/transforms/transform.js +76 -104
- package/dist/traverse.js +11 -18
- package/dist/util/compare.js +27 -29
- package/dist/util/gen.js +32 -86
- package/dist/util/guard.js +5 -1
- package/dist/util/identifiers.js +9 -72
- package/dist/util/insert.js +27 -77
- package/dist/util/math.js +0 -3
- package/dist/util/object.js +3 -7
- package/dist/util/random.js +31 -36
- package/dist/util/scope.js +6 -3
- package/docs/Countermeasures.md +13 -6
- package/docs/Integrity.md +35 -28
- package/docs/RGF.md +6 -1
- package/docs/RenameVariables.md +116 -0
- package/docs/TamperProtection.md +100 -0
- package/docs/Template.md +117 -0
- package/package.json +3 -3
- package/src/constants.ts +17 -0
- package/src/index.ts +7 -5
- package/src/options.ts +60 -7
- package/src/order.ts +2 -2
- package/src/templates/bufferToString.ts +79 -11
- package/src/templates/core.ts +29 -0
- package/src/templates/crash.ts +6 -38
- package/src/templates/es5.ts +1 -1
- package/src/templates/functionLength.ts +21 -3
- package/src/templates/globals.ts +3 -0
- package/src/templates/template.ts +205 -46
- package/src/transforms/antiTooling.ts +33 -11
- package/src/transforms/calculator.ts +4 -2
- package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +12 -5
- package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +46 -10
- package/src/transforms/deadCode.ts +74 -42
- package/src/transforms/dispatcher.ts +99 -73
- package/src/transforms/es5/antiClass.ts +25 -12
- package/src/transforms/es5/antiDestructuring.ts +1 -1
- package/src/transforms/es5/antiES6Object.ts +2 -2
- package/src/transforms/es5/antiTemplate.ts +1 -1
- package/src/transforms/extraction/classExtraction.ts +168 -0
- package/src/transforms/extraction/duplicateLiteralsRemoval.ts +11 -16
- package/src/transforms/extraction/objectExtraction.ts +4 -15
- package/src/transforms/flatten.ts +20 -5
- package/src/transforms/identifier/globalAnalysis.ts +18 -1
- package/src/transforms/identifier/globalConcealing.ts +119 -72
- package/src/transforms/identifier/movedDeclarations.ts +90 -24
- package/src/transforms/identifier/renameVariables.ts +16 -1
- package/src/transforms/lock/antiDebug.ts +2 -2
- package/src/transforms/lock/integrity.ts +13 -11
- package/src/transforms/lock/lock.ts +122 -30
- package/src/transforms/minify.ts +28 -13
- package/src/transforms/opaquePredicates.ts +2 -2
- package/src/transforms/preparation.ts +16 -0
- package/src/transforms/rgf.ts +139 -12
- package/src/transforms/shuffle.ts +3 -3
- package/src/transforms/stack.ts +19 -4
- package/src/transforms/string/encoding.ts +88 -51
- package/src/transforms/string/stringCompression.ts +86 -17
- package/src/transforms/string/stringConcealing.ts +148 -118
- package/src/transforms/string/stringEncoding.ts +1 -2
- package/src/transforms/string/stringSplitting.ts +1 -2
- package/src/transforms/transform.ts +63 -46
- package/src/types.ts +2 -0
- package/src/util/compare.ts +39 -5
- package/src/util/gen.ts +10 -3
- package/src/util/guard.ts +10 -0
- package/src/util/insert.ts +17 -0
- package/src/util/random.ts +81 -1
- package/src/util/scope.ts +14 -2
- package/test/code/Cash.test.ts +94 -5
- package/test/code/StrictMode.src.js +65 -0
- package/test/code/StrictMode.test.js +37 -0
- package/test/compare.test.ts +62 -2
- package/test/options.test.ts +129 -55
- package/test/templates/template.test.ts +211 -1
- package/test/transforms/controlFlowFlattening/expressionObfuscation.test.ts +37 -18
- package/test/transforms/dispatcher.test.ts +55 -0
- package/test/transforms/extraction/classExtraction.test.ts +86 -0
- package/test/transforms/extraction/duplicateLiteralsRemoval.test.ts +8 -0
- package/test/transforms/extraction/objectExtraction.test.ts +2 -0
- package/test/transforms/identifier/globalConcealing.test.ts +89 -0
- package/test/transforms/identifier/movedDeclarations.test.ts +61 -0
- package/test/transforms/identifier/renameVariables.test.ts +75 -1
- package/test/transforms/lock/tamperProtection.test.ts +336 -0
- package/test/transforms/minify.test.ts +37 -0
- package/test/transforms/rgf.test.ts +50 -0
- package/dist/transforms/controlFlowFlattening/choiceFlowObfuscation.js +0 -62
- package/dist/transforms/controlFlowFlattening/controlFlowObfuscation.js +0 -159
- package/dist/transforms/controlFlowFlattening/switchCaseObfuscation.js +0 -106
- package/dist/transforms/eval.js +0 -84
- package/dist/transforms/hexadecimalNumbers.js +0 -63
- package/dist/transforms/hideInitializingCode.js +0 -270
- package/dist/transforms/identifier/nameRecycling.js +0 -218
- package/dist/transforms/label.js +0 -67
- package/dist/transforms/preparation/nameConflicts.js +0 -116
- package/dist/transforms/preparation/preparation.js +0 -188
|
@@ -509,7 +509,14 @@ test.each(["hexadecimal", "mangled", "number", "zeroWidth"])(
|
|
|
509
509
|
`
|
|
510
510
|
var myVar1 = "Correct Value";
|
|
511
511
|
|
|
512
|
-
|
|
512
|
+
function myFunction(myVar2){
|
|
513
|
+
myVar2 = myVar1;
|
|
514
|
+
let myVar3 = myVar2;
|
|
515
|
+
var myVar4 = myVar3;
|
|
516
|
+
return myVar4;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
TEST_OUTPUT = myFunction();
|
|
513
520
|
`,
|
|
514
521
|
{
|
|
515
522
|
target: "node",
|
|
@@ -619,3 +626,70 @@ test("Variant #25: Reference catch parameter", async () => {
|
|
|
619
626
|
|
|
620
627
|
expect(TEST_OUTPUT).toStrictEqual("Correct Value");
|
|
621
628
|
});
|
|
629
|
+
|
|
630
|
+
test("Variant #26: Transform __JS_CONFUSER_VAR__ to access variable mappings", async () => {
|
|
631
|
+
var output = await JsConfuser(
|
|
632
|
+
`
|
|
633
|
+
var myVar1 = "Incorrect Value";
|
|
634
|
+
|
|
635
|
+
function myFunction(){
|
|
636
|
+
var myVar1 = "Correct Value";
|
|
637
|
+
TEST_OUTPUT = eval( __JS_CONFUSER_VAR__(myVar1) );
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
myFunction();
|
|
641
|
+
`,
|
|
642
|
+
{ target: "node", renameVariables: true }
|
|
643
|
+
);
|
|
644
|
+
|
|
645
|
+
expect(output).not.toContain("myVar1");
|
|
646
|
+
expect(output).not.toContain("__JS_CONFUSER_VAR__");
|
|
647
|
+
|
|
648
|
+
var TEST_OUTPUT;
|
|
649
|
+
|
|
650
|
+
eval(output);
|
|
651
|
+
expect(TEST_OUTPUT).toStrictEqual("Correct Value");
|
|
652
|
+
});
|
|
653
|
+
|
|
654
|
+
test("Variant #27: Transform __JS_CONFUSER_VAR__ even when Rename Variables is disabled", async () => {
|
|
655
|
+
var output = await JsConfuser(
|
|
656
|
+
`
|
|
657
|
+
var name = "John Doe";
|
|
658
|
+
TEST_OUTPUT = __JS_CONFUSER_VAR__(name);
|
|
659
|
+
`,
|
|
660
|
+
{ target: "node", renameVariables: false }
|
|
661
|
+
);
|
|
662
|
+
|
|
663
|
+
expect(output).not.toContain("__JS_CONFUSER_VAR__");
|
|
664
|
+
|
|
665
|
+
var TEST_OUTPUT;
|
|
666
|
+
|
|
667
|
+
eval(output);
|
|
668
|
+
expect(TEST_OUTPUT).toStrictEqual("name");
|
|
669
|
+
});
|
|
670
|
+
|
|
671
|
+
test("Variant #28: Transform __JS_CONFUSER_VAR__ on High Preset", async () => {
|
|
672
|
+
var output = await JsConfuser(
|
|
673
|
+
`
|
|
674
|
+
function myFunction(){
|
|
675
|
+
var a
|
|
676
|
+
var b
|
|
677
|
+
var c
|
|
678
|
+
|
|
679
|
+
return "Correct Value"
|
|
680
|
+
}
|
|
681
|
+
TEST_OUTPUT = eval(__JS_CONFUSER_VAR__(myFunction) + "()");
|
|
682
|
+
`,
|
|
683
|
+
{
|
|
684
|
+
target: "node",
|
|
685
|
+
preset: "high",
|
|
686
|
+
}
|
|
687
|
+
);
|
|
688
|
+
|
|
689
|
+
expect(output).not.toContain("__JS_CONFUSER_VAR__");
|
|
690
|
+
|
|
691
|
+
var TEST_OUTPUT;
|
|
692
|
+
eval(output);
|
|
693
|
+
|
|
694
|
+
expect(TEST_OUTPUT).toStrictEqual("Correct Value");
|
|
695
|
+
});
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
import JsConfuser from "../../../src/index";
|
|
2
|
+
|
|
3
|
+
var _eval = eval;
|
|
4
|
+
|
|
5
|
+
function evalInNonStrictMode(str: string) {
|
|
6
|
+
var TEST_OUTPUT;
|
|
7
|
+
|
|
8
|
+
function TEST_OUTPUT_SET(value) {
|
|
9
|
+
TEST_OUTPUT = value;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
// 'new Function' runs in non-strict mode
|
|
14
|
+
// The original 'eval' function is passed in each test
|
|
15
|
+
// This is because once 'eval' is changed, it is changed for all new Function() calls!
|
|
16
|
+
var fn = new Function("TEST_OUTPUT_SET", "eval", str);
|
|
17
|
+
|
|
18
|
+
fn(TEST_OUTPUT_SET, _eval);
|
|
19
|
+
} catch (err) {
|
|
20
|
+
return { error: err, TEST_OUTPUT: TEST_OUTPUT };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return { error: null, TEST_OUTPUT: TEST_OUTPUT };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
describe("Global Concealing", () => {
|
|
27
|
+
test("Variant #1: Detect Eval tamper (no tamper)", async () => {
|
|
28
|
+
var code = `
|
|
29
|
+
global.TEST_GLOBAL_OUTPUT = global.TEST_GLOBAL;
|
|
30
|
+
`;
|
|
31
|
+
|
|
32
|
+
var output = await JsConfuser(code, {
|
|
33
|
+
target: "node",
|
|
34
|
+
globalConcealing: true,
|
|
35
|
+
lock: {
|
|
36
|
+
tamperProtection: true,
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
var TEST_GLOBAL = {};
|
|
41
|
+
(global as any).TEST_GLOBAL = TEST_GLOBAL;
|
|
42
|
+
|
|
43
|
+
evalInNonStrictMode(output);
|
|
44
|
+
|
|
45
|
+
// Make reuse global variable as 'new Function' runs in isolated environment
|
|
46
|
+
var TEST_OUTPUT = (global as any).TEST_GLOBAL_OUTPUT;
|
|
47
|
+
|
|
48
|
+
expect(TEST_OUTPUT).toStrictEqual(TEST_GLOBAL);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("Variant #2: Detect Eval tamper (tampered)", async () => {
|
|
52
|
+
var code = `
|
|
53
|
+
function onTamperDetected(){
|
|
54
|
+
TEST_OUTPUT_SET(true);
|
|
55
|
+
}
|
|
56
|
+
global.TEST_GLOBAL_VARIANT_7_OUTPUT = global.TEST_GLOBAL_VARIANT_7;
|
|
57
|
+
`;
|
|
58
|
+
|
|
59
|
+
var output = await JsConfuser(code, {
|
|
60
|
+
target: "node",
|
|
61
|
+
globalConcealing: (varName) => varName != "TEST_OUTPUT_SET",
|
|
62
|
+
lock: {
|
|
63
|
+
tamperProtection: true,
|
|
64
|
+
countermeasures: "onTamperDetected",
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// Inject 'eval' tamper code
|
|
69
|
+
output =
|
|
70
|
+
`var _eval = eval;
|
|
71
|
+
eval = (codeStr)=>( console.log(codeStr), _eval(codeStr) );
|
|
72
|
+
` + output;
|
|
73
|
+
|
|
74
|
+
var TEST_GLOBAL_VARIANT_7 = {};
|
|
75
|
+
(global as any).TEST_GLOBAL_VARIANT_7 = TEST_GLOBAL_VARIANT_7;
|
|
76
|
+
|
|
77
|
+
var { error, TEST_OUTPUT } = evalInNonStrictMode(output);
|
|
78
|
+
|
|
79
|
+
expect(error).toBeNull();
|
|
80
|
+
expect(TEST_OUTPUT).toStrictEqual(true);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test("Variant #3: Native check on functions", async () => {
|
|
84
|
+
var mockConsoleLog = (...msgs) => {
|
|
85
|
+
console.log(...msgs);
|
|
86
|
+
};
|
|
87
|
+
mockConsoleLog.toString = () => "{ [native code] }";
|
|
88
|
+
(global as any).mockConsoleLog = mockConsoleLog;
|
|
89
|
+
|
|
90
|
+
var output = await JsConfuser(
|
|
91
|
+
`
|
|
92
|
+
function onTamperDetected(){
|
|
93
|
+
TEST_OUTPUT_SET(true);
|
|
94
|
+
}
|
|
95
|
+
mockConsoleLog("console.log was not tampered")
|
|
96
|
+
`,
|
|
97
|
+
{
|
|
98
|
+
target: "node",
|
|
99
|
+
globalConcealing: (varName) => varName != "TEST_OUTPUT_SET",
|
|
100
|
+
lock: {
|
|
101
|
+
tamperProtection: true,
|
|
102
|
+
countermeasures: "onTamperDetected",
|
|
103
|
+
},
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
|
|
108
|
+
(global as any).Object.getOwnPropertyDescriptor = () => undefined;
|
|
109
|
+
|
|
110
|
+
var { TEST_OUTPUT, error } = evalInNonStrictMode(output);
|
|
111
|
+
|
|
112
|
+
(global as any).Object.getOwnPropertyDescriptor = getOwnPropertyDescriptor;
|
|
113
|
+
|
|
114
|
+
expect(TEST_OUTPUT).not.toStrictEqual(true);
|
|
115
|
+
expect(error).toBeNull();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test("Variant #4: Native check on functions (tampered)", async () => {
|
|
119
|
+
var mockConsoleLog = (...msgs) => {
|
|
120
|
+
console.log(...msgs);
|
|
121
|
+
};
|
|
122
|
+
mockConsoleLog.toString = () => "[native code]";
|
|
123
|
+
(global as any).mockConsoleLog = mockConsoleLog;
|
|
124
|
+
|
|
125
|
+
var output = await JsConfuser(
|
|
126
|
+
`
|
|
127
|
+
function onTamperDetected(){
|
|
128
|
+
TEST_OUTPUT_SET(true);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
mockConsoleLog("console.log was not tampered")
|
|
132
|
+
`,
|
|
133
|
+
{
|
|
134
|
+
target: "node",
|
|
135
|
+
globalConcealing: (varName) => varName != "TEST_OUTPUT_SET",
|
|
136
|
+
lock: {
|
|
137
|
+
tamperProtection: true,
|
|
138
|
+
countermeasures: "onTamperDetected",
|
|
139
|
+
},
|
|
140
|
+
}
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
(global as any).mockConsoleLog = (...str) =>
|
|
144
|
+
console.log("Tampered console.log: ", ...str);
|
|
145
|
+
|
|
146
|
+
// Unfortunately the program errors dude to console.log being tampered
|
|
147
|
+
var { TEST_OUTPUT, error } = evalInNonStrictMode(output);
|
|
148
|
+
|
|
149
|
+
expect(TEST_OUTPUT).toStrictEqual(true);
|
|
150
|
+
|
|
151
|
+
// Ensure error was thrown
|
|
152
|
+
expect(error).not.toBeNull();
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test("Variant #5: Native check on non-existent functions", async () => {
|
|
156
|
+
var output = await JsConfuser(
|
|
157
|
+
`
|
|
158
|
+
a.b.c.d()
|
|
159
|
+
`,
|
|
160
|
+
{
|
|
161
|
+
target: "node",
|
|
162
|
+
globalConcealing: true,
|
|
163
|
+
lock: {
|
|
164
|
+
tamperProtection: true,
|
|
165
|
+
},
|
|
166
|
+
}
|
|
167
|
+
);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
test("Variant #6: Custom implementation for lock.tamperProtection", async () => {
|
|
171
|
+
var foundNames = [];
|
|
172
|
+
var output = await JsConfuser(
|
|
173
|
+
`
|
|
174
|
+
fetch()
|
|
175
|
+
console.log()
|
|
176
|
+
shouldBeFound()
|
|
177
|
+
console["trace"]()
|
|
178
|
+
var NotFound = "NotFound"
|
|
179
|
+
console[NotFound]()
|
|
180
|
+
|
|
181
|
+
toString()
|
|
182
|
+
|
|
183
|
+
var shouldNotBeFound;
|
|
184
|
+
|
|
185
|
+
shouldNotBeFound()
|
|
186
|
+
`,
|
|
187
|
+
{
|
|
188
|
+
target: "node",
|
|
189
|
+
globalConcealing: true,
|
|
190
|
+
lock: {
|
|
191
|
+
tamperProtection: (fnName) => {
|
|
192
|
+
foundNames.push(fnName);
|
|
193
|
+
|
|
194
|
+
return false;
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
}
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
expect(foundNames).toContain("fetch");
|
|
201
|
+
expect(foundNames).toContain("console.log");
|
|
202
|
+
expect(foundNames).toContain("shouldBeFound");
|
|
203
|
+
expect(foundNames).toContain("console.trace");
|
|
204
|
+
expect(foundNames).toContain("toString");
|
|
205
|
+
|
|
206
|
+
expect(foundNames.join("")).not.toContain("NotFound");
|
|
207
|
+
|
|
208
|
+
expect(foundNames).not.toContain("shouldNotBeFound");
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
test("Variant #7: Protect native function Math.floor", async () => {
|
|
212
|
+
var output = await JsConfuser(
|
|
213
|
+
`
|
|
214
|
+
TEST_OUTPUT_SET(Math.floor(10.1));
|
|
215
|
+
`,
|
|
216
|
+
{
|
|
217
|
+
target: "node",
|
|
218
|
+
globalConcealing: (varName) => varName != "TEST_OUTPUT_SET",
|
|
219
|
+
lock: {
|
|
220
|
+
tamperProtection: true,
|
|
221
|
+
},
|
|
222
|
+
}
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
expect(output).not.toContain("Math['floor");
|
|
226
|
+
|
|
227
|
+
var { TEST_OUTPUT, error } = evalInNonStrictMode(output);
|
|
228
|
+
|
|
229
|
+
expect(error).toBeNull();
|
|
230
|
+
expect(TEST_OUTPUT).toStrictEqual(10);
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
describe("RGF", () => {
|
|
235
|
+
test("Variant #1: Use Eval instead of new Function", async () => {
|
|
236
|
+
var output = await JsConfuser(
|
|
237
|
+
`
|
|
238
|
+
function myFunction1(){
|
|
239
|
+
TEST_OUTPUT_SET(true);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
myFunction1();
|
|
243
|
+
`,
|
|
244
|
+
{
|
|
245
|
+
target: "node",
|
|
246
|
+
rgf: true,
|
|
247
|
+
lock: {
|
|
248
|
+
tamperProtection: true,
|
|
249
|
+
},
|
|
250
|
+
renameVariables: true,
|
|
251
|
+
|
|
252
|
+
// Allow RGF to transform 'myFunction1'
|
|
253
|
+
// Otherwise, RGF will skip 'myFunction1' as 'TEST_OUTPUT_SET' is an outside variable
|
|
254
|
+
globalVariables: new Set(["TEST_OUTPUT_SET"]),
|
|
255
|
+
}
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
expect(output).not.toContain(
|
|
259
|
+
"function myFunction1(){TEST_OUTPUT_SET(true)"
|
|
260
|
+
);
|
|
261
|
+
expect(output).toContain("eval");
|
|
262
|
+
expect(output).not.toContain("new Function");
|
|
263
|
+
|
|
264
|
+
var { TEST_OUTPUT, error } = evalInNonStrictMode(output);
|
|
265
|
+
|
|
266
|
+
expect(error).toBeNull();
|
|
267
|
+
expect(TEST_OUTPUT).toStrictEqual(true);
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
test("Variant #2: Detect Eval tamper", async () => {
|
|
271
|
+
var output = await JsConfuser(
|
|
272
|
+
`
|
|
273
|
+
function onTamperDetected(){
|
|
274
|
+
TEST_OUTPUT_SET("Correct Value");
|
|
275
|
+
}
|
|
276
|
+
function myFunction1(){
|
|
277
|
+
TEST_OUTPUT_SET("Function still called");
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
myFunction1();
|
|
281
|
+
`,
|
|
282
|
+
{
|
|
283
|
+
target: "node",
|
|
284
|
+
rgf: true,
|
|
285
|
+
lock: {
|
|
286
|
+
tamperProtection: true,
|
|
287
|
+
countermeasures: "onTamperDetected",
|
|
288
|
+
},
|
|
289
|
+
renameVariables: true,
|
|
290
|
+
|
|
291
|
+
// Allow RGF to transform 'myFunction1'
|
|
292
|
+
// Otherwise, RGF will skip 'myFunction1' as 'TEST_OUTPUT_SET' is an outside variable
|
|
293
|
+
globalVariables: new Set(["TEST_OUTPUT_SET"]),
|
|
294
|
+
}
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
expect(output).not.toContain("function myFunction1(){TEST_OUTPUT_SET(");
|
|
298
|
+
expect(output).toContain("eval");
|
|
299
|
+
|
|
300
|
+
// Inject 'eval' tamper code
|
|
301
|
+
output =
|
|
302
|
+
`var _eval = eval;
|
|
303
|
+
eval = (code)=>( TEST_OUTPUT_SET(code), console.log(code), _eval(code) );` +
|
|
304
|
+
output;
|
|
305
|
+
|
|
306
|
+
var { TEST_OUTPUT, error } = evalInNonStrictMode(output);
|
|
307
|
+
|
|
308
|
+
expect(TEST_OUTPUT).toStrictEqual("Correct Value");
|
|
309
|
+
expect(error).toBeTruthy(); // An error occurs because the RGF array was not initialized
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
describe("Strict Mode", () => {
|
|
314
|
+
test("Variant #1: Disallow Strict Mode", async () => {
|
|
315
|
+
var output = await JsConfuser(
|
|
316
|
+
`
|
|
317
|
+
"use strict"; // Note: Jest testing environment is already in Strict Mode
|
|
318
|
+
function onTamperDetected(){
|
|
319
|
+
TEST_OUTPUT = true;
|
|
320
|
+
}
|
|
321
|
+
`,
|
|
322
|
+
{
|
|
323
|
+
target: "node",
|
|
324
|
+
lock: {
|
|
325
|
+
tamperProtection: true,
|
|
326
|
+
countermeasures: "onTamperDetected",
|
|
327
|
+
},
|
|
328
|
+
}
|
|
329
|
+
);
|
|
330
|
+
|
|
331
|
+
var TEST_OUTPUT;
|
|
332
|
+
eval(output);
|
|
333
|
+
|
|
334
|
+
expect(TEST_OUTPUT).toStrictEqual(true);
|
|
335
|
+
});
|
|
336
|
+
});
|
|
@@ -211,6 +211,16 @@ test("Variant #11: Shorten 'undefined' to 'void 0'", async () => {
|
|
|
211
211
|
});
|
|
212
212
|
|
|
213
213
|
expect(output2).toContain("var x={[void 0]:1}");
|
|
214
|
+
|
|
215
|
+
var output3 = await JsConfuser(
|
|
216
|
+
`try { var undefined; (undefined) = true } catch(e) {}`,
|
|
217
|
+
{
|
|
218
|
+
target: "node",
|
|
219
|
+
minify: true,
|
|
220
|
+
}
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
eval(output3);
|
|
214
224
|
});
|
|
215
225
|
|
|
216
226
|
test("Variant #11: Shorten 'Infinity' to 1/0", async () => {
|
|
@@ -536,3 +546,30 @@ test("Variant #27: Preserve function.length property", async () => {
|
|
|
536
546
|
|
|
537
547
|
expect(TEST_OUTPUT).toStrictEqual(6);
|
|
538
548
|
});
|
|
549
|
+
|
|
550
|
+
// https://github.com/MichaelXF/js-confuser/issues/125
|
|
551
|
+
test("Variant #28: Don't break destructuring assignment", async () => {
|
|
552
|
+
var output = await JsConfuser(
|
|
553
|
+
`
|
|
554
|
+
let objectSlice = [];
|
|
555
|
+
objectSlice.push({
|
|
556
|
+
a: 1,
|
|
557
|
+
b: 2,
|
|
558
|
+
c: 3,
|
|
559
|
+
})
|
|
560
|
+
for (let {
|
|
561
|
+
a,
|
|
562
|
+
b,
|
|
563
|
+
c
|
|
564
|
+
} of objectSlice) {
|
|
565
|
+
TEST_OUTPUT = a + b + c;
|
|
566
|
+
}
|
|
567
|
+
`,
|
|
568
|
+
{ target: "node", minify: true }
|
|
569
|
+
);
|
|
570
|
+
|
|
571
|
+
var TEST_OUTPUT;
|
|
572
|
+
eval(output);
|
|
573
|
+
|
|
574
|
+
expect(TEST_OUTPUT).toStrictEqual(6);
|
|
575
|
+
});
|
|
@@ -326,3 +326,53 @@ test("Variant #10: Configurable by custom function option", async () => {
|
|
|
326
326
|
expect(TEST_OUTPUT_1).toStrictEqual(false);
|
|
327
327
|
expect(TEST_OUTPUT_2).toStrictEqual(true);
|
|
328
328
|
});
|
|
329
|
+
|
|
330
|
+
test("Variant #11: Function containing function should both be changed", async function () {
|
|
331
|
+
var output = await JsConfuser(
|
|
332
|
+
`
|
|
333
|
+
function FunctionA(){
|
|
334
|
+
function FunctionB(){
|
|
335
|
+
var bVar = 10;
|
|
336
|
+
return bVar
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
var bFn = FunctionB;
|
|
340
|
+
var aVar = bFn();
|
|
341
|
+
return aVar + 1
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
TEST_OUTPUT = FunctionA();
|
|
345
|
+
`,
|
|
346
|
+
{ target: "node", rgf: true }
|
|
347
|
+
);
|
|
348
|
+
|
|
349
|
+
// 2 means one Function changed, 3 means two Functions changed
|
|
350
|
+
expect(output.split("new Function").length).toStrictEqual(3);
|
|
351
|
+
|
|
352
|
+
var TEST_OUTPUT;
|
|
353
|
+
eval(output);
|
|
354
|
+
|
|
355
|
+
expect(TEST_OUTPUT).toStrictEqual(11);
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
test("Variant #12: Preserve Function.length", async function () {
|
|
359
|
+
var output = await JsConfuser(
|
|
360
|
+
`
|
|
361
|
+
function myFunction(a,b,c,d = ""){ // Function.length = 3
|
|
362
|
+
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
myFunction()
|
|
366
|
+
TEST_OUTPUT = myFunction.length
|
|
367
|
+
`,
|
|
368
|
+
{
|
|
369
|
+
target: "node",
|
|
370
|
+
rgf: true,
|
|
371
|
+
}
|
|
372
|
+
);
|
|
373
|
+
|
|
374
|
+
var TEST_OUTPUT;
|
|
375
|
+
eval(output);
|
|
376
|
+
|
|
377
|
+
expect(TEST_OUTPUT).toStrictEqual(3);
|
|
378
|
+
});
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.default = void 0;
|
|
7
|
-
|
|
8
|
-
var _gen = require("../../util/gen");
|
|
9
|
-
|
|
10
|
-
var _transform = _interopRequireDefault(require("../transform"));
|
|
11
|
-
|
|
12
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
13
|
-
|
|
14
|
-
class ChoiceFlowObfuscation extends _transform.default {
|
|
15
|
-
constructor(o) {
|
|
16
|
-
super(o);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
match(object, parents) {
|
|
20
|
-
return object.type == "IfStatement";
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
transform(object, parents) {
|
|
24
|
-
return () => {
|
|
25
|
-
var body = parents[0];
|
|
26
|
-
var element = object;
|
|
27
|
-
|
|
28
|
-
if (parents[0].type == "LabeledStatement") {
|
|
29
|
-
body = parents[1];
|
|
30
|
-
element = parents[0];
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
var before = [];
|
|
34
|
-
var isNested = parents[0].type == "IfStatement" && parents[0].alternate === object;
|
|
35
|
-
|
|
36
|
-
if (!isNested && (!Array.isArray(body) || body.indexOf(element) === -1)) {
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
var result = this.getPlaceholder();
|
|
41
|
-
before.push((0, _gen.VariableDeclaration)((0, _gen.VariableDeclarator)(result)));
|
|
42
|
-
var yesBody = object.consequent ? object.consequent.type == "BlockStatement" ? [...object.consequent.body] : [object.consequent] : [];
|
|
43
|
-
yesBody.unshift((0, _gen.ExpressionStatement)((0, _gen.AssignmentExpression)("=", (0, _gen.Identifier)(result), (0, _gen.Literal)(1))));
|
|
44
|
-
var noBody = object.alternate ? object.alternate.type == "BlockStatement" ? [...object.alternate.body] : [object.alternate] : [];
|
|
45
|
-
noBody.unshift((0, _gen.ExpressionStatement)((0, _gen.AssignmentExpression)("=", (0, _gen.Identifier)(result), (0, _gen.Literal)(1))));
|
|
46
|
-
var elseTest = (0, _gen.UnaryExpression)("!", (0, _gen.Identifier)(result));
|
|
47
|
-
var newObject = (0, _gen.TryStatement)([(0, _gen.IfStatement)({ ...object.test
|
|
48
|
-
}, [(0, _gen.ThrowStatement)((0, _gen.Identifier)(result))])], (0, _gen.CatchClause)((0, _gen.Identifier)(this.getPlaceholder()), yesBody), [(0, _gen.IfStatement)(elseTest, noBody)]);
|
|
49
|
-
|
|
50
|
-
if (isNested) {
|
|
51
|
-
this.replace(object, (0, _gen.BlockStatement)([...before, { ...newObject
|
|
52
|
-
}]));
|
|
53
|
-
} else {
|
|
54
|
-
body.splice(body.indexOf(element), 0, ...before);
|
|
55
|
-
this.replace(object, newObject);
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
exports.default = ChoiceFlowObfuscation;
|