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.
- package/.github/workflows/node.js.yml +2 -2
- package/CHANGELOG.md +55 -0
- package/README.md +346 -165
- package/dist/constants.js +6 -2
- package/dist/index.js +9 -21
- package/dist/obfuscator.js +19 -31
- package/dist/options.js +5 -5
- package/dist/order.js +1 -3
- package/dist/presets.js +6 -7
- package/dist/probability.js +2 -4
- package/dist/templates/bufferToString.js +13 -0
- package/dist/templates/crash.js +3 -3
- package/dist/templates/es5.js +18 -0
- package/dist/templates/functionLength.js +16 -0
- package/dist/transforms/calculator.js +77 -21
- package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +980 -367
- package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +4 -1
- package/dist/transforms/controlFlowFlattening/switchCaseObfuscation.js +25 -26
- package/dist/transforms/deadCode.js +33 -25
- package/dist/transforms/dispatcher.js +8 -4
- package/dist/transforms/es5/antiDestructuring.js +2 -0
- package/dist/transforms/es5/es5.js +31 -34
- package/dist/transforms/extraction/duplicateLiteralsRemoval.js +92 -58
- package/dist/transforms/finalizer.js +82 -0
- package/dist/transforms/flatten.js +229 -148
- package/dist/transforms/identifier/globalAnalysis.js +88 -0
- package/dist/transforms/identifier/globalConcealing.js +10 -83
- package/dist/transforms/identifier/movedDeclarations.js +35 -88
- package/dist/transforms/identifier/renameVariables.js +124 -59
- package/dist/transforms/identifier/variableAnalysis.js +58 -62
- package/dist/transforms/lock/lock.js +0 -37
- package/dist/transforms/minify.js +60 -57
- package/dist/transforms/opaquePredicates.js +1 -1
- package/dist/transforms/preparation/preparation.js +2 -2
- package/dist/transforms/preparation.js +231 -0
- package/dist/transforms/renameLabels.js +1 -1
- package/dist/transforms/rgf.js +139 -247
- package/dist/transforms/stack.js +128 -26
- package/dist/transforms/string/encoding.js +150 -179
- package/dist/transforms/string/stringCompression.js +14 -15
- package/dist/transforms/string/stringConcealing.js +25 -8
- package/dist/transforms/string/stringEncoding.js +13 -24
- package/dist/transforms/transform.js +12 -19
- package/dist/traverse.js +24 -10
- package/dist/util/gen.js +17 -1
- package/dist/util/identifiers.js +37 -3
- package/dist/util/insert.js +35 -4
- package/dist/util/random.js +15 -0
- package/docs/ControlFlowFlattening.md +595 -0
- package/{Countermeasures.md → docs/Countermeasures.md} +1 -15
- package/{Integrity.md → docs/Integrity.md} +2 -2
- package/docs/RGF.md +419 -0
- package/package.json +5 -5
- package/src/constants.ts +3 -0
- package/src/index.ts +2 -2
- package/src/obfuscator.ts +19 -31
- package/src/options.ts +14 -103
- package/src/order.ts +1 -5
- package/src/presets.ts +6 -7
- package/src/probability.ts +2 -3
- package/src/templates/bufferToString.ts +68 -0
- package/src/templates/crash.ts +15 -19
- package/src/templates/es5.ts +131 -0
- package/src/templates/functionLength.ts +14 -0
- package/src/transforms/calculator.ts +122 -59
- package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +1583 -571
- package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +4 -1
- package/src/transforms/deadCode.ts +383 -26
- package/src/transforms/dispatcher.ts +9 -4
- package/src/transforms/es5/antiDestructuring.ts +2 -0
- package/src/transforms/es5/es5.ts +32 -77
- package/src/transforms/extraction/duplicateLiteralsRemoval.ts +133 -129
- package/src/transforms/{hexadecimalNumbers.ts → finalizer.ts} +29 -13
- package/src/transforms/flatten.ts +357 -300
- package/src/transforms/identifier/globalAnalysis.ts +85 -0
- package/src/transforms/identifier/globalConcealing.ts +14 -103
- package/src/transforms/identifier/movedDeclarations.ts +49 -102
- package/src/transforms/identifier/renameVariables.ts +149 -78
- package/src/transforms/identifier/variableAnalysis.ts +66 -73
- package/src/transforms/lock/lock.ts +1 -42
- package/src/transforms/minify.ts +91 -75
- package/src/transforms/opaquePredicates.ts +2 -2
- package/src/transforms/preparation.ts +238 -0
- package/src/transforms/renameLabels.ts +2 -2
- package/src/transforms/rgf.ts +213 -405
- package/src/transforms/stack.ts +156 -36
- package/src/transforms/string/encoding.ts +115 -212
- package/src/transforms/string/stringCompression.ts +27 -18
- package/src/transforms/string/stringConcealing.ts +39 -9
- package/src/transforms/string/stringEncoding.ts +18 -18
- package/src/transforms/transform.ts +21 -23
- package/src/traverse.ts +23 -4
- package/src/types.ts +2 -1
- package/src/util/gen.ts +28 -3
- package/src/util/identifiers.ts +43 -2
- package/src/util/insert.ts +38 -3
- package/src/util/random.ts +13 -0
- package/test/code/Cash.test.ts +1 -1
- package/test/code/Dynamic.test.ts +12 -10
- package/test/code/ES6.src.js +146 -0
- package/test/code/ES6.test.ts +28 -2
- package/test/index.test.ts +2 -1
- package/test/probability.test.ts +44 -0
- package/test/templates/template.test.ts +1 -1
- package/test/transforms/antiTooling.test.ts +22 -0
- package/test/transforms/calculator.test.ts +40 -0
- package/test/transforms/controlFlowFlattening/controlFlowFlattening.test.ts +702 -160
- package/test/transforms/controlFlowFlattening/expressionObfuscation.test.ts +173 -0
- package/test/transforms/deadCode.test.ts +66 -15
- package/test/transforms/dispatcher.test.ts +20 -1
- package/test/transforms/es5/antiDestructuring.test.ts +16 -0
- package/test/transforms/flatten.test.ts +399 -86
- package/test/transforms/identifier/movedDeclarations.test.ts +63 -8
- package/test/transforms/identifier/renameVariables.test.ts +119 -0
- package/test/transforms/lock/antiDebug.test.ts +2 -2
- package/test/transforms/lock/lock.test.ts +1 -48
- package/test/transforms/minify.test.ts +104 -0
- package/test/transforms/preparation.test.ts +157 -0
- package/test/transforms/rgf.test.ts +261 -381
- package/test/transforms/stack.test.ts +143 -21
- package/test/transforms/string/stringCompression.test.ts +39 -0
- package/test/transforms/string/stringConcealing.test.ts +82 -0
- package/test/transforms/string/stringEncoding.test.ts +53 -2
- package/test/transforms/transform.test.ts +66 -0
- package/test/traverse.test.ts +139 -0
- package/test/util/identifiers.test.ts +113 -1
- package/test/util/insert.test.ts +57 -3
- package/src/transforms/controlFlowFlattening/choiceFlowObfuscation.ts +0 -87
- package/src/transforms/controlFlowFlattening/controlFlowObfuscation.ts +0 -203
- package/src/transforms/controlFlowFlattening/switchCaseObfuscation.ts +0 -130
- package/src/transforms/eval.ts +0 -89
- package/src/transforms/hideInitializingCode.ts +0 -432
- package/src/transforms/identifier/nameRecycling.ts +0 -280
- package/src/transforms/label.ts +0 -64
- package/src/transforms/preparation/nameConflicts.ts +0 -102
- package/src/transforms/preparation/preparation.ts +0 -176
- package/test/transforms/controlFlowFlattening/controlFlowObfuscation.test.ts +0 -101
- package/test/transforms/controlFlowFlattening/switchCaseObfuscation.test.ts +0 -120
- package/test/transforms/eval.test.ts +0 -131
- package/test/transforms/hideInitializingCode.test.ts +0 -336
- package/test/transforms/identifier/nameRecycling.test.ts +0 -205
- package/test/transforms/preparation/nameConflicts.test.ts +0 -52
- package/test/transforms/preparation/preparation.test.ts +0 -62
package/src/transforms/rgf.ts
CHANGED
|
@@ -3,37 +3,23 @@ import { reservedIdentifiers } from "../constants";
|
|
|
3
3
|
import Obfuscator from "../obfuscator";
|
|
4
4
|
import { ObfuscateOrder } from "../order";
|
|
5
5
|
import { ComputeProbabilityMap } from "../probability";
|
|
6
|
-
import
|
|
7
|
-
import traverse, { walk } from "../traverse";
|
|
6
|
+
import { walk } from "../traverse";
|
|
8
7
|
import {
|
|
9
8
|
ArrayExpression,
|
|
10
|
-
|
|
9
|
+
BlockStatement,
|
|
11
10
|
CallExpression,
|
|
12
|
-
ConditionalExpression,
|
|
13
|
-
ExpressionStatement,
|
|
14
|
-
FunctionExpression,
|
|
15
11
|
Identifier,
|
|
16
12
|
Literal,
|
|
17
|
-
Location,
|
|
18
13
|
MemberExpression,
|
|
19
14
|
NewExpression,
|
|
20
15
|
Node,
|
|
21
16
|
ReturnStatement,
|
|
22
|
-
SpreadElement,
|
|
23
17
|
ThisExpression,
|
|
24
18
|
VariableDeclaration,
|
|
25
19
|
VariableDeclarator,
|
|
26
20
|
} from "../util/gen";
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
getVarContext,
|
|
30
|
-
isVarContext,
|
|
31
|
-
isFunction,
|
|
32
|
-
prepend,
|
|
33
|
-
getDefiningContext,
|
|
34
|
-
clone,
|
|
35
|
-
} from "../util/insert";
|
|
36
|
-
import { getRandomString } from "../util/random";
|
|
21
|
+
import { getIdentifierInfo } from "../util/identifiers";
|
|
22
|
+
import { prepend, getDefiningContext } from "../util/insert";
|
|
37
23
|
import Transform from "./transform";
|
|
38
24
|
|
|
39
25
|
/**
|
|
@@ -44,437 +30,259 @@ import Transform from "./transform";
|
|
|
44
30
|
* Rigorous checks are in place to only include pure functions.
|
|
45
31
|
*
|
|
46
32
|
* `flatten` can attempt to make function reference-less. Recommended to have flatten enabled with RGF.
|
|
47
|
-
*
|
|
48
|
-
* | Mode | Description |
|
|
49
|
-
* | --- | --- |
|
|
50
|
-
* | `"all"` | Applies to all scopes |
|
|
51
|
-
* | `true` | Applies to the top level only |
|
|
52
|
-
* | `false` | Feature disabled |
|
|
53
33
|
*/
|
|
54
34
|
export default class RGF extends Transform {
|
|
35
|
+
// Array of all the `new Function` calls
|
|
36
|
+
arrayExpressionElements: Node[];
|
|
37
|
+
// The name of the array holding all the `new Function` expressions
|
|
38
|
+
arrayExpressionName: string;
|
|
39
|
+
|
|
55
40
|
constructor(o) {
|
|
56
41
|
super(o, ObfuscateOrder.RGF);
|
|
42
|
+
|
|
43
|
+
this.arrayExpressionName = this.getPlaceholder() + "_rgf";
|
|
44
|
+
this.arrayExpressionElements = [];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
apply(tree: Node): void {
|
|
48
|
+
super.apply(tree);
|
|
49
|
+
|
|
50
|
+
// Only add the array if there were converted functions
|
|
51
|
+
if (this.arrayExpressionElements.length > 0) {
|
|
52
|
+
prepend(
|
|
53
|
+
tree,
|
|
54
|
+
VariableDeclaration(
|
|
55
|
+
VariableDeclarator(
|
|
56
|
+
Identifier(this.arrayExpressionName),
|
|
57
|
+
ArrayExpression(this.arrayExpressionElements)
|
|
58
|
+
)
|
|
59
|
+
)
|
|
60
|
+
);
|
|
61
|
+
}
|
|
57
62
|
}
|
|
58
63
|
|
|
59
64
|
match(object, parents) {
|
|
60
|
-
return
|
|
65
|
+
return (
|
|
66
|
+
(object.type === "FunctionDeclaration" ||
|
|
67
|
+
object.type === "FunctionExpression") && // Does not apply to Arrow functions
|
|
68
|
+
!object.async && // Does not apply to async/generator functions
|
|
69
|
+
!object.generator
|
|
70
|
+
);
|
|
61
71
|
}
|
|
62
72
|
|
|
63
|
-
transform(
|
|
64
|
-
|
|
65
|
-
|
|
73
|
+
transform(object: Node, parents: Node[]) {
|
|
74
|
+
// Discard getter/setter methods
|
|
75
|
+
if (parents[0].type === "Property" && parents[0].value === object) {
|
|
76
|
+
if (
|
|
77
|
+
parents[0].method ||
|
|
78
|
+
parents[0].kind === "get" ||
|
|
79
|
+
parents[0].kind === "set"
|
|
80
|
+
) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Discard class methods
|
|
86
|
+
if (parents[0].type === "MethodDefinition" && parents[0].value === object) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Avoid applying to the countermeasures function
|
|
91
|
+
if (typeof this.options.lock?.countermeasures === "string") {
|
|
92
|
+
// function countermeasures(){...}
|
|
93
|
+
if (
|
|
94
|
+
object.type === "FunctionDeclaration" &&
|
|
95
|
+
object.id.type === "Identifier" &&
|
|
96
|
+
object.id.name === this.options.lock.countermeasures
|
|
97
|
+
) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
66
100
|
|
|
67
|
-
var
|
|
68
|
-
if (
|
|
101
|
+
// var countermeasures = function(){...}
|
|
102
|
+
if (
|
|
103
|
+
parents[0].type === "VariableDeclarator" &&
|
|
104
|
+
parents[0].init === object &&
|
|
105
|
+
parents[0].id.type === "Identifier" &&
|
|
106
|
+
parents[0].id.name === this.options.lock.countermeasures
|
|
107
|
+
) {
|
|
69
108
|
return;
|
|
70
109
|
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Check user option
|
|
113
|
+
if (!ComputeProbabilityMap(this.options.rgf, (x) => x, object?.id?.name))
|
|
114
|
+
return;
|
|
115
|
+
|
|
116
|
+
// Discard functions that use 'eval' function
|
|
117
|
+
if (object.$requiresEval) return;
|
|
118
|
+
|
|
119
|
+
// Check for 'this', 'arguments' (not allowed!)
|
|
120
|
+
var isIllegal = false;
|
|
121
|
+
walk(object, parents, (o, p) => {
|
|
122
|
+
if (
|
|
123
|
+
o.type === "ThisExpression" ||
|
|
124
|
+
o.type === "Super" ||
|
|
125
|
+
(o.type === "Identifier" && o.name === "arguments")
|
|
126
|
+
) {
|
|
127
|
+
isIllegal = true;
|
|
128
|
+
return "EXIT";
|
|
129
|
+
}
|
|
130
|
+
});
|
|
71
131
|
|
|
72
|
-
|
|
73
|
-
location: Location;
|
|
74
|
-
references: Set<string>;
|
|
75
|
-
name?: string;
|
|
76
|
-
}[] = [];
|
|
77
|
-
var queue: Location[] = [];
|
|
78
|
-
var names = new Map<string, number>();
|
|
79
|
-
var referenceSignatures: { [name: string]: string } = {};
|
|
132
|
+
if (isIllegal) return;
|
|
80
133
|
|
|
81
|
-
|
|
134
|
+
return () => {
|
|
135
|
+
// Make sure function is 'reference-less'
|
|
136
|
+
var definedMap = new Map<Node, Set<string>>();
|
|
137
|
+
var isReferenceLess = true;
|
|
138
|
+
var identifierPreventingTransformation: string;
|
|
82
139
|
|
|
83
|
-
walk(
|
|
140
|
+
walk(object, parents, (o, p) => {
|
|
84
141
|
if (
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
!
|
|
88
|
-
!object.async &&
|
|
89
|
-
!object.generator &&
|
|
90
|
-
getVarContext(parents[0], parents.slice(1)) === contextObject
|
|
142
|
+
o.type === "Identifier" &&
|
|
143
|
+
!reservedIdentifiers.has(o.name) &&
|
|
144
|
+
!this.options.globalVariables.has(o.name)
|
|
91
145
|
) {
|
|
92
|
-
|
|
93
|
-
if (
|
|
94
|
-
if (
|
|
95
|
-
parents[0].method ||
|
|
96
|
-
parents[0].kind === "get" ||
|
|
97
|
-
parents[0].kind === "set"
|
|
98
|
-
) {
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// Discard class methods
|
|
104
|
-
if (
|
|
105
|
-
parents[0].type === "MethodDefinition" &&
|
|
106
|
-
parents[0].value === object
|
|
107
|
-
) {
|
|
146
|
+
var info = getIdentifierInfo(o, p);
|
|
147
|
+
if (!info.spec.isReferenced) {
|
|
108
148
|
return;
|
|
109
149
|
}
|
|
110
150
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
if (
|
|
115
|
-
object.type === "FunctionDeclaration" &&
|
|
116
|
-
object.id.type === "Identifier" &&
|
|
117
|
-
object.id.name === this.options.lock.countermeasures
|
|
118
|
-
) {
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
151
|
+
if (info.spec.isDefined) {
|
|
152
|
+
// Add to defined map
|
|
153
|
+
var definingContext = getDefiningContext(o, p);
|
|
121
154
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
parents[0].id.type === "Identifier" &&
|
|
127
|
-
parents[0].id.name === this.options.lock.countermeasures
|
|
128
|
-
) {
|
|
129
|
-
return;
|
|
155
|
+
if (!definedMap.has(definingContext)) {
|
|
156
|
+
definedMap.set(definingContext, new Set([o.name]));
|
|
157
|
+
} else {
|
|
158
|
+
definedMap.get(definingContext).add(o.name);
|
|
130
159
|
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
*
|
|
141
|
-
* - Identify all the variables referenced and defined here
|
|
142
|
-
* - Identify is the 'this' keyword is used anywhere
|
|
143
|
-
*
|
|
144
|
-
* @param o
|
|
145
|
-
* @param p
|
|
146
|
-
* @returns
|
|
147
|
-
*/
|
|
148
|
-
const fnTraverser = (o, p) => {
|
|
149
|
-
if (
|
|
150
|
-
o.type == "Identifier" &&
|
|
151
|
-
!reservedIdentifiers.has(o.name) &&
|
|
152
|
-
!this.options.globalVariables.has(o.name)
|
|
153
|
-
) {
|
|
154
|
-
var info = getIdentifierInfo(o, p);
|
|
155
|
-
if (!info.spec.isReferenced) {
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
if (info.spec.isDefined && getDefiningContext(o, p) === object) {
|
|
159
|
-
defined.add(o.name);
|
|
160
|
-
} else {
|
|
161
|
-
referenced.add(o.name);
|
|
160
|
+
} else {
|
|
161
|
+
// This approach is dirty and does not account for hoisted FunctionDeclarations
|
|
162
|
+
var isDefinedAbove = false;
|
|
163
|
+
for (var pNode of p) {
|
|
164
|
+
if (definedMap.has(pNode)) {
|
|
165
|
+
if (definedMap.get(pNode).has(o.name)) {
|
|
166
|
+
isDefinedAbove = true;
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
162
169
|
}
|
|
163
170
|
}
|
|
164
171
|
|
|
165
|
-
if (
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
walk(object.params, [object, ...parents], fnTraverser);
|
|
171
|
-
walk(object.body, [object, ...parents], fnTraverser);
|
|
172
|
-
|
|
173
|
-
if (!isBound) {
|
|
174
|
-
defined.forEach((identifier) => {
|
|
175
|
-
referenced.delete(identifier);
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
object.params.forEach((param) => {
|
|
179
|
-
referenced.delete(param.name);
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
collect.push({
|
|
183
|
-
location: [object, parents],
|
|
184
|
-
references: referenced,
|
|
185
|
-
name: object.id?.name,
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
if (!collect.length) {
|
|
192
|
-
return;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
var miss = 0;
|
|
196
|
-
var start = collect.length * 2;
|
|
197
|
-
|
|
198
|
-
while (true) {
|
|
199
|
-
var hit = false;
|
|
200
|
-
|
|
201
|
-
collect.forEach(
|
|
202
|
-
({ name, references: references1, location: location1 }) => {
|
|
203
|
-
if (!references1.size && name) {
|
|
204
|
-
collect.forEach((o) => {
|
|
205
|
-
if (
|
|
206
|
-
o.location[0] !== location1[0] &&
|
|
207
|
-
o.references.size &&
|
|
208
|
-
o.references.delete(name)
|
|
209
|
-
) {
|
|
210
|
-
// console.log(collect);
|
|
172
|
+
if (!isDefinedAbove) {
|
|
173
|
+
isReferenceLess = false;
|
|
174
|
+
identifierPreventingTransformation = o.name;
|
|
211
175
|
|
|
212
|
-
|
|
213
|
-
}
|
|
214
|
-
});
|
|
176
|
+
return "EXIT";
|
|
215
177
|
}
|
|
216
178
|
}
|
|
217
|
-
);
|
|
218
|
-
if (hit) {
|
|
219
|
-
miss = 0;
|
|
220
|
-
} else {
|
|
221
|
-
miss++;
|
|
222
179
|
}
|
|
180
|
+
});
|
|
223
181
|
|
|
224
|
-
|
|
225
|
-
|
|
182
|
+
// This function is not 'reference-less', cannot be RGF'd
|
|
183
|
+
if (!isReferenceLess) {
|
|
184
|
+
if (object.id) {
|
|
185
|
+
this.log(
|
|
186
|
+
`${object?.id?.name}() cannot be transformed because of ${identifierPreventingTransformation}`
|
|
187
|
+
);
|
|
226
188
|
}
|
|
189
|
+
return;
|
|
227
190
|
}
|
|
228
191
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
object.type == "FunctionDeclaration" &&
|
|
237
|
-
typeof object.id.name === "string"
|
|
238
|
-
) {
|
|
239
|
-
var index = names.size;
|
|
240
|
-
|
|
241
|
-
names.set(object.id.name, index);
|
|
242
|
-
referenceSignatures[index] = getRandomString(10);
|
|
243
|
-
|
|
244
|
-
definingNodes.set(object.id.name, object.id);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
192
|
+
// Since `new Function` is completely isolated, create an entire new obfuscator and run remaining transformations.
|
|
193
|
+
// RGF runs early and needs completed code before converting to a string.
|
|
194
|
+
// (^ the variables haven't been renamed yet)
|
|
195
|
+
var obfuscator = new Obfuscator({
|
|
196
|
+
...this.options,
|
|
197
|
+
stringEncoding: false,
|
|
198
|
+
compact: true,
|
|
247
199
|
});
|
|
248
200
|
|
|
249
|
-
if (
|
|
250
|
-
|
|
201
|
+
if (obfuscator.options.lock) {
|
|
202
|
+
delete obfuscator.options.lock.countermeasures;
|
|
251
203
|
}
|
|
252
204
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
} else {
|
|
288
|
-
// fn()
|
|
289
|
-
// fn
|
|
290
|
-
|
|
291
|
-
// In most cases the identifier is being used like this (call expression, or referenced to be called later)
|
|
292
|
-
// Replace it with a simple wrapper function that will pass on the reference array
|
|
293
|
-
|
|
294
|
-
var conditionalExpression = ConditionalExpression(
|
|
295
|
-
Template(
|
|
296
|
-
`typeof ${referenceArray}[${index}] === "function" && ${referenceArray}[${index}]["${
|
|
297
|
-
referenceSignatures[index] || "_"
|
|
298
|
-
}"]`
|
|
299
|
-
).single().expression,
|
|
300
|
-
FunctionExpression(
|
|
301
|
-
[],
|
|
302
|
-
[
|
|
303
|
-
ReturnStatement(
|
|
304
|
-
// clone() is required!
|
|
305
|
-
CallExpression(clone(memberExpression), [
|
|
306
|
-
Identifier(referenceArray),
|
|
307
|
-
SpreadElement(Identifier("arguments")),
|
|
308
|
-
])
|
|
309
|
-
),
|
|
310
|
-
]
|
|
311
|
-
),
|
|
312
|
-
memberExpression
|
|
313
|
-
);
|
|
314
|
-
|
|
315
|
-
this.replace(o, conditionalExpression);
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
}
|
|
205
|
+
var transforms = obfuscator.array.filter(
|
|
206
|
+
(x) => x.priority > this.priority
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
var embeddedFunctionName = this.getPlaceholder();
|
|
210
|
+
|
|
211
|
+
var embeddedFunction = {
|
|
212
|
+
type: "FunctionDeclaration",
|
|
213
|
+
id: Identifier(embeddedFunctionName),
|
|
214
|
+
body: BlockStatement([...object.body.body]),
|
|
215
|
+
params: object.params,
|
|
216
|
+
async: false,
|
|
217
|
+
generator: false,
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
var tree = {
|
|
221
|
+
type: "Program",
|
|
222
|
+
body: [
|
|
223
|
+
embeddedFunction,
|
|
224
|
+
ReturnStatement(
|
|
225
|
+
CallExpression(
|
|
226
|
+
MemberExpression(
|
|
227
|
+
Identifier(embeddedFunctionName),
|
|
228
|
+
Literal("apply"),
|
|
229
|
+
true
|
|
230
|
+
),
|
|
231
|
+
[ThisExpression(), Identifier("arguments")]
|
|
232
|
+
)
|
|
233
|
+
),
|
|
234
|
+
],
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
transforms.forEach((transform) => {
|
|
238
|
+
transform.apply(tree);
|
|
322
239
|
});
|
|
323
240
|
|
|
324
|
-
var
|
|
325
|
-
var variableDeclaration = VariableDeclaration([
|
|
326
|
-
VariableDeclarator(Identifier(referenceArray), arrayExpression),
|
|
327
|
-
]);
|
|
328
|
-
|
|
329
|
-
prepend(contextObject, variableDeclaration);
|
|
330
|
-
|
|
331
|
-
queue.forEach(([object, parents]) => {
|
|
332
|
-
var name = object?.id?.name;
|
|
333
|
-
var signature = referenceSignatures[names.get(name)];
|
|
334
|
-
|
|
335
|
-
var embeddedName = name || this.getPlaceholder();
|
|
336
|
-
|
|
337
|
-
// Since `new Function` is completely isolated, create an entire new obfuscator and run remaining transformations.
|
|
338
|
-
// RGF runs early and needs completed code before converting to a string.
|
|
339
|
-
// (^ the variables haven't been renamed yet)
|
|
340
|
-
var obfuscator = new Obfuscator({
|
|
341
|
-
...this.options,
|
|
342
|
-
rgf: false,
|
|
343
|
-
globalVariables: new Set([
|
|
344
|
-
...this.options.globalVariables,
|
|
345
|
-
referenceArray,
|
|
346
|
-
]),
|
|
347
|
-
lock: {
|
|
348
|
-
integrity: false,
|
|
349
|
-
},
|
|
350
|
-
eval: false,
|
|
351
|
-
hideInitializingCode: false,
|
|
352
|
-
stringEncoding: false,
|
|
353
|
-
});
|
|
354
|
-
var transforms = Object.values(obfuscator.transforms).filter(
|
|
355
|
-
(x) => x.priority > this.priority
|
|
356
|
-
);
|
|
357
|
-
|
|
358
|
-
var embeddedFunction = {
|
|
359
|
-
...object,
|
|
360
|
-
type: "FunctionDeclaration",
|
|
361
|
-
id: Identifier(embeddedName),
|
|
362
|
-
};
|
|
363
|
-
|
|
364
|
-
var tree = {
|
|
365
|
-
type: "Program",
|
|
366
|
-
body: [
|
|
367
|
-
embeddedFunction,
|
|
368
|
-
ReturnStatement(
|
|
369
|
-
CallExpression(
|
|
370
|
-
MemberExpression(
|
|
371
|
-
Identifier(embeddedName),
|
|
372
|
-
Literal("call"),
|
|
373
|
-
true
|
|
374
|
-
),
|
|
375
|
-
[
|
|
376
|
-
Identifier("undefined"),
|
|
377
|
-
SpreadElement(
|
|
378
|
-
Template(
|
|
379
|
-
`Array.prototype.slice.call(arguments, 1)`
|
|
380
|
-
).single().expression
|
|
381
|
-
),
|
|
382
|
-
]
|
|
383
|
-
)
|
|
384
|
-
),
|
|
385
|
-
],
|
|
386
|
-
};
|
|
387
|
-
|
|
388
|
-
(tree as any).__hiddenDeclarations = VariableDeclaration(
|
|
389
|
-
VariableDeclarator(referenceArray)
|
|
390
|
-
);
|
|
391
|
-
(tree as any).__hiddenDeclarations.hidden = true;
|
|
392
|
-
(tree as any).__hiddenDeclarations.declarations[0].id.hidden = true;
|
|
393
|
-
|
|
394
|
-
transforms.forEach((transform) => {
|
|
395
|
-
transform.apply(tree);
|
|
396
|
-
});
|
|
397
|
-
|
|
398
|
-
// Find eval callbacks
|
|
399
|
-
traverse(tree, (o, p) => {
|
|
400
|
-
if (o.$eval) {
|
|
401
|
-
return () => {
|
|
402
|
-
o.$eval(o, p);
|
|
403
|
-
};
|
|
404
|
-
}
|
|
405
|
-
});
|
|
241
|
+
var toString = compileJsSync(tree, obfuscator.options);
|
|
406
242
|
|
|
407
|
-
|
|
243
|
+
// new Function(code)
|
|
244
|
+
var newFunctionExpression = NewExpression(Identifier("Function"), [
|
|
245
|
+
Literal(toString),
|
|
246
|
+
]);
|
|
408
247
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
248
|
+
// The index where this function is placed in the array
|
|
249
|
+
var newFunctionExpressionIndex = this.arrayExpressionElements.length;
|
|
250
|
+
|
|
251
|
+
// Add it to the array
|
|
252
|
+
this.arrayExpressionElements.push(newFunctionExpression);
|
|
253
|
+
|
|
254
|
+
// The member expression to retrieve this function
|
|
255
|
+
var memberExpression = MemberExpression(
|
|
256
|
+
Identifier(this.arrayExpressionName),
|
|
257
|
+
Literal(newFunctionExpressionIndex),
|
|
258
|
+
true
|
|
259
|
+
);
|
|
260
|
+
|
|
261
|
+
// Replace based on type
|
|
262
|
+
|
|
263
|
+
// (1) Function Declaration:
|
|
264
|
+
// - Replace body with call to new function
|
|
265
|
+
if (object.type === "FunctionDeclaration") {
|
|
266
|
+
object.body = BlockStatement([
|
|
267
|
+
ReturnStatement(
|
|
268
|
+
CallExpression(
|
|
269
|
+
MemberExpression(memberExpression, Literal("apply"), true),
|
|
270
|
+
[ThisExpression(), Identifier("arguments")]
|
|
271
|
+
)
|
|
272
|
+
),
|
|
412
273
|
]);
|
|
413
274
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
// This code marks the function object with a unique property
|
|
420
|
-
return CallExpression(
|
|
421
|
-
FunctionExpression(
|
|
422
|
-
[],
|
|
423
|
-
[
|
|
424
|
-
VariableDeclaration(VariableDeclarator("fn", fn)),
|
|
425
|
-
ExpressionStatement(
|
|
426
|
-
AssignmentExpression(
|
|
427
|
-
"=",
|
|
428
|
-
MemberExpression(
|
|
429
|
-
Identifier("fn"),
|
|
430
|
-
Literal(signature),
|
|
431
|
-
true
|
|
432
|
-
),
|
|
433
|
-
Literal(true)
|
|
434
|
-
)
|
|
435
|
-
),
|
|
436
|
-
ReturnStatement(Identifier("fn")),
|
|
437
|
-
]
|
|
438
|
-
),
|
|
439
|
-
[]
|
|
440
|
-
);
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
if (object.type === "FunctionDeclaration") {
|
|
444
|
-
arrayExpression.elements[names.get(name)] =
|
|
445
|
-
applySignature(newFunction);
|
|
446
|
-
|
|
447
|
-
if (Array.isArray(parents[0])) {
|
|
448
|
-
parents[0].splice(parents[0].indexOf(object), 1);
|
|
449
|
-
} else {
|
|
450
|
-
this.error(
|
|
451
|
-
new Error(
|
|
452
|
-
"Error deleting function declaration: " +
|
|
453
|
-
parents.map((x) => x.type).join(",")
|
|
454
|
-
)
|
|
455
|
-
);
|
|
456
|
-
}
|
|
457
|
-
} else {
|
|
458
|
-
// The wrapper function passes the reference array around
|
|
459
|
-
var wrapperFunction = FunctionExpression(
|
|
460
|
-
[],
|
|
461
|
-
[
|
|
462
|
-
ReturnStatement(
|
|
463
|
-
CallExpression(
|
|
464
|
-
MemberExpression(newFunction, Literal("call"), true),
|
|
465
|
-
[
|
|
466
|
-
Identifier("undefined"),
|
|
467
|
-
Identifier(referenceArray),
|
|
468
|
-
SpreadElement(Identifier("arguments")),
|
|
469
|
-
]
|
|
470
|
-
)
|
|
471
|
-
),
|
|
472
|
-
]
|
|
473
|
-
);
|
|
275
|
+
// The parameters are no longer needed ('arguments' is used to capture them)
|
|
276
|
+
object.params = [];
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
474
279
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
280
|
+
// (2) Function Expression:
|
|
281
|
+
// - Replace expression with member expression pointing to new function
|
|
282
|
+
if (object.type === "FunctionExpression") {
|
|
283
|
+
this.replace(object, memberExpression);
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
478
286
|
};
|
|
479
287
|
}
|
|
480
288
|
}
|