js-confuser 2.0.0-alpha.5 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/ISSUE_TEMPLATE/bug_report.md +43 -43
- package/.github/ISSUE_TEMPLATE/feature_request.md +20 -20
- package/.github/workflows/node.js.yml +28 -28
- package/.prettierrc +4 -4
- package/CHANGELOG.md +1015 -989
- package/CODE_OF_CONDUCT.md +131 -131
- package/CONTRIBUTING.md +52 -52
- package/LICENSE +21 -21
- package/Migration.md +72 -71
- package/README.md +86 -78
- package/dist/constants.js +43 -43
- package/dist/index.js +14 -23
- package/dist/obfuscator.js +31 -25
- package/dist/order.js +4 -4
- package/dist/presets.js +31 -31
- package/dist/templates/integrityTemplate.js +4 -4
- package/dist/templates/template.js +1 -2
- package/dist/transforms/astScrambler.js +1 -2
- package/dist/transforms/calculator.js +1 -2
- package/dist/transforms/controlFlowFlattening.js +93 -63
- package/dist/transforms/deadCode.js +1 -2
- package/dist/transforms/dispatcher.js +4 -5
- package/dist/transforms/extraction/duplicateLiteralsRemoval.js +1 -2
- package/dist/transforms/extraction/objectExtraction.js +1 -2
- package/dist/transforms/finalizer.js +1 -2
- package/dist/transforms/flatten.js +1 -2
- package/dist/transforms/identifier/globalConcealing.js +15 -2
- package/dist/transforms/identifier/movedDeclarations.js +8 -7
- package/dist/transforms/identifier/renameVariables.js +7 -7
- package/dist/transforms/lock/integrity.js +11 -10
- package/dist/transforms/lock/lock.js +2 -3
- package/dist/transforms/minify.js +11 -29
- package/dist/transforms/opaquePredicates.js +1 -2
- package/dist/transforms/pack.js +5 -2
- package/dist/transforms/plugin.js +18 -19
- package/dist/transforms/preparation.js +16 -16
- package/dist/transforms/renameLabels.js +1 -2
- package/dist/transforms/rgf.js +8 -9
- package/dist/transforms/shuffle.js +1 -2
- package/dist/transforms/string/encoding.js +1 -2
- package/dist/transforms/string/stringCompression.js +3 -4
- package/dist/transforms/string/stringConcealing.js +8 -3
- package/dist/transforms/string/stringEncoding.js +1 -2
- package/dist/transforms/variableMasking.js +1 -2
- package/dist/utils/NameGen.js +2 -2
- package/dist/utils/PredicateGen.js +1 -2
- package/dist/utils/ast-utils.js +87 -88
- package/dist/utils/function-utils.js +8 -8
- package/dist/utils/node.js +5 -6
- package/dist/utils/object-utils.js +4 -4
- package/dist/utils/random-utils.js +20 -20
- package/dist/utils/static-utils.js +1 -2
- package/dist/validateOptions.js +4 -7
- package/index.d.ts +17 -17
- package/package.json +61 -59
- package/src/constants.ts +168 -168
- package/src/index.ts +118 -118
- package/src/obfuscationResult.ts +49 -49
- package/src/obfuscator.ts +501 -497
- package/src/options.ts +407 -407
- package/src/order.ts +54 -54
- package/src/presets.ts +125 -125
- package/src/templates/bufferToStringTemplate.ts +57 -57
- package/src/templates/deadCodeTemplates.ts +1185 -1185
- package/src/templates/getGlobalTemplate.ts +76 -76
- package/src/templates/integrityTemplate.ts +64 -64
- package/src/templates/setFunctionLengthTemplate.ts +11 -11
- package/src/templates/stringCompressionTemplate.ts +20 -20
- package/src/templates/tamperProtectionTemplates.ts +120 -120
- package/src/templates/template.ts +224 -224
- package/src/transforms/astScrambler.ts +99 -99
- package/src/transforms/calculator.ts +99 -99
- package/src/transforms/controlFlowFlattening.ts +1716 -1664
- package/src/transforms/deadCode.ts +82 -82
- package/src/transforms/dispatcher.ts +450 -450
- package/src/transforms/extraction/duplicateLiteralsRemoval.ts +156 -158
- package/src/transforms/extraction/objectExtraction.ts +186 -186
- package/src/transforms/finalizer.ts +74 -74
- package/src/transforms/flatten.ts +421 -420
- package/src/transforms/identifier/globalConcealing.ts +315 -295
- package/src/transforms/identifier/movedDeclarations.ts +252 -251
- package/src/transforms/identifier/renameVariables.ts +328 -321
- package/src/transforms/lock/integrity.ts +117 -114
- package/src/transforms/lock/lock.ts +418 -425
- package/src/transforms/minify.ts +615 -629
- package/src/transforms/opaquePredicates.ts +100 -100
- package/src/transforms/pack.ts +239 -231
- package/src/transforms/plugin.ts +173 -173
- package/src/transforms/preparation.ts +349 -347
- package/src/transforms/renameLabels.ts +175 -175
- package/src/transforms/rgf.ts +322 -322
- package/src/transforms/shuffle.ts +82 -82
- package/src/transforms/string/encoding.ts +144 -144
- package/src/transforms/string/stringCompression.ts +128 -128
- package/src/transforms/string/stringConcealing.ts +312 -298
- package/src/transforms/string/stringEncoding.ts +80 -80
- package/src/transforms/string/stringSplitting.ts +77 -77
- package/src/transforms/variableMasking.ts +257 -257
- package/src/utils/IntGen.ts +33 -33
- package/src/utils/NameGen.ts +116 -116
- package/src/utils/PredicateGen.ts +61 -61
- package/src/utils/ast-utils.ts +663 -663
- package/src/utils/function-utils.ts +50 -50
- package/src/utils/gen-utils.ts +48 -48
- package/src/utils/node.ts +78 -78
- package/src/utils/object-utils.ts +21 -21
- package/src/utils/random-utils.ts +93 -93
- package/src/utils/static-utils.ts +66 -66
- package/src/validateOptions.ts +256 -259
- package/tsconfig.json +13 -14
- package/dist/probability.js +0 -1
- package/dist/transforms/functionOutlining.js +0 -230
- package/dist/utils/ControlObject.js +0 -125
package/src/transforms/rgf.ts
CHANGED
|
@@ -1,322 +1,322 @@
|
|
|
1
|
-
import { NodePath } from "@babel/traverse";
|
|
2
|
-
import { PluginArg, PluginObject } from "./plugin";
|
|
3
|
-
import { Order } from "../order";
|
|
4
|
-
import * as t from "@babel/types";
|
|
5
|
-
import Obfuscator from "../obfuscator";
|
|
6
|
-
import {
|
|
7
|
-
append,
|
|
8
|
-
getFunctionName,
|
|
9
|
-
isDefiningIdentifier,
|
|
10
|
-
isStrictMode,
|
|
11
|
-
isVariableIdentifier,
|
|
12
|
-
prepend,
|
|
13
|
-
} from "../utils/ast-utils";
|
|
14
|
-
import {
|
|
15
|
-
MULTI_TRANSFORM,
|
|
16
|
-
NodeSymbol,
|
|
17
|
-
PREDICTABLE,
|
|
18
|
-
reservedIdentifiers,
|
|
19
|
-
SKIP,
|
|
20
|
-
UNSAFE,
|
|
21
|
-
} from "../constants";
|
|
22
|
-
import { computeFunctionLength } from "../utils/function-utils";
|
|
23
|
-
import { numericLiteral } from "../utils/node";
|
|
24
|
-
import Template from "../templates/template";
|
|
25
|
-
import { createEvalIntegrityTemplate } from "../templates/tamperProtectionTemplates";
|
|
26
|
-
|
|
27
|
-
const RGF_ELIGIBLE = Symbol("rgfEligible");
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* RGF (Runtime-Generated-Function) uses the `new Function("code")` syntax to create executable code from strings.
|
|
31
|
-
*
|
|
32
|
-
* Limitations:
|
|
33
|
-
*
|
|
34
|
-
* 1. Does not apply to async or generator functions
|
|
35
|
-
* 2. Does not apply to functions that reference outside variables
|
|
36
|
-
*/
|
|
37
|
-
export default ({ Plugin }: PluginArg): PluginObject => {
|
|
38
|
-
const me = Plugin(Order.RGF, {
|
|
39
|
-
changeData: {
|
|
40
|
-
functions: 0,
|
|
41
|
-
},
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
const rgfArrayName = me.getPlaceholder() + "_rgf";
|
|
45
|
-
const rgfEvalName = me.getPlaceholder() + "_rgf_eval";
|
|
46
|
-
const rgfArrayExpression = t.arrayExpression([]);
|
|
47
|
-
|
|
48
|
-
let active = true;
|
|
49
|
-
|
|
50
|
-
return {
|
|
51
|
-
visitor: {
|
|
52
|
-
Program: {
|
|
53
|
-
enter(path) {
|
|
54
|
-
path.scope.crawl();
|
|
55
|
-
},
|
|
56
|
-
exit(path) {
|
|
57
|
-
active = false;
|
|
58
|
-
if (rgfArrayExpression.elements.length === 0) return;
|
|
59
|
-
|
|
60
|
-
// Insert the RGF array at the top of the program
|
|
61
|
-
prepend(
|
|
62
|
-
path,
|
|
63
|
-
t.variableDeclaration("var", [
|
|
64
|
-
t.variableDeclarator(
|
|
65
|
-
t.identifier(rgfArrayName),
|
|
66
|
-
rgfArrayExpression
|
|
67
|
-
),
|
|
68
|
-
])
|
|
69
|
-
);
|
|
70
|
-
|
|
71
|
-
var rgfEvalIntegrity = me.getPlaceholder() + "_rgf_eval_integrity";
|
|
72
|
-
|
|
73
|
-
prepend(
|
|
74
|
-
path,
|
|
75
|
-
new Template(`
|
|
76
|
-
{EvalIntegrity}
|
|
77
|
-
var ${rgfEvalIntegrity} = {EvalIntegrityName}();
|
|
78
|
-
`).compile({
|
|
79
|
-
EvalIntegrity: createEvalIntegrityTemplate(me, path),
|
|
80
|
-
EvalIntegrityName: me.getPlaceholder(),
|
|
81
|
-
})
|
|
82
|
-
);
|
|
83
|
-
|
|
84
|
-
append(
|
|
85
|
-
path,
|
|
86
|
-
new Template(
|
|
87
|
-
`
|
|
88
|
-
function ${rgfEvalName}(code) {
|
|
89
|
-
if (${rgfEvalIntegrity}) {
|
|
90
|
-
return eval(code);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
`
|
|
94
|
-
)
|
|
95
|
-
.addSymbols(UNSAFE)
|
|
96
|
-
.single()
|
|
97
|
-
);
|
|
98
|
-
},
|
|
99
|
-
},
|
|
100
|
-
"FunctionDeclaration|FunctionExpression": {
|
|
101
|
-
enter(_path) {
|
|
102
|
-
if (!active) return;
|
|
103
|
-
|
|
104
|
-
// On enter, determine if Function is eligible for RGF transformation
|
|
105
|
-
|
|
106
|
-
const path = _path as NodePath<
|
|
107
|
-
t.FunctionDeclaration | t.FunctionExpression
|
|
108
|
-
>;
|
|
109
|
-
|
|
110
|
-
if (me.isSkipped(path)) return;
|
|
111
|
-
|
|
112
|
-
// Skip nested functions if the parent function is already deemed eligible
|
|
113
|
-
if (path.find((p) => p.node[RGF_ELIGIBLE] || p.node[MULTI_TRANSFORM]))
|
|
114
|
-
return;
|
|
115
|
-
|
|
116
|
-
// Skip async and generator functions
|
|
117
|
-
if (path.node.async || path.node.generator) return;
|
|
118
|
-
|
|
119
|
-
const name = getFunctionName(path);
|
|
120
|
-
if (name === me.options.lock?.countermeasures) return;
|
|
121
|
-
if (me.obfuscator.isInternalVariable(name)) return;
|
|
122
|
-
|
|
123
|
-
if (
|
|
124
|
-
!me.computeProbabilityMap(
|
|
125
|
-
me.options.rgf,
|
|
126
|
-
name,
|
|
127
|
-
path.getFunctionParent() === null
|
|
128
|
-
)
|
|
129
|
-
)
|
|
130
|
-
return;
|
|
131
|
-
|
|
132
|
-
// Skip functions with references to outside variables
|
|
133
|
-
// Check the scope to see if this function relies on any variables defined outside the function
|
|
134
|
-
var identifierPreventingTransform: string;
|
|
135
|
-
|
|
136
|
-
path.traverse({
|
|
137
|
-
Identifier(idPath) {
|
|
138
|
-
if (!isVariableIdentifier(idPath)) return;
|
|
139
|
-
if (idPath.isBindingIdentifier() && isDefiningIdentifier(idPath))
|
|
140
|
-
return;
|
|
141
|
-
|
|
142
|
-
const { name } = idPath.node;
|
|
143
|
-
// RGF array name is allowed, it is not considered an outside reference
|
|
144
|
-
if (name === rgfArrayName) return;
|
|
145
|
-
if (reservedIdentifiers.has(name)) return;
|
|
146
|
-
if (me.options.globalVariables.has(name)) return;
|
|
147
|
-
|
|
148
|
-
const binding = idPath.scope.getBinding(name);
|
|
149
|
-
if (!binding) {
|
|
150
|
-
// Global variables are allowed
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
var isOutsideVariable =
|
|
155
|
-
path.scope.parent.getBinding(name) === binding;
|
|
156
|
-
// If the binding is not in the current scope, it is an outside reference
|
|
157
|
-
if (isOutsideVariable) {
|
|
158
|
-
identifierPreventingTransform = name;
|
|
159
|
-
idPath.stop();
|
|
160
|
-
}
|
|
161
|
-
},
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
if (identifierPreventingTransform) {
|
|
165
|
-
me.log(
|
|
166
|
-
"Skipping function " +
|
|
167
|
-
name +
|
|
168
|
-
" due to reference to outside variable: " +
|
|
169
|
-
identifierPreventingTransform
|
|
170
|
-
);
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
me.log("Function " + name + " is eligible for RGF transformation");
|
|
175
|
-
path.node[RGF_ELIGIBLE] = true;
|
|
176
|
-
},
|
|
177
|
-
exit(_path) {
|
|
178
|
-
if (!active) return;
|
|
179
|
-
|
|
180
|
-
const path = _path as NodePath<
|
|
181
|
-
t.FunctionDeclaration | t.FunctionExpression
|
|
182
|
-
>;
|
|
183
|
-
|
|
184
|
-
if (me.isSkipped(path)) return;
|
|
185
|
-
|
|
186
|
-
// Function is not eligible for RGF transformation
|
|
187
|
-
if (!path.node[RGF_ELIGIBLE]) return;
|
|
188
|
-
|
|
189
|
-
const embeddedName = me.getPlaceholder() + "_embedded";
|
|
190
|
-
const replacementName = me.getPlaceholder() + "_replacement";
|
|
191
|
-
const argumentsName = me.getPlaceholder() + "_args";
|
|
192
|
-
|
|
193
|
-
const lastNode = t.expressionStatement(t.identifier(embeddedName));
|
|
194
|
-
(lastNode as NodeSymbol)[SKIP] = true;
|
|
195
|
-
|
|
196
|
-
// Transform the function
|
|
197
|
-
const evalProgram: t.Program = t.program([
|
|
198
|
-
t.functionDeclaration(
|
|
199
|
-
t.identifier(embeddedName),
|
|
200
|
-
[],
|
|
201
|
-
t.blockStatement([
|
|
202
|
-
t.variableDeclaration("var", [
|
|
203
|
-
t.variableDeclarator(
|
|
204
|
-
t.arrayPattern([
|
|
205
|
-
t.identifier(rgfArrayName),
|
|
206
|
-
t.identifier(argumentsName),
|
|
207
|
-
]),
|
|
208
|
-
t.identifier("arguments")
|
|
209
|
-
),
|
|
210
|
-
]),
|
|
211
|
-
t.functionDeclaration(
|
|
212
|
-
t.identifier(replacementName),
|
|
213
|
-
path.node.params as (t.Identifier | t.Pattern)[],
|
|
214
|
-
path.node.body
|
|
215
|
-
),
|
|
216
|
-
t.returnStatement(
|
|
217
|
-
t.callExpression(
|
|
218
|
-
t.memberExpression(
|
|
219
|
-
t.identifier(replacementName),
|
|
220
|
-
t.identifier("apply")
|
|
221
|
-
),
|
|
222
|
-
[t.thisExpression(), t.identifier(argumentsName)]
|
|
223
|
-
)
|
|
224
|
-
),
|
|
225
|
-
])
|
|
226
|
-
),
|
|
227
|
-
lastNode,
|
|
228
|
-
]);
|
|
229
|
-
|
|
230
|
-
const strictModeEnforcingBlock = path.find((p) => isStrictMode(p));
|
|
231
|
-
if (strictModeEnforcingBlock) {
|
|
232
|
-
// Preserve 'use strict' directive
|
|
233
|
-
// This is necessary to enure subsequent transforms (Control Flow Flattening) are aware of the strict mode directive
|
|
234
|
-
evalProgram.directives.push(
|
|
235
|
-
t.directive(t.directiveLiteral("use strict"))
|
|
236
|
-
);
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
const evalFile = t.file(evalProgram);
|
|
240
|
-
|
|
241
|
-
var newObfuscator = new Obfuscator(me.options, me.obfuscator);
|
|
242
|
-
|
|
243
|
-
var hasRan = new Set(
|
|
244
|
-
me.obfuscator.plugins
|
|
245
|
-
.filter((plugin, i) => {
|
|
246
|
-
return i <= me.obfuscator.index;
|
|
247
|
-
})
|
|
248
|
-
.map((plugin) => plugin.pluginInstance.order)
|
|
249
|
-
);
|
|
250
|
-
|
|
251
|
-
// Global Concealing will likely cause issues when Pack is also enabled
|
|
252
|
-
const disallowedTransforms = new Set([Order.GlobalConcealing]);
|
|
253
|
-
|
|
254
|
-
newObfuscator.plugins = newObfuscator.plugins.filter(
|
|
255
|
-
({ pluginInstance }) => {
|
|
256
|
-
return (
|
|
257
|
-
(pluginInstance.order == Order.Preparation ||
|
|
258
|
-
!hasRan.has(pluginInstance.order)) &&
|
|
259
|
-
!disallowedTransforms.has(pluginInstance.order)
|
|
260
|
-
);
|
|
261
|
-
}
|
|
262
|
-
);
|
|
263
|
-
|
|
264
|
-
newObfuscator.obfuscateAST(evalFile);
|
|
265
|
-
|
|
266
|
-
const generated = Obfuscator.generateCode(evalFile);
|
|
267
|
-
|
|
268
|
-
var functionExpression = t.callExpression(t.identifier(rgfEvalName), [
|
|
269
|
-
t.stringLiteral(generated),
|
|
270
|
-
]);
|
|
271
|
-
|
|
272
|
-
var index = rgfArrayExpression.elements.length;
|
|
273
|
-
rgfArrayExpression.elements.push(functionExpression);
|
|
274
|
-
|
|
275
|
-
// Params no longer needed, using 'arguments' instead
|
|
276
|
-
const originalLength = computeFunctionLength(path);
|
|
277
|
-
path.node.params = [];
|
|
278
|
-
|
|
279
|
-
// Function is now unsafe
|
|
280
|
-
(path.node as NodeSymbol)[UNSAFE] = true;
|
|
281
|
-
// Params changed and using 'arguments'
|
|
282
|
-
(path.node as NodeSymbol)[PREDICTABLE] = false;
|
|
283
|
-
me.skip(path);
|
|
284
|
-
|
|
285
|
-
// Update body to point to new function
|
|
286
|
-
path
|
|
287
|
-
.get("body")
|
|
288
|
-
.replaceWith(
|
|
289
|
-
t.blockStatement([
|
|
290
|
-
t.returnStatement(
|
|
291
|
-
t.callExpression(
|
|
292
|
-
t.memberExpression(
|
|
293
|
-
t.memberExpression(
|
|
294
|
-
t.identifier(rgfArrayName),
|
|
295
|
-
numericLiteral(index),
|
|
296
|
-
true
|
|
297
|
-
),
|
|
298
|
-
t.stringLiteral("apply"),
|
|
299
|
-
true
|
|
300
|
-
),
|
|
301
|
-
[
|
|
302
|
-
t.thisExpression(),
|
|
303
|
-
t.arrayExpression([
|
|
304
|
-
t.identifier(rgfArrayName),
|
|
305
|
-
t.identifier("arguments"),
|
|
306
|
-
]),
|
|
307
|
-
]
|
|
308
|
-
)
|
|
309
|
-
),
|
|
310
|
-
])
|
|
311
|
-
);
|
|
312
|
-
|
|
313
|
-
path.skip();
|
|
314
|
-
|
|
315
|
-
me.setFunctionLength(path, originalLength);
|
|
316
|
-
|
|
317
|
-
me.changeData.functions++;
|
|
318
|
-
},
|
|
319
|
-
},
|
|
320
|
-
},
|
|
321
|
-
};
|
|
322
|
-
};
|
|
1
|
+
import { NodePath } from "@babel/traverse";
|
|
2
|
+
import { PluginArg, PluginObject } from "./plugin";
|
|
3
|
+
import { Order } from "../order";
|
|
4
|
+
import * as t from "@babel/types";
|
|
5
|
+
import Obfuscator from "../obfuscator";
|
|
6
|
+
import {
|
|
7
|
+
append,
|
|
8
|
+
getFunctionName,
|
|
9
|
+
isDefiningIdentifier,
|
|
10
|
+
isStrictMode,
|
|
11
|
+
isVariableIdentifier,
|
|
12
|
+
prepend,
|
|
13
|
+
} from "../utils/ast-utils";
|
|
14
|
+
import {
|
|
15
|
+
MULTI_TRANSFORM,
|
|
16
|
+
NodeSymbol,
|
|
17
|
+
PREDICTABLE,
|
|
18
|
+
reservedIdentifiers,
|
|
19
|
+
SKIP,
|
|
20
|
+
UNSAFE,
|
|
21
|
+
} from "../constants";
|
|
22
|
+
import { computeFunctionLength } from "../utils/function-utils";
|
|
23
|
+
import { numericLiteral } from "../utils/node";
|
|
24
|
+
import Template from "../templates/template";
|
|
25
|
+
import { createEvalIntegrityTemplate } from "../templates/tamperProtectionTemplates";
|
|
26
|
+
|
|
27
|
+
const RGF_ELIGIBLE = Symbol("rgfEligible");
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* RGF (Runtime-Generated-Function) uses the `new Function("code")` syntax to create executable code from strings.
|
|
31
|
+
*
|
|
32
|
+
* Limitations:
|
|
33
|
+
*
|
|
34
|
+
* 1. Does not apply to async or generator functions
|
|
35
|
+
* 2. Does not apply to functions that reference outside variables
|
|
36
|
+
*/
|
|
37
|
+
export default ({ Plugin }: PluginArg): PluginObject => {
|
|
38
|
+
const me = Plugin(Order.RGF, {
|
|
39
|
+
changeData: {
|
|
40
|
+
functions: 0,
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const rgfArrayName = me.getPlaceholder() + "_rgf";
|
|
45
|
+
const rgfEvalName = me.getPlaceholder() + "_rgf_eval";
|
|
46
|
+
const rgfArrayExpression = t.arrayExpression([]);
|
|
47
|
+
|
|
48
|
+
let active = true;
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
visitor: {
|
|
52
|
+
Program: {
|
|
53
|
+
enter(path) {
|
|
54
|
+
path.scope.crawl();
|
|
55
|
+
},
|
|
56
|
+
exit(path) {
|
|
57
|
+
active = false;
|
|
58
|
+
if (rgfArrayExpression.elements.length === 0) return;
|
|
59
|
+
|
|
60
|
+
// Insert the RGF array at the top of the program
|
|
61
|
+
prepend(
|
|
62
|
+
path,
|
|
63
|
+
t.variableDeclaration("var", [
|
|
64
|
+
t.variableDeclarator(
|
|
65
|
+
t.identifier(rgfArrayName),
|
|
66
|
+
rgfArrayExpression
|
|
67
|
+
),
|
|
68
|
+
])
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
var rgfEvalIntegrity = me.getPlaceholder() + "_rgf_eval_integrity";
|
|
72
|
+
|
|
73
|
+
prepend(
|
|
74
|
+
path,
|
|
75
|
+
new Template(`
|
|
76
|
+
{EvalIntegrity}
|
|
77
|
+
var ${rgfEvalIntegrity} = {EvalIntegrityName}();
|
|
78
|
+
`).compile({
|
|
79
|
+
EvalIntegrity: createEvalIntegrityTemplate(me, path),
|
|
80
|
+
EvalIntegrityName: me.getPlaceholder(),
|
|
81
|
+
})
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
append(
|
|
85
|
+
path,
|
|
86
|
+
new Template(
|
|
87
|
+
`
|
|
88
|
+
function ${rgfEvalName}(code) {
|
|
89
|
+
if (${rgfEvalIntegrity}) {
|
|
90
|
+
return eval(code);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
`
|
|
94
|
+
)
|
|
95
|
+
.addSymbols(UNSAFE)
|
|
96
|
+
.single()
|
|
97
|
+
);
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
"FunctionDeclaration|FunctionExpression": {
|
|
101
|
+
enter(_path) {
|
|
102
|
+
if (!active) return;
|
|
103
|
+
|
|
104
|
+
// On enter, determine if Function is eligible for RGF transformation
|
|
105
|
+
|
|
106
|
+
const path = _path as NodePath<
|
|
107
|
+
t.FunctionDeclaration | t.FunctionExpression
|
|
108
|
+
>;
|
|
109
|
+
|
|
110
|
+
if (me.isSkipped(path)) return;
|
|
111
|
+
|
|
112
|
+
// Skip nested functions if the parent function is already deemed eligible
|
|
113
|
+
if (path.find((p) => p.node[RGF_ELIGIBLE] || p.node[MULTI_TRANSFORM]))
|
|
114
|
+
return;
|
|
115
|
+
|
|
116
|
+
// Skip async and generator functions
|
|
117
|
+
if (path.node.async || path.node.generator) return;
|
|
118
|
+
|
|
119
|
+
const name = getFunctionName(path);
|
|
120
|
+
if (name === me.options.lock?.countermeasures) return;
|
|
121
|
+
if (me.obfuscator.isInternalVariable(name)) return;
|
|
122
|
+
|
|
123
|
+
if (
|
|
124
|
+
!me.computeProbabilityMap(
|
|
125
|
+
me.options.rgf,
|
|
126
|
+
name,
|
|
127
|
+
path.getFunctionParent() === null
|
|
128
|
+
)
|
|
129
|
+
)
|
|
130
|
+
return;
|
|
131
|
+
|
|
132
|
+
// Skip functions with references to outside variables
|
|
133
|
+
// Check the scope to see if this function relies on any variables defined outside the function
|
|
134
|
+
var identifierPreventingTransform: string;
|
|
135
|
+
|
|
136
|
+
path.traverse({
|
|
137
|
+
Identifier(idPath) {
|
|
138
|
+
if (!isVariableIdentifier(idPath)) return;
|
|
139
|
+
if (idPath.isBindingIdentifier() && isDefiningIdentifier(idPath))
|
|
140
|
+
return;
|
|
141
|
+
|
|
142
|
+
const { name } = idPath.node;
|
|
143
|
+
// RGF array name is allowed, it is not considered an outside reference
|
|
144
|
+
if (name === rgfArrayName) return;
|
|
145
|
+
if (reservedIdentifiers.has(name)) return;
|
|
146
|
+
if (me.options.globalVariables.has(name)) return;
|
|
147
|
+
|
|
148
|
+
const binding = idPath.scope.getBinding(name);
|
|
149
|
+
if (!binding) {
|
|
150
|
+
// Global variables are allowed
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
var isOutsideVariable =
|
|
155
|
+
path.scope.parent.getBinding(name) === binding;
|
|
156
|
+
// If the binding is not in the current scope, it is an outside reference
|
|
157
|
+
if (isOutsideVariable) {
|
|
158
|
+
identifierPreventingTransform = name;
|
|
159
|
+
idPath.stop();
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
if (identifierPreventingTransform) {
|
|
165
|
+
me.log(
|
|
166
|
+
"Skipping function " +
|
|
167
|
+
name +
|
|
168
|
+
" due to reference to outside variable: " +
|
|
169
|
+
identifierPreventingTransform
|
|
170
|
+
);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
me.log("Function " + name + " is eligible for RGF transformation");
|
|
175
|
+
path.node[RGF_ELIGIBLE] = true;
|
|
176
|
+
},
|
|
177
|
+
exit(_path) {
|
|
178
|
+
if (!active) return;
|
|
179
|
+
|
|
180
|
+
const path = _path as NodePath<
|
|
181
|
+
t.FunctionDeclaration | t.FunctionExpression
|
|
182
|
+
>;
|
|
183
|
+
|
|
184
|
+
if (me.isSkipped(path)) return;
|
|
185
|
+
|
|
186
|
+
// Function is not eligible for RGF transformation
|
|
187
|
+
if (!path.node[RGF_ELIGIBLE]) return;
|
|
188
|
+
|
|
189
|
+
const embeddedName = me.getPlaceholder() + "_embedded";
|
|
190
|
+
const replacementName = me.getPlaceholder() + "_replacement";
|
|
191
|
+
const argumentsName = me.getPlaceholder() + "_args";
|
|
192
|
+
|
|
193
|
+
const lastNode = t.expressionStatement(t.identifier(embeddedName));
|
|
194
|
+
(lastNode as NodeSymbol)[SKIP] = true;
|
|
195
|
+
|
|
196
|
+
// Transform the function
|
|
197
|
+
const evalProgram: t.Program = t.program([
|
|
198
|
+
t.functionDeclaration(
|
|
199
|
+
t.identifier(embeddedName),
|
|
200
|
+
[],
|
|
201
|
+
t.blockStatement([
|
|
202
|
+
t.variableDeclaration("var", [
|
|
203
|
+
t.variableDeclarator(
|
|
204
|
+
t.arrayPattern([
|
|
205
|
+
t.identifier(rgfArrayName),
|
|
206
|
+
t.identifier(argumentsName),
|
|
207
|
+
]),
|
|
208
|
+
t.identifier("arguments")
|
|
209
|
+
),
|
|
210
|
+
]),
|
|
211
|
+
t.functionDeclaration(
|
|
212
|
+
t.identifier(replacementName),
|
|
213
|
+
path.node.params as (t.Identifier | t.Pattern)[],
|
|
214
|
+
path.node.body
|
|
215
|
+
),
|
|
216
|
+
t.returnStatement(
|
|
217
|
+
t.callExpression(
|
|
218
|
+
t.memberExpression(
|
|
219
|
+
t.identifier(replacementName),
|
|
220
|
+
t.identifier("apply")
|
|
221
|
+
),
|
|
222
|
+
[t.thisExpression(), t.identifier(argumentsName)]
|
|
223
|
+
)
|
|
224
|
+
),
|
|
225
|
+
])
|
|
226
|
+
),
|
|
227
|
+
lastNode,
|
|
228
|
+
]);
|
|
229
|
+
|
|
230
|
+
const strictModeEnforcingBlock = path.find((p) => isStrictMode(p));
|
|
231
|
+
if (strictModeEnforcingBlock) {
|
|
232
|
+
// Preserve 'use strict' directive
|
|
233
|
+
// This is necessary to enure subsequent transforms (Control Flow Flattening) are aware of the strict mode directive
|
|
234
|
+
evalProgram.directives.push(
|
|
235
|
+
t.directive(t.directiveLiteral("use strict"))
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const evalFile = t.file(evalProgram);
|
|
240
|
+
|
|
241
|
+
var newObfuscator = new Obfuscator(me.options, me.obfuscator);
|
|
242
|
+
|
|
243
|
+
var hasRan = new Set(
|
|
244
|
+
me.obfuscator.plugins
|
|
245
|
+
.filter((plugin, i) => {
|
|
246
|
+
return i <= me.obfuscator.index;
|
|
247
|
+
})
|
|
248
|
+
.map((plugin) => plugin.pluginInstance.order)
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
// Global Concealing will likely cause issues when Pack is also enabled
|
|
252
|
+
const disallowedTransforms = new Set([Order.GlobalConcealing]);
|
|
253
|
+
|
|
254
|
+
newObfuscator.plugins = newObfuscator.plugins.filter(
|
|
255
|
+
({ pluginInstance }) => {
|
|
256
|
+
return (
|
|
257
|
+
(pluginInstance.order == Order.Preparation ||
|
|
258
|
+
!hasRan.has(pluginInstance.order)) &&
|
|
259
|
+
!disallowedTransforms.has(pluginInstance.order)
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
);
|
|
263
|
+
|
|
264
|
+
newObfuscator.obfuscateAST(evalFile);
|
|
265
|
+
|
|
266
|
+
const generated = Obfuscator.generateCode(evalFile);
|
|
267
|
+
|
|
268
|
+
var functionExpression = t.callExpression(t.identifier(rgfEvalName), [
|
|
269
|
+
t.stringLiteral(generated),
|
|
270
|
+
]);
|
|
271
|
+
|
|
272
|
+
var index = rgfArrayExpression.elements.length;
|
|
273
|
+
rgfArrayExpression.elements.push(functionExpression);
|
|
274
|
+
|
|
275
|
+
// Params no longer needed, using 'arguments' instead
|
|
276
|
+
const originalLength = computeFunctionLength(path);
|
|
277
|
+
path.node.params = [];
|
|
278
|
+
|
|
279
|
+
// Function is now unsafe
|
|
280
|
+
(path.node as NodeSymbol)[UNSAFE] = true;
|
|
281
|
+
// Params changed and using 'arguments'
|
|
282
|
+
(path.node as NodeSymbol)[PREDICTABLE] = false;
|
|
283
|
+
me.skip(path);
|
|
284
|
+
|
|
285
|
+
// Update body to point to new function
|
|
286
|
+
path
|
|
287
|
+
.get("body")
|
|
288
|
+
.replaceWith(
|
|
289
|
+
t.blockStatement([
|
|
290
|
+
t.returnStatement(
|
|
291
|
+
t.callExpression(
|
|
292
|
+
t.memberExpression(
|
|
293
|
+
t.memberExpression(
|
|
294
|
+
t.identifier(rgfArrayName),
|
|
295
|
+
numericLiteral(index),
|
|
296
|
+
true
|
|
297
|
+
),
|
|
298
|
+
t.stringLiteral("apply"),
|
|
299
|
+
true
|
|
300
|
+
),
|
|
301
|
+
[
|
|
302
|
+
t.thisExpression(),
|
|
303
|
+
t.arrayExpression([
|
|
304
|
+
t.identifier(rgfArrayName),
|
|
305
|
+
t.identifier("arguments"),
|
|
306
|
+
]),
|
|
307
|
+
]
|
|
308
|
+
)
|
|
309
|
+
),
|
|
310
|
+
])
|
|
311
|
+
);
|
|
312
|
+
|
|
313
|
+
path.skip();
|
|
314
|
+
|
|
315
|
+
me.setFunctionLength(path, originalLength);
|
|
316
|
+
|
|
317
|
+
me.changeData.functions++;
|
|
318
|
+
},
|
|
319
|
+
},
|
|
320
|
+
},
|
|
321
|
+
};
|
|
322
|
+
};
|