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
|
@@ -1,257 +1,257 @@
|
|
|
1
|
-
import { Binding, NodePath } from "@babel/traverse";
|
|
2
|
-
import { PluginArg, PluginObject } from "./plugin";
|
|
3
|
-
import * as t from "@babel/types";
|
|
4
|
-
import Template from "../templates/template";
|
|
5
|
-
import { Order } from "../order";
|
|
6
|
-
import {
|
|
7
|
-
NodeSymbol,
|
|
8
|
-
PREDICTABLE,
|
|
9
|
-
reservedIdentifiers,
|
|
10
|
-
UNSAFE,
|
|
11
|
-
variableFunctionName,
|
|
12
|
-
} from "../constants";
|
|
13
|
-
import {
|
|
14
|
-
ensureComputedExpression,
|
|
15
|
-
getFunctionName,
|
|
16
|
-
isDefiningIdentifier,
|
|
17
|
-
isStrictMode,
|
|
18
|
-
isVariableIdentifier,
|
|
19
|
-
prepend,
|
|
20
|
-
replaceDefiningIdentifierToMemberExpression,
|
|
21
|
-
} from "../utils/ast-utils";
|
|
22
|
-
import {
|
|
23
|
-
computeFunctionLength,
|
|
24
|
-
isVariableFunctionIdentifier,
|
|
25
|
-
} from "../utils/function-utils";
|
|
26
|
-
import { ok } from "assert";
|
|
27
|
-
import { NameGen } from "../utils/NameGen";
|
|
28
|
-
import { choice, getRandomInteger } from "../utils/random-utils";
|
|
29
|
-
import { createLiteral } from "../utils/node";
|
|
30
|
-
|
|
31
|
-
export default ({ Plugin }: PluginArg): PluginObject => {
|
|
32
|
-
const me = Plugin(Order.VariableMasking, {
|
|
33
|
-
changeData: {
|
|
34
|
-
functions: 0,
|
|
35
|
-
},
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
const transformFunction = (fnPath: NodePath<t.Function>) => {
|
|
39
|
-
// Do not apply to getter/setter methods
|
|
40
|
-
if (fnPath.isObjectMethod() && fnPath.node.kind !== "method") {
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Do not apply to class getters/setters
|
|
45
|
-
if (fnPath.isClassMethod() && fnPath.node.kind !== "method") {
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Do not apply to async or generator functions
|
|
50
|
-
if (fnPath.node.generator || fnPath.node.async) {
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Do not apply to functions with rest parameters or destructuring
|
|
55
|
-
if (fnPath.node.params.some((param) => !t.isIdentifier(param))) {
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Do not apply to 'use strict' functions
|
|
60
|
-
if (isStrictMode(fnPath)) return;
|
|
61
|
-
|
|
62
|
-
// Do not apply to functions marked unsafe
|
|
63
|
-
if ((fnPath.node as NodeSymbol)[UNSAFE]) return;
|
|
64
|
-
|
|
65
|
-
const functionName = getFunctionName(fnPath);
|
|
66
|
-
|
|
67
|
-
if (!me.computeProbabilityMap(me.options.variableMasking, functionName)) {
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const stackName = me.getPlaceholder() + "_varMask";
|
|
72
|
-
const stackMap = new Map<Binding, number | string>();
|
|
73
|
-
const propertyGen = new NameGen("mangled");
|
|
74
|
-
const stackKeys = new Set<string>();
|
|
75
|
-
let needsStack = false;
|
|
76
|
-
|
|
77
|
-
const illegalBindings = new Set<Binding>();
|
|
78
|
-
|
|
79
|
-
function checkBinding(binding: Binding) {
|
|
80
|
-
// Custom illegal check
|
|
81
|
-
// Variable Declarations with more than one declarator are not supported
|
|
82
|
-
// They can be inserted from the user's code even though Preparation phase should prevent it
|
|
83
|
-
// String Compression library includes such code
|
|
84
|
-
// TODO: Support multiple declarators
|
|
85
|
-
var variableDeclaration = binding.path.find((p) =>
|
|
86
|
-
p.isVariableDeclaration()
|
|
87
|
-
) as NodePath<t.VariableDeclaration>;
|
|
88
|
-
if (
|
|
89
|
-
variableDeclaration &&
|
|
90
|
-
variableDeclaration.node.declarations.length > 1
|
|
91
|
-
) {
|
|
92
|
-
return false;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function checkForUnsafe(valuePath: NodePath) {
|
|
96
|
-
var hasUnsafeNode = false;
|
|
97
|
-
|
|
98
|
-
valuePath.traverse({
|
|
99
|
-
ThisExpression(path) {
|
|
100
|
-
hasUnsafeNode = true;
|
|
101
|
-
path.stop();
|
|
102
|
-
},
|
|
103
|
-
Function(path) {
|
|
104
|
-
if ((path.node as NodeSymbol)[UNSAFE]) {
|
|
105
|
-
hasUnsafeNode = true;
|
|
106
|
-
path.stop();
|
|
107
|
-
}
|
|
108
|
-
},
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
return hasUnsafeNode;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Check function value for 'this'
|
|
115
|
-
// Adding function expression to the stack (member expression)
|
|
116
|
-
// would break the 'this' context
|
|
117
|
-
if (binding.path.isVariableDeclarator()) {
|
|
118
|
-
let init = binding.path.get("init");
|
|
119
|
-
if (init.node) {
|
|
120
|
-
if (checkForUnsafe(init)) return false;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// x = function(){ return this }
|
|
125
|
-
// Cannot be transformed to x = stack[0] as 'this' would change
|
|
126
|
-
for (var assignment of binding.constantViolations) {
|
|
127
|
-
if (checkForUnsafe(assignment)) return false;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// __JS_CONFUSER_VAR__(identifier) -> __JS_CONFUSER_VAR__(stack.identifier)
|
|
131
|
-
// This cannot be transformed as it would break the user's code
|
|
132
|
-
for (var referencePath of binding.referencePaths) {
|
|
133
|
-
if (isVariableFunctionIdentifier(referencePath)) {
|
|
134
|
-
return false;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
return true;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
for (const param of fnPath.get("params")) {
|
|
142
|
-
ok(param.isIdentifier());
|
|
143
|
-
|
|
144
|
-
const paramName = param.node.name;
|
|
145
|
-
const binding = param.scope.getBinding(paramName);
|
|
146
|
-
|
|
147
|
-
if (!binding || !checkBinding(binding)) return;
|
|
148
|
-
|
|
149
|
-
ok(!stackMap.has(binding));
|
|
150
|
-
stackKeys.add(stackMap.size.toString());
|
|
151
|
-
stackMap.set(binding, stackMap.size);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
fnPath.traverse({
|
|
155
|
-
Identifier(path) {
|
|
156
|
-
if (!isVariableIdentifier(path)) return;
|
|
157
|
-
if (fnPath.get("id") === path) return; // Skip this function's name (Test #21)
|
|
158
|
-
|
|
159
|
-
if (reservedIdentifiers.has(path.node.name)) return;
|
|
160
|
-
if (me.options.globalVariables.has(path.node.name)) return;
|
|
161
|
-
if (path.node.name === stackName) return;
|
|
162
|
-
if (path.node.name === variableFunctionName) return;
|
|
163
|
-
|
|
164
|
-
const binding = path.scope.getBinding(path.node.name);
|
|
165
|
-
if (!binding || binding.scope !== fnPath.scope) return;
|
|
166
|
-
if (illegalBindings.has(binding)) return;
|
|
167
|
-
|
|
168
|
-
needsStack = true;
|
|
169
|
-
|
|
170
|
-
let index = stackMap.get(binding);
|
|
171
|
-
if (typeof index === "undefined") {
|
|
172
|
-
// Only transform var and let bindings
|
|
173
|
-
// Function declarations could be hoisted and changing them to declarations is breaking
|
|
174
|
-
if (!["var", "let"].includes(binding.kind)) {
|
|
175
|
-
illegalBindings.add(binding);
|
|
176
|
-
return;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
if (!checkBinding(binding)) {
|
|
180
|
-
illegalBindings.add(binding);
|
|
181
|
-
return;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
do {
|
|
185
|
-
index = choice([
|
|
186
|
-
stackMap.size,
|
|
187
|
-
propertyGen.generate(),
|
|
188
|
-
getRandomInteger(-250, 250),
|
|
189
|
-
]);
|
|
190
|
-
} while (!index || stackKeys.has(index.toString()));
|
|
191
|
-
|
|
192
|
-
stackMap.set(binding, index);
|
|
193
|
-
stackKeys.add(index.toString());
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
const memberExpression = t.memberExpression(
|
|
197
|
-
t.identifier(stackName),
|
|
198
|
-
createLiteral(index),
|
|
199
|
-
true
|
|
200
|
-
);
|
|
201
|
-
|
|
202
|
-
if (isDefiningIdentifier(path)) {
|
|
203
|
-
replaceDefiningIdentifierToMemberExpression(path, memberExpression);
|
|
204
|
-
|
|
205
|
-
return;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
ensureComputedExpression(path);
|
|
209
|
-
path.replaceWith(memberExpression);
|
|
210
|
-
},
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
if (!needsStack) return;
|
|
214
|
-
|
|
215
|
-
const originalParamCount = fnPath.node.params.length;
|
|
216
|
-
const originalLength = computeFunctionLength(fnPath);
|
|
217
|
-
|
|
218
|
-
fnPath.node.params = [t.restElement(t.identifier(stackName))];
|
|
219
|
-
|
|
220
|
-
// Discard extraneous parameters
|
|
221
|
-
// Predictable functions are guaranteed to not have extraneous parameters
|
|
222
|
-
if (!(fnPath.node as NodeSymbol)[PREDICTABLE]) {
|
|
223
|
-
prepend(
|
|
224
|
-
fnPath,
|
|
225
|
-
new Template(`${stackName}["length"] = {originalParamCount};`).single({
|
|
226
|
-
originalParamCount: t.numericLiteral(originalParamCount),
|
|
227
|
-
})
|
|
228
|
-
);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// Function is no longer predictable
|
|
232
|
-
(fnPath.node as NodeSymbol)[PREDICTABLE] = false;
|
|
233
|
-
|
|
234
|
-
fnPath.scope.registerBinding("param", fnPath.get("params")[0], fnPath);
|
|
235
|
-
|
|
236
|
-
me.setFunctionLength(fnPath, originalLength);
|
|
237
|
-
|
|
238
|
-
me.changeData.functions++;
|
|
239
|
-
};
|
|
240
|
-
|
|
241
|
-
return {
|
|
242
|
-
visitor: {
|
|
243
|
-
Function: {
|
|
244
|
-
exit(path: NodePath<t.Function>) {
|
|
245
|
-
if (!path.get("body").isBlockStatement()) return;
|
|
246
|
-
|
|
247
|
-
transformFunction(path);
|
|
248
|
-
},
|
|
249
|
-
},
|
|
250
|
-
Program: {
|
|
251
|
-
enter(path) {
|
|
252
|
-
path.scope.crawl();
|
|
253
|
-
},
|
|
254
|
-
},
|
|
255
|
-
},
|
|
256
|
-
};
|
|
257
|
-
};
|
|
1
|
+
import { Binding, NodePath } from "@babel/traverse";
|
|
2
|
+
import { PluginArg, PluginObject } from "./plugin";
|
|
3
|
+
import * as t from "@babel/types";
|
|
4
|
+
import Template from "../templates/template";
|
|
5
|
+
import { Order } from "../order";
|
|
6
|
+
import {
|
|
7
|
+
NodeSymbol,
|
|
8
|
+
PREDICTABLE,
|
|
9
|
+
reservedIdentifiers,
|
|
10
|
+
UNSAFE,
|
|
11
|
+
variableFunctionName,
|
|
12
|
+
} from "../constants";
|
|
13
|
+
import {
|
|
14
|
+
ensureComputedExpression,
|
|
15
|
+
getFunctionName,
|
|
16
|
+
isDefiningIdentifier,
|
|
17
|
+
isStrictMode,
|
|
18
|
+
isVariableIdentifier,
|
|
19
|
+
prepend,
|
|
20
|
+
replaceDefiningIdentifierToMemberExpression,
|
|
21
|
+
} from "../utils/ast-utils";
|
|
22
|
+
import {
|
|
23
|
+
computeFunctionLength,
|
|
24
|
+
isVariableFunctionIdentifier,
|
|
25
|
+
} from "../utils/function-utils";
|
|
26
|
+
import { ok } from "assert";
|
|
27
|
+
import { NameGen } from "../utils/NameGen";
|
|
28
|
+
import { choice, getRandomInteger } from "../utils/random-utils";
|
|
29
|
+
import { createLiteral } from "../utils/node";
|
|
30
|
+
|
|
31
|
+
export default ({ Plugin }: PluginArg): PluginObject => {
|
|
32
|
+
const me = Plugin(Order.VariableMasking, {
|
|
33
|
+
changeData: {
|
|
34
|
+
functions: 0,
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const transformFunction = (fnPath: NodePath<t.Function>) => {
|
|
39
|
+
// Do not apply to getter/setter methods
|
|
40
|
+
if (fnPath.isObjectMethod() && fnPath.node.kind !== "method") {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Do not apply to class getters/setters
|
|
45
|
+
if (fnPath.isClassMethod() && fnPath.node.kind !== "method") {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Do not apply to async or generator functions
|
|
50
|
+
if (fnPath.node.generator || fnPath.node.async) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Do not apply to functions with rest parameters or destructuring
|
|
55
|
+
if (fnPath.node.params.some((param) => !t.isIdentifier(param))) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Do not apply to 'use strict' functions
|
|
60
|
+
if (isStrictMode(fnPath)) return;
|
|
61
|
+
|
|
62
|
+
// Do not apply to functions marked unsafe
|
|
63
|
+
if ((fnPath.node as NodeSymbol)[UNSAFE]) return;
|
|
64
|
+
|
|
65
|
+
const functionName = getFunctionName(fnPath);
|
|
66
|
+
|
|
67
|
+
if (!me.computeProbabilityMap(me.options.variableMasking, functionName)) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const stackName = me.getPlaceholder() + "_varMask";
|
|
72
|
+
const stackMap = new Map<Binding, number | string>();
|
|
73
|
+
const propertyGen = new NameGen("mangled");
|
|
74
|
+
const stackKeys = new Set<string>();
|
|
75
|
+
let needsStack = false;
|
|
76
|
+
|
|
77
|
+
const illegalBindings = new Set<Binding>();
|
|
78
|
+
|
|
79
|
+
function checkBinding(binding: Binding) {
|
|
80
|
+
// Custom illegal check
|
|
81
|
+
// Variable Declarations with more than one declarator are not supported
|
|
82
|
+
// They can be inserted from the user's code even though Preparation phase should prevent it
|
|
83
|
+
// String Compression library includes such code
|
|
84
|
+
// TODO: Support multiple declarators
|
|
85
|
+
var variableDeclaration = binding.path.find((p) =>
|
|
86
|
+
p.isVariableDeclaration()
|
|
87
|
+
) as NodePath<t.VariableDeclaration>;
|
|
88
|
+
if (
|
|
89
|
+
variableDeclaration &&
|
|
90
|
+
variableDeclaration.node.declarations.length > 1
|
|
91
|
+
) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function checkForUnsafe(valuePath: NodePath) {
|
|
96
|
+
var hasUnsafeNode = false;
|
|
97
|
+
|
|
98
|
+
valuePath.traverse({
|
|
99
|
+
ThisExpression(path) {
|
|
100
|
+
hasUnsafeNode = true;
|
|
101
|
+
path.stop();
|
|
102
|
+
},
|
|
103
|
+
Function(path) {
|
|
104
|
+
if ((path.node as NodeSymbol)[UNSAFE]) {
|
|
105
|
+
hasUnsafeNode = true;
|
|
106
|
+
path.stop();
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
return hasUnsafeNode;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Check function value for 'this'
|
|
115
|
+
// Adding function expression to the stack (member expression)
|
|
116
|
+
// would break the 'this' context
|
|
117
|
+
if (binding.path.isVariableDeclarator()) {
|
|
118
|
+
let init = binding.path.get("init");
|
|
119
|
+
if (init.node) {
|
|
120
|
+
if (checkForUnsafe(init)) return false;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// x = function(){ return this }
|
|
125
|
+
// Cannot be transformed to x = stack[0] as 'this' would change
|
|
126
|
+
for (var assignment of binding.constantViolations) {
|
|
127
|
+
if (checkForUnsafe(assignment)) return false;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// __JS_CONFUSER_VAR__(identifier) -> __JS_CONFUSER_VAR__(stack.identifier)
|
|
131
|
+
// This cannot be transformed as it would break the user's code
|
|
132
|
+
for (var referencePath of binding.referencePaths) {
|
|
133
|
+
if (isVariableFunctionIdentifier(referencePath)) {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
for (const param of fnPath.get("params")) {
|
|
142
|
+
ok(param.isIdentifier());
|
|
143
|
+
|
|
144
|
+
const paramName = param.node.name;
|
|
145
|
+
const binding = param.scope.getBinding(paramName);
|
|
146
|
+
|
|
147
|
+
if (!binding || !checkBinding(binding)) return;
|
|
148
|
+
|
|
149
|
+
ok(!stackMap.has(binding));
|
|
150
|
+
stackKeys.add(stackMap.size.toString());
|
|
151
|
+
stackMap.set(binding, stackMap.size);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
fnPath.traverse({
|
|
155
|
+
Identifier(path) {
|
|
156
|
+
if (!isVariableIdentifier(path)) return;
|
|
157
|
+
if (fnPath.get("id") === path) return; // Skip this function's name (Test #21)
|
|
158
|
+
|
|
159
|
+
if (reservedIdentifiers.has(path.node.name)) return;
|
|
160
|
+
if (me.options.globalVariables.has(path.node.name)) return;
|
|
161
|
+
if (path.node.name === stackName) return;
|
|
162
|
+
if (path.node.name === variableFunctionName) return;
|
|
163
|
+
|
|
164
|
+
const binding = path.scope.getBinding(path.node.name);
|
|
165
|
+
if (!binding || binding.scope !== fnPath.scope) return;
|
|
166
|
+
if (illegalBindings.has(binding)) return;
|
|
167
|
+
|
|
168
|
+
needsStack = true;
|
|
169
|
+
|
|
170
|
+
let index = stackMap.get(binding);
|
|
171
|
+
if (typeof index === "undefined") {
|
|
172
|
+
// Only transform var and let bindings
|
|
173
|
+
// Function declarations could be hoisted and changing them to declarations is breaking
|
|
174
|
+
if (!["var", "let"].includes(binding.kind)) {
|
|
175
|
+
illegalBindings.add(binding);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (!checkBinding(binding)) {
|
|
180
|
+
illegalBindings.add(binding);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
do {
|
|
185
|
+
index = choice([
|
|
186
|
+
stackMap.size,
|
|
187
|
+
propertyGen.generate(),
|
|
188
|
+
getRandomInteger(-250, 250),
|
|
189
|
+
]);
|
|
190
|
+
} while (!index || stackKeys.has(index.toString()));
|
|
191
|
+
|
|
192
|
+
stackMap.set(binding, index);
|
|
193
|
+
stackKeys.add(index.toString());
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const memberExpression = t.memberExpression(
|
|
197
|
+
t.identifier(stackName),
|
|
198
|
+
createLiteral(index),
|
|
199
|
+
true
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
if (isDefiningIdentifier(path)) {
|
|
203
|
+
replaceDefiningIdentifierToMemberExpression(path, memberExpression);
|
|
204
|
+
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
ensureComputedExpression(path);
|
|
209
|
+
path.replaceWith(memberExpression);
|
|
210
|
+
},
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
if (!needsStack) return;
|
|
214
|
+
|
|
215
|
+
const originalParamCount = fnPath.node.params.length;
|
|
216
|
+
const originalLength = computeFunctionLength(fnPath);
|
|
217
|
+
|
|
218
|
+
fnPath.node.params = [t.restElement(t.identifier(stackName))];
|
|
219
|
+
|
|
220
|
+
// Discard extraneous parameters
|
|
221
|
+
// Predictable functions are guaranteed to not have extraneous parameters
|
|
222
|
+
if (!(fnPath.node as NodeSymbol)[PREDICTABLE]) {
|
|
223
|
+
prepend(
|
|
224
|
+
fnPath,
|
|
225
|
+
new Template(`${stackName}["length"] = {originalParamCount};`).single({
|
|
226
|
+
originalParamCount: t.numericLiteral(originalParamCount),
|
|
227
|
+
})
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Function is no longer predictable
|
|
232
|
+
(fnPath.node as NodeSymbol)[PREDICTABLE] = false;
|
|
233
|
+
|
|
234
|
+
fnPath.scope.registerBinding("param", fnPath.get("params")[0], fnPath);
|
|
235
|
+
|
|
236
|
+
me.setFunctionLength(fnPath, originalLength);
|
|
237
|
+
|
|
238
|
+
me.changeData.functions++;
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
return {
|
|
242
|
+
visitor: {
|
|
243
|
+
Function: {
|
|
244
|
+
exit(path: NodePath<t.Function>) {
|
|
245
|
+
if (!path.get("body").isBlockStatement()) return;
|
|
246
|
+
|
|
247
|
+
transformFunction(path);
|
|
248
|
+
},
|
|
249
|
+
},
|
|
250
|
+
Program: {
|
|
251
|
+
enter(path) {
|
|
252
|
+
path.scope.crawl();
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
};
|
|
257
|
+
};
|
package/src/utils/IntGen.ts
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
export class IntGen {
|
|
2
|
-
private min: number;
|
|
3
|
-
private max: number;
|
|
4
|
-
private generatedInts: Set<number>;
|
|
5
|
-
|
|
6
|
-
constructor(min: number = -250, max: number = 250) {
|
|
7
|
-
this.min = min;
|
|
8
|
-
this.max = max;
|
|
9
|
-
this.generatedInts = new Set<number>();
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
private getRandomInt(min: number, max: number): number {
|
|
13
|
-
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
generate(): number {
|
|
17
|
-
let randomInt: number;
|
|
18
|
-
|
|
19
|
-
// Keep generating until we find a unique integer
|
|
20
|
-
do {
|
|
21
|
-
randomInt = this.getRandomInt(this.min, this.max);
|
|
22
|
-
|
|
23
|
-
// Expand the range if most integers in the current range are exhausted
|
|
24
|
-
if (this.generatedInts.size >= 0.8 * (this.max - this.min)) {
|
|
25
|
-
this.min -= 100;
|
|
26
|
-
this.max += 100;
|
|
27
|
-
}
|
|
28
|
-
} while (this.generatedInts.has(randomInt));
|
|
29
|
-
|
|
30
|
-
this.generatedInts.add(randomInt);
|
|
31
|
-
return randomInt;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
1
|
+
export class IntGen {
|
|
2
|
+
private min: number;
|
|
3
|
+
private max: number;
|
|
4
|
+
private generatedInts: Set<number>;
|
|
5
|
+
|
|
6
|
+
constructor(min: number = -250, max: number = 250) {
|
|
7
|
+
this.min = min;
|
|
8
|
+
this.max = max;
|
|
9
|
+
this.generatedInts = new Set<number>();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
private getRandomInt(min: number, max: number): number {
|
|
13
|
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
generate(): number {
|
|
17
|
+
let randomInt: number;
|
|
18
|
+
|
|
19
|
+
// Keep generating until we find a unique integer
|
|
20
|
+
do {
|
|
21
|
+
randomInt = this.getRandomInt(this.min, this.max);
|
|
22
|
+
|
|
23
|
+
// Expand the range if most integers in the current range are exhausted
|
|
24
|
+
if (this.generatedInts.size >= 0.8 * (this.max - this.min)) {
|
|
25
|
+
this.min -= 100;
|
|
26
|
+
this.max += 100;
|
|
27
|
+
}
|
|
28
|
+
} while (this.generatedInts.has(randomInt));
|
|
29
|
+
|
|
30
|
+
this.generatedInts.add(randomInt);
|
|
31
|
+
return randomInt;
|
|
32
|
+
}
|
|
33
|
+
}
|