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