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
package/docs/Integrity.md
CHANGED
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
## `Integrity`
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
JS-Confuser can detect changes to the source code and terminate execution.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
- **⚠️ This can break your code!**
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Option name: `lock.integrity`
|
|
8
|
+
|
|
9
|
+
Option values: `true/false`
|
|
10
|
+
|
|
11
|
+
### Usage
|
|
8
12
|
|
|
9
13
|
```js
|
|
10
14
|
var JsConfuser = require("js-confuser");
|
|
11
15
|
|
|
12
|
-
|
|
16
|
+
var sourceCode = "console.log(1)"
|
|
17
|
+
|
|
18
|
+
JsConfuser.obfuscate(sourceCode, {
|
|
13
19
|
target: "browser",
|
|
14
20
|
lock: {
|
|
15
21
|
integrity: true,
|
|
@@ -19,35 +25,22 @@ JsConfuser.obfuscate("console.log(1)", {
|
|
|
19
25
|
});
|
|
20
26
|
```
|
|
21
27
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
```shell
|
|
25
|
-
<coming soon>
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## Example
|
|
28
|
+
### Example
|
|
29
29
|
|
|
30
30
|
Consider the following code:
|
|
31
31
|
|
|
32
32
|
```js
|
|
33
33
|
console.log(1)
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
The output:
|
|
37
34
|
|
|
38
|
-
|
|
39
|
-
> 1
|
|
35
|
+
// 1
|
|
40
36
|
```
|
|
41
37
|
|
|
42
38
|
The obfuscated code (from Usage):
|
|
43
39
|
|
|
44
40
|
```js
|
|
45
41
|
(function(){var jXwFUz=Math.imul||function(jXwFUz,m9pBnlk){m9pBnlk|=0;var n1mfO$O=(jXwFUz&4194303)*m9pBnlk;if(jXwFUz&4290772992)n1mfO$O+=(jXwFUz&4290772992)*m9pBnlk|0;return n1mfO$O|0};function m9pBnlk(n1mfO$O,humOEA){var DGCgjl=3735928559^humOEA;var S$63Fy1=1103547991^humOEA;for(var Lop2FFS=0,GC2VbAQ;Lop2FFS<n1mfO$O.length;Lop2FFS++){GC2VbAQ=n1mfO$O.charCodeAt(Lop2FFS);DGCgjl=jXwFUz(DGCgjl^GC2VbAQ,2654435761);S$63Fy1=jXwFUz(S$63Fy1^GC2VbAQ,1597334677)}DGCgjl=jXwFUz(DGCgjl^DGCgjl>>>16,2246822507)^jXwFUz(S$63Fy1^S$63Fy1>>>13,3266489909);S$63Fy1=jXwFUz(S$63Fy1^S$63Fy1>>>16,2246822507)^jXwFUz(DGCgjl^DGCgjl>>>13,3266489909);return 4294967296*(2097151&S$63Fy1)+(DGCgjl>>>0)}function n1mfO$O(jXwFUz){return jXwFUz.toString().replace(/ |\n|;|,|\{|\}|\(|\)/g,'')}function y3EzuX9(){console['log'](1)}var yzLesc=m9pBnlk(n1mfO$O(y3EzuX9),957);if(yzLesc==0x7a77799eaf937){return y3EzuX9.apply(this,arguments)}}())
|
|
46
|
-
```
|
|
47
42
|
|
|
48
|
-
|
|
49
|
-
```
|
|
50
|
-
> 1
|
|
43
|
+
// 1
|
|
51
44
|
```
|
|
52
45
|
|
|
53
46
|
Since only Integrity is enabled, it's pretty easy to find the original code: `console['log'](1)`.
|
|
@@ -58,18 +51,32 @@ Let's try to change the `console['log'](1)` to `console['log'](2)`:
|
|
|
58
51
|
(function(){var jXwFUz=Math.imul||function(jXwFUz,m9pBnlk){m9pBnlk|=0;var n1mfO$O=(jXwFUz&4194303)*m9pBnlk;if(jXwFUz&4290772992)n1mfO$O+=(jXwFUz&4290772992)*m9pBnlk|0;return n1mfO$O|0};function m9pBnlk(n1mfO$O,humOEA){var DGCgjl=3735928559^humOEA;var S$63Fy1=1103547991^humOEA;for(var Lop2FFS=0,GC2VbAQ;Lop2FFS<n1mfO$O.length;Lop2FFS++){GC2VbAQ=n1mfO$O.charCodeAt(Lop2FFS);DGCgjl=jXwFUz(DGCgjl^GC2VbAQ,2654435761);S$63Fy1=jXwFUz(S$63Fy1^GC2VbAQ,1597334677)}DGCgjl=jXwFUz(DGCgjl^DGCgjl>>>16,2246822507)^jXwFUz(S$63Fy1^S$63Fy1>>>13,3266489909);S$63Fy1=jXwFUz(S$63Fy1^S$63Fy1>>>16,2246822507)^jXwFUz(DGCgjl^DGCgjl>>>13,3266489909);return 4294967296*(2097151&S$63Fy1)+(DGCgjl>>>0)}function n1mfO$O(jXwFUz){return jXwFUz.toString().replace(/ |\n|;|,|\{|\}|\(|\)/g,'')}function y3EzuX9(){console['log'](2)}var yzLesc=m9pBnlk(n1mfO$O(y3EzuX9),957);if(yzLesc==0x7a77799eaf937){return y3EzuX9.apply(this,arguments)}}())
|
|
59
52
|
```
|
|
60
53
|
|
|
61
|
-
The program no longer outputs anything. Integrity detected the change and stopped execution.
|
|
54
|
+
The program no longer outputs anything. Integrity has detected the change and stopped execution.
|
|
55
|
+
|
|
56
|
+
### How is this possible?
|
|
57
|
+
|
|
58
|
+
JavaScript has a sneaky method to view the source code any function. Calling `Function.toString()` on any function reveals the raw source code.
|
|
59
|
+
|
|
60
|
+
Integrity uses a hashing algorithm on the obfuscated code during the obfuscation-phase. The obfuscator then places checksum functions throughout the output code to verify it's unchanged at runtime.
|
|
61
|
+
|
|
62
|
+
An additional RegEx is utilized to remove spaces, newlines, braces, and commas. This ensures the hash isn't too sensitive.
|
|
62
63
|
|
|
63
|
-
|
|
64
|
+
### Tamper Detection
|
|
64
65
|
|
|
65
|
-
|
|
66
|
-
Integrity hashes the code during obfuscation phase and embeds an IF-statement within the code. We used an additional regex to remove spaces, newlines, braces,
|
|
67
|
-
and commas to ensure the hash isn't too sensitive.
|
|
66
|
+
If tampering is detected, the `lock.countermeasures` function will be invoked. If you don't provide a `lock.countermeasures` function, the default behavior is to crash the program.
|
|
68
67
|
|
|
69
|
-
|
|
68
|
+
[Learn more about the countermeasures function](Countermeasures.md).
|
|
69
|
+
|
|
70
|
+
### Potential Issues
|
|
70
71
|
|
|
71
72
|
If you decide to use Integrity, consider the following:
|
|
72
73
|
|
|
73
|
-
1. Any build-tools must not modify the locked code. The code can't be changed after
|
|
74
|
-
2.
|
|
74
|
+
1. Any build-tools must not modify the locked code. The code can't be changed after JS-Confuser is applied.
|
|
75
|
+
2. `Function.toString()` functionality may not be enabled in your environment (bytenode)
|
|
76
|
+
|
|
77
|
+
### See also
|
|
78
|
+
|
|
79
|
+
- [Countermeasures](Countermeasures.md)
|
|
80
|
+
- [Tamper Protection](TamperProtection.md)
|
|
81
|
+
|
|
75
82
|
|
package/docs/RGF.md
CHANGED
|
@@ -416,4 +416,9 @@ RGF only applies to:
|
|
|
416
416
|
- Function Declarations or Expressions
|
|
417
417
|
- Cannot be async / generator function
|
|
418
418
|
- Cannot rely on outside-scoped variables
|
|
419
|
-
- Cannot use `this`, `arguments`, or `eval`
|
|
419
|
+
- Cannot use `this`, `arguments`, or `eval`
|
|
420
|
+
|
|
421
|
+
### See also
|
|
422
|
+
|
|
423
|
+
- [Control Flow Flattening](./ControlFlowFlattening.md)
|
|
424
|
+
- [Tamper Protection](./TamperProtection.md)
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
## `Rename Variables`
|
|
2
|
+
|
|
3
|
+
Determines if variables should be renamed. (`true/false`)
|
|
4
|
+
|
|
5
|
+
Option name: `controlFlowFlattening`
|
|
6
|
+
|
|
7
|
+
Option values: `true/false`
|
|
8
|
+
|
|
9
|
+
```js
|
|
10
|
+
// Input
|
|
11
|
+
var twoSum = function (nums, target) {
|
|
12
|
+
var hash = {};
|
|
13
|
+
var len = nums.length;
|
|
14
|
+
for (var i = 0; i < len; i++) {
|
|
15
|
+
if (nums[i] in hash) return [hash[nums[i]], i];
|
|
16
|
+
hash[target - nums[i]] = i;
|
|
17
|
+
}
|
|
18
|
+
return [-1, -1];
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
var test = function () {
|
|
22
|
+
var inputNums = [2, 7, 11, 15];
|
|
23
|
+
var inputTarget = 9;
|
|
24
|
+
var expectedResult = [0, 1];
|
|
25
|
+
|
|
26
|
+
var actualResult = twoSum(inputNums, inputTarget);
|
|
27
|
+
ok(actualResult[0] === expectedResult[0]);
|
|
28
|
+
ok(actualResult[1] === expectedResult[1]);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
test();
|
|
32
|
+
|
|
33
|
+
// Output
|
|
34
|
+
var _O2mOcF = function (kB4uXM, w_07HXS) {
|
|
35
|
+
var ZLTJcx = {};
|
|
36
|
+
var sXQOaUx = kB4uXM["length"];
|
|
37
|
+
for (var JYYxEk = 0; JYYxEk < sXQOaUx; JYYxEk++) {
|
|
38
|
+
if (kB4uXM[JYYxEk] in ZLTJcx) {
|
|
39
|
+
return [ZLTJcx[kB4uXM[JYYxEk]], JYYxEk];
|
|
40
|
+
}
|
|
41
|
+
ZLTJcx[w_07HXS - kB4uXM[JYYxEk]] = JYYxEk;
|
|
42
|
+
}
|
|
43
|
+
return [-1, -1];
|
|
44
|
+
};
|
|
45
|
+
var qFaI6S = function () {
|
|
46
|
+
var fZpeOw = [2, 7, 11, 15];
|
|
47
|
+
var UJ62R2c = 9;
|
|
48
|
+
var dG6R0cV = [0, 1];
|
|
49
|
+
var WgYXwn = _O2mOcF(fZpeOw, UJ62R2c);
|
|
50
|
+
void (ok(WgYXwn[0] === dG6R0cV[0]), ok(WgYXwn[1] === dG6R0cV[1]));
|
|
51
|
+
};
|
|
52
|
+
qFaI6S();
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Custom Implementation
|
|
56
|
+
|
|
57
|
+
A custom function can provided as the `renameVariables` option, determining if a variable should be renamed.
|
|
58
|
+
|
|
59
|
+
| Parameter | Type | Description |
|
|
60
|
+
| --- | --- | --- |
|
|
61
|
+
| `name` | `string` | The variable proposed to be renamed |
|
|
62
|
+
| `isGlobal` | `boolean` | Is the variable defined at the global level? |
|
|
63
|
+
|
|
64
|
+
```js
|
|
65
|
+
{
|
|
66
|
+
target: "node",
|
|
67
|
+
|
|
68
|
+
// Avoid renaming a certain variable
|
|
69
|
+
renameVariables: name=>name != "jQuery",
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Access the renamed variable
|
|
74
|
+
|
|
75
|
+
The `__JS_CONFUSER_VAR__` function provides a method to access variable mappings. This is especially useful for `eval()` scenarios where you want preserve the mapping.
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
```js
|
|
79
|
+
// Input
|
|
80
|
+
var message = "Hello world!";
|
|
81
|
+
eval(`console.log(${ __JS_CONFUSER_VAR__(message) })`);
|
|
82
|
+
|
|
83
|
+
console.log("message was renamed to", __JS_CONFUSER_VAR__(message));
|
|
84
|
+
|
|
85
|
+
// Output
|
|
86
|
+
var nSgZyJf = "Hello world!";
|
|
87
|
+
eval(`console.log(${"nSgZyJf"})`) // "Hello world!"
|
|
88
|
+
console["log"]("message was renamed to", "nSgZyJf") // message was renamed to nSgZyJf
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Even if `Rename Variables` is disabled, the `__JS_CONFUSER_VAR__` will still be removed. (The original name will be returned as a string)
|
|
92
|
+
|
|
93
|
+
### Never rename a variable
|
|
94
|
+
|
|
95
|
+
The `__NO_JS_CONFUSER_RENAME__` prefix disables renaming a certain variable. This can be useful for debugging the obfuscator.
|
|
96
|
+
|
|
97
|
+
```js
|
|
98
|
+
// Input
|
|
99
|
+
var __NO_JS_CONFUSER_RENAME__message1 = "My first message"
|
|
100
|
+
var message2 = "My other message"
|
|
101
|
+
|
|
102
|
+
console.log(__NO_JS_CONFUSER_RENAME__message1)
|
|
103
|
+
console.log(message2)
|
|
104
|
+
|
|
105
|
+
// Output
|
|
106
|
+
var __NO_JS_CONFUSER_RENAME__message1 = "My first message";
|
|
107
|
+
var jRLf713 = "My other message";
|
|
108
|
+
|
|
109
|
+
console.log(__NO_JS_CONFUSER_RENAME__message1),
|
|
110
|
+
console.log(jRLf713)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
## `Tamper Protection`
|
|
2
|
+
|
|
3
|
+
Tamper Protection safeguards the runtime behavior from being altered by JavaScript pitfalls.
|
|
4
|
+
|
|
5
|
+
**⚠️ Tamper Protection requires eval and ran in a non-strict mode environment!**
|
|
6
|
+
|
|
7
|
+
- **This can break your code.**
|
|
8
|
+
- **Due to the security concerns of arbitrary code execution, you must enable this yourself.**
|
|
9
|
+
|
|
10
|
+
Option name: `lock.tamperProtection`
|
|
11
|
+
|
|
12
|
+
Option values: `true/false/Function`
|
|
13
|
+
|
|
14
|
+
### 1. Improves `Global Concealing`
|
|
15
|
+
|
|
16
|
+
Tamper Protection with `Global Concealing` can detect at runtime if certain global functions have been monkey-patched. The following code exemplifies this:
|
|
17
|
+
|
|
18
|
+
#### (a) Native function check
|
|
19
|
+
|
|
20
|
+
```js
|
|
21
|
+
var _fetch = fetch;
|
|
22
|
+
fetch = (...args)=>{
|
|
23
|
+
console.log("Fetch request intercepted!", ...args)
|
|
24
|
+
return _fetch(...args)
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
This monkey-patch can be detected by inspecting the `fetch.toString()` value:
|
|
29
|
+
|
|
30
|
+
```js
|
|
31
|
+
// Untampered
|
|
32
|
+
fetch.toString() // "function fetch() { [native code] }"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
// Tampered
|
|
36
|
+
fetch.toString() // "(...args)=>{\n console.log("Fetch request intercepted!", ...args)\n return _fetch(...args)\n}"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Certain global functions are checked before each invocation to ensure that (1) the arguments cannot be intercepted and (2) their behavior cannot be altered.
|
|
40
|
+
|
|
41
|
+
#### (b) Stealthy global
|
|
42
|
+
|
|
43
|
+
A direct `eval` invocation can access the local scope, only if it has not been redefined.
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
let root = {};
|
|
47
|
+
eval("root=this"); // Window {window: ...}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
This method securely obtains the real global object for both the browser and NodeJS. Properties on the global object can still be changed however.
|
|
51
|
+
|
|
52
|
+
### 2. Improves `RGF`
|
|
53
|
+
|
|
54
|
+
RGF (Runtime-Generated-Functions) behavior's can be altered by overriding the default `Function` constructor.
|
|
55
|
+
This allows a reverse engineer to inspect the concealed code and alter the behavior of the application.
|
|
56
|
+
|
|
57
|
+
When `lock.tamperProtection` is enabled, `RGF` will no longer use the `Function` constructor.
|
|
58
|
+
Instead, `eval` will be used with a strict integrity check.
|
|
59
|
+
|
|
60
|
+
```js
|
|
61
|
+
let check = false;
|
|
62
|
+
eval("check = true")
|
|
63
|
+
if (!check) {
|
|
64
|
+
throw new Error("Eval was redefined")
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const myFunction = eval("function abc(){}; abc");
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Eval loses it's local scope access when redefined by a monkey-patched function. This example ensures the concealed code cannot be inspected or behavior be changed.
|
|
71
|
+
|
|
72
|
+
[Learn more about RGF](RGF.md).
|
|
73
|
+
|
|
74
|
+
### Custom Implementation
|
|
75
|
+
|
|
76
|
+
You can provide a custom implementation for `lock.tamperProtection` to control which functions get the native function check.
|
|
77
|
+
|
|
78
|
+
```js
|
|
79
|
+
{
|
|
80
|
+
target: "node",
|
|
81
|
+
lock: {
|
|
82
|
+
tamperProtection: (fnName) => fnName === "console.log"
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Disallows Strict Mode
|
|
88
|
+
|
|
89
|
+
Tamper Protection requires the script to run in non-strict mode. Detection of the script in Strict Mode will be considered tampering. You can control the tampering response using the `lock.countermeasures` option, as detailed in the next section.
|
|
90
|
+
|
|
91
|
+
### Tamper Detection
|
|
92
|
+
|
|
93
|
+
If tampering is detected, the `lock.countermeasures` function will be invoked. If you don't provide a `lock.countermeasures` function, the default behavior is to crash the program.
|
|
94
|
+
|
|
95
|
+
[Learn more about the countermeasures function](Countermeasures.md).
|
|
96
|
+
|
|
97
|
+
### See also
|
|
98
|
+
|
|
99
|
+
- [Countermeasures](Countermeasures.md)
|
|
100
|
+
- [RGF](RGF.md)
|
package/docs/Template.md
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
## `Template`
|
|
2
|
+
|
|
3
|
+
The Template API provides an easy way to parse code snippets into AST subtrees.
|
|
4
|
+
These AST subtrees can added to the obfuscated code, tailored with custom variable names and logic.
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
### 1. Basic string interpolation
|
|
8
|
+
|
|
9
|
+
Interpolated strings can use the `{name}` syntax to be replaced. This allows you to create custom-named functions exemplified in the following example:
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
import JsConfuser from "js-confuser"
|
|
13
|
+
|
|
14
|
+
var Base64Template = new JsConfuser.Template(`
|
|
15
|
+
function {name}(str){
|
|
16
|
+
return btoa(str)
|
|
17
|
+
}
|
|
18
|
+
`);
|
|
19
|
+
|
|
20
|
+
var functionDeclaration = Base64Template.single({
|
|
21
|
+
name: "atob"
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
console.log(functionDeclaration);
|
|
25
|
+
// Node {
|
|
26
|
+
// type: 'FunctionDeclaration',
|
|
27
|
+
// start: 3,
|
|
28
|
+
// end: 47,
|
|
29
|
+
// id: Node { type: 'Identifier', start: 12, end: 16, name: 'atob' },
|
|
30
|
+
// expression: false,
|
|
31
|
+
// generator: false,
|
|
32
|
+
// async: false,
|
|
33
|
+
// params: [ Node { type: 'Identifier', start: 17, end: 20, name: 'str' } ],
|
|
34
|
+
// body: Node { type: 'BlockStatement', start: 21, end: 47, body: [ [Node] ] }
|
|
35
|
+
// }
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
This simply preprocesses the `{name}` to `"atob"` before parsing. This behavior can let additional code to be inserted and does not properly escape strings. To avoid these pitfalls, use AST subtree insertion.
|
|
39
|
+
|
|
40
|
+
### 2. AST subtree insertion
|
|
41
|
+
|
|
42
|
+
```js
|
|
43
|
+
var Base64Template = new JsConfuser.Template(`
|
|
44
|
+
function {name}(str){
|
|
45
|
+
{getWindow}
|
|
46
|
+
return {getWindowName}btoa(str)
|
|
47
|
+
}`)
|
|
48
|
+
|
|
49
|
+
var functionDeclaration = Base64Template.single({
|
|
50
|
+
name: "atob",
|
|
51
|
+
getWindowName: "newWindow",
|
|
52
|
+
getWindow: () => {
|
|
53
|
+
var code = "var newWindow = {}";
|
|
54
|
+
return acorn.parse(code).body[0];
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Here, the `getWindow` variable is passed as function that returns an AST subtree. This must be a `Node` object, `Node[]` array, or another Template.
|
|
60
|
+
Optionally, the function can be replaced with the return value if it's already computed.
|
|
61
|
+
|
|
62
|
+
When utilizing AST-interpolated variables, an additional traversal will need to be ran to replace the plain Identifier nodes.
|
|
63
|
+
|
|
64
|
+
Regular string interpolation does not require an additional traversal.
|
|
65
|
+
|
|
66
|
+
### 3. Template subtree insertion
|
|
67
|
+
|
|
68
|
+
```js
|
|
69
|
+
var NewWindowTemplate = new JsConfuser.Template(`
|
|
70
|
+
var {NewWindowName} = {};
|
|
71
|
+
`);
|
|
72
|
+
|
|
73
|
+
var Base64Template = new JsConfuser.Template(`
|
|
74
|
+
function {name}(str){
|
|
75
|
+
{NewWindowTemplate}
|
|
76
|
+
return {NewWindowName}.btoa(str)
|
|
77
|
+
}`)
|
|
78
|
+
|
|
79
|
+
var functionDeclaration = Base64Template.single({
|
|
80
|
+
name: "atob",
|
|
81
|
+
NewWindowName: "newWindow",
|
|
82
|
+
NewWindowTemplate: NewWindowTemplate
|
|
83
|
+
});
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
The variables are passed into the child templates. This allows you to not have to repeat the `NewWindowName` variable.
|
|
87
|
+
|
|
88
|
+
### `new Template(template)`
|
|
89
|
+
|
|
90
|
+
Creates a new Template instance. You can pass multiple templates and a random one will be chosen each interpolation.
|
|
91
|
+
|
|
92
|
+
| Parameter | Type | Description |
|
|
93
|
+
| --- | --- | --- |
|
|
94
|
+
| `template` | `string` | The source code for the Template |
|
|
95
|
+
|
|
96
|
+
### `template.compile(variables)`
|
|
97
|
+
|
|
98
|
+
Compiles the template and returns a Node array (`Node[]`)
|
|
99
|
+
|
|
100
|
+
Returns the equivalent of a [ESTree `Program.body`](https://github.com/estree/estree/blob/master/es5.md#programs)
|
|
101
|
+
|
|
102
|
+
| Parameter | Type | Description |
|
|
103
|
+
| --- | --- | --- |
|
|
104
|
+
| `variables` | `object` | An object of variables |
|
|
105
|
+
|
|
106
|
+
### `template.single(variables)`
|
|
107
|
+
|
|
108
|
+
Compiles the template and returns the first Node. (`Node`)
|
|
109
|
+
|
|
110
|
+
An error will thrown if multiple nodes were parsed. Use this function for singular expressions/declarations.
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
Returns the equivalent of a [ESTree `Program.body[0]`](https://github.com/estree/estree/blob/master/es5.md#programs)
|
|
114
|
+
|
|
115
|
+
| Parameter | Type | Description |
|
|
116
|
+
| --- | --- | --- |
|
|
117
|
+
| `variables` | `object` | An object of variables |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "js-confuser",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.3",
|
|
4
4
|
"description": "JavaScript Obfuscation Tool.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
"author": "MichaelXF",
|
|
23
23
|
"license": "MIT",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"acorn": "^8.
|
|
26
|
-
"escodegen": "^2.
|
|
25
|
+
"acorn": "^8.12.1",
|
|
26
|
+
"escodegen": "^2.1.0"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@babel/cli": "^7.17.6",
|
package/src/constants.ts
CHANGED
|
@@ -82,3 +82,20 @@ export const reservedIdentifiers = new Set([
|
|
|
82
82
|
|
|
83
83
|
export const noRenameVariablePrefix = "__NO_JS_CONFUSER_RENAME__";
|
|
84
84
|
export const placeholderVariablePrefix = "__p_";
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Tells the obfuscator this function is predictable:
|
|
88
|
+
* - Never called with extraneous parameters
|
|
89
|
+
*/
|
|
90
|
+
export const predictableFunctionTag = "__JS_PREDICT__";
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Tells the obfuscator this function is critical for the Obfuscated code.
|
|
94
|
+
* - Example: string decryption function
|
|
95
|
+
*/
|
|
96
|
+
export const criticalFunctionTag = "__JS_CRITICAL__";
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Allows the user to grab the variable name of a renamed variable.
|
|
100
|
+
*/
|
|
101
|
+
export const variableFunctionName = "__JS_CONFUSER_VAR__";
|
package/src/index.ts
CHANGED
|
@@ -2,6 +2,7 @@ import compileJs, { compileJsSync } from "./compiler";
|
|
|
2
2
|
import parseJS, { parseSync } from "./parser";
|
|
3
3
|
import Obfuscator from "./obfuscator";
|
|
4
4
|
import Transform from "./transforms/transform";
|
|
5
|
+
import Template from "./templates/template";
|
|
5
6
|
import { remove$Properties } from "./util/object";
|
|
6
7
|
import presets from "./presets";
|
|
7
8
|
|
|
@@ -39,7 +40,7 @@ export async function obfuscateAST(AST, options: ObfuscateOptions) {
|
|
|
39
40
|
|
|
40
41
|
options = await correctOptions(options);
|
|
41
42
|
|
|
42
|
-
var obfuscator = new Obfuscator(options);
|
|
43
|
+
var obfuscator = new Obfuscator(options as any);
|
|
43
44
|
|
|
44
45
|
await obfuscator.apply(AST);
|
|
45
46
|
|
|
@@ -70,7 +71,7 @@ var JsConfuser: IJsConfuser = async function (
|
|
|
70
71
|
|
|
71
72
|
options.verbose && console.log("* Obfuscating...");
|
|
72
73
|
|
|
73
|
-
var obfuscator = new Obfuscator(options);
|
|
74
|
+
var obfuscator = new Obfuscator(options as any);
|
|
74
75
|
|
|
75
76
|
await obfuscator.apply(tree);
|
|
76
77
|
|
|
@@ -96,7 +97,7 @@ export const debugTransformations: IJsConfuserDebugTransformations =
|
|
|
96
97
|
var frames = [];
|
|
97
98
|
|
|
98
99
|
var tree = parseSync(code);
|
|
99
|
-
var obfuscator = new Obfuscator(options);
|
|
100
|
+
var obfuscator = new Obfuscator(options as any);
|
|
100
101
|
|
|
101
102
|
var time = Date.now();
|
|
102
103
|
|
|
@@ -141,7 +142,7 @@ export const debugObfuscation: IJsConfuserDebugObfuscation = async function (
|
|
|
141
142
|
|
|
142
143
|
const parseTime = performance.now() - beforeParseTime;
|
|
143
144
|
|
|
144
|
-
var obfuscator = new Obfuscator(options);
|
|
145
|
+
var obfuscator = new Obfuscator(options as any);
|
|
145
146
|
var totalTransforms = obfuscator.array.length;
|
|
146
147
|
|
|
147
148
|
var transformationTimes = Object.create(null);
|
|
@@ -183,6 +184,7 @@ JsConfuser.debugTransformations = debugTransformations;
|
|
|
183
184
|
JsConfuser.debugObfuscation = debugObfuscation;
|
|
184
185
|
JsConfuser.Obfuscator = Obfuscator;
|
|
185
186
|
JsConfuser.Transform = Transform;
|
|
187
|
+
JsConfuser.Template = Template;
|
|
186
188
|
|
|
187
189
|
if (typeof window !== "undefined") {
|
|
188
190
|
window["JsConfuser"] = JsConfuser;
|
|
@@ -193,4 +195,4 @@ if (typeof global !== "undefined") {
|
|
|
193
195
|
|
|
194
196
|
export default JsConfuser;
|
|
195
197
|
|
|
196
|
-
export { presets, Obfuscator, Transform };
|
|
198
|
+
export { presets, Obfuscator, Transform, Template };
|