js-confuser 2.0.0-alpha.2 → 2.0.0-alpha.4
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/.prettierrc +4 -0
- package/CHANGELOG.md +42 -8
- package/Migration.md +23 -8
- package/README.md +2 -2
- package/dist/constants.js +11 -2
- package/dist/index.js +49 -6
- package/dist/obfuscator.js +121 -10
- package/dist/order.js +0 -1
- package/dist/probability.js +1 -96
- package/dist/templates/getGlobalTemplate.js +4 -1
- package/dist/templates/integrityTemplate.js +1 -1
- package/dist/templates/stringCompressionTemplate.js +3 -3
- package/dist/templates/tamperProtectionTemplates.js +1 -1
- package/dist/templates/template.js +17 -12
- package/dist/transforms/controlFlowFlattening.js +112 -83
- package/dist/transforms/deadCode.js +21 -22
- package/dist/transforms/dispatcher.js +62 -37
- package/dist/transforms/extraction/duplicateLiteralsRemoval.js +5 -0
- package/dist/transforms/extraction/objectExtraction.js +1 -2
- package/dist/transforms/finalizer.js +1 -1
- package/dist/transforms/flatten.js +2 -19
- package/dist/transforms/identifier/globalConcealing.js +3 -4
- package/dist/transforms/identifier/movedDeclarations.js +12 -5
- package/dist/transforms/identifier/renameVariables.js +40 -6
- package/dist/transforms/lock/integrity.js +9 -1
- package/dist/transforms/lock/lock.js +16 -9
- package/dist/transforms/minify.js +64 -27
- package/dist/transforms/opaquePredicates.js +6 -7
- package/dist/transforms/pack.js +32 -5
- package/dist/transforms/plugin.js +20 -39
- package/dist/transforms/preparation.js +25 -36
- package/dist/transforms/renameLabels.js +1 -2
- package/dist/transforms/rgf.js +36 -16
- package/dist/transforms/shuffle.js +10 -11
- package/dist/transforms/string/stringCompression.js +14 -10
- package/dist/transforms/string/stringConcealing.js +7 -5
- package/dist/transforms/string/stringEncoding.js +4 -2
- package/dist/transforms/string/stringSplitting.js +4 -2
- package/dist/transforms/variableMasking.js +3 -2
- package/dist/utils/NameGen.js +5 -2
- package/dist/utils/PredicateGen.js +62 -0
- package/dist/utils/ast-utils.js +24 -9
- package/dist/utils/random-utils.js +10 -0
- package/dist/validateOptions.js +2 -2
- package/index.d.ts +16 -2
- package/package.json +2 -2
- package/src/constants.ts +15 -5
- package/src/index.ts +15 -5
- package/src/obfuscationResult.ts +7 -1
- package/src/obfuscator.ts +152 -12
- package/src/options.ts +26 -8
- package/src/order.ts +0 -2
- package/src/templates/getGlobalTemplate.ts +5 -1
- package/src/templates/integrityTemplate.ts +14 -19
- package/src/templates/stringCompressionTemplate.ts +4 -28
- package/src/templates/tamperProtectionTemplates.ts +7 -3
- package/src/templates/template.ts +5 -3
- package/src/transforms/controlFlowFlattening.ts +139 -83
- package/src/transforms/deadCode.ts +27 -30
- package/src/transforms/dispatcher.ts +24 -5
- package/src/transforms/extraction/duplicateLiteralsRemoval.ts +10 -1
- package/src/transforms/extraction/objectExtraction.ts +1 -2
- package/src/transforms/finalizer.ts +1 -1
- package/src/transforms/flatten.ts +3 -22
- package/src/transforms/identifier/globalConcealing.ts +26 -17
- package/src/transforms/identifier/movedDeclarations.ts +18 -6
- package/src/transforms/identifier/renameVariables.ts +48 -6
- package/src/transforms/lock/integrity.ts +11 -1
- package/src/transforms/lock/lock.ts +26 -10
- package/src/transforms/minify.ts +85 -38
- package/src/transforms/opaquePredicates.ts +6 -9
- package/src/transforms/pack.ts +41 -5
- package/src/transforms/plugin.ts +47 -69
- package/src/transforms/preparation.ts +33 -46
- package/src/transforms/renameLabels.ts +1 -2
- package/src/transforms/rgf.ts +52 -23
- package/src/transforms/shuffle.ts +28 -26
- package/src/transforms/string/encoding.ts +1 -1
- package/src/transforms/string/stringCompression.ts +22 -13
- package/src/transforms/string/stringConcealing.ts +13 -7
- package/src/transforms/string/stringEncoding.ts +6 -2
- package/src/transforms/string/stringSplitting.ts +9 -4
- package/src/transforms/variableMasking.ts +2 -2
- package/src/utils/NameGen.ts +13 -3
- package/src/utils/PredicateGen.ts +61 -0
- package/src/utils/ast-utils.ts +16 -9
- package/src/utils/random-utils.ts +14 -0
- package/src/validateOptions.ts +7 -4
- package/src/probability.ts +0 -110
- package/src/transforms/functionOutlining.ts +0 -225
- package/src/utils/ControlObject.ts +0 -141
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import traverse, { NodePath, Scope, Visitor } from "@babel/traverse";
|
|
2
2
|
import { PluginArg, PluginObject } from "./plugin";
|
|
3
3
|
import { Order } from "../order";
|
|
4
|
-
import { computeProbabilityMap } from "../probability";
|
|
5
4
|
import {
|
|
6
5
|
ensureComputedExpression,
|
|
7
6
|
getParentFunctionOrProgram,
|
|
@@ -30,9 +29,11 @@ import {
|
|
|
30
29
|
PREDICTABLE,
|
|
31
30
|
variableFunctionName,
|
|
32
31
|
WITH_STATEMENT,
|
|
33
|
-
CONTROL_OBJECTS,
|
|
34
32
|
} from "../constants";
|
|
35
33
|
|
|
34
|
+
// Function deemed unsafe for CFF
|
|
35
|
+
const CFF_UNSAFE = Symbol("CFF_UNSAFE");
|
|
36
|
+
|
|
36
37
|
/**
|
|
37
38
|
* Breaks functions into DAGs (Directed Acyclic Graphs)
|
|
38
39
|
*
|
|
@@ -77,13 +78,44 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
77
78
|
|
|
78
79
|
const functionsModified = new Set<t.Node>();
|
|
79
80
|
|
|
81
|
+
function flagFunctionToAvoid(path: NodePath, reason: string) {
|
|
82
|
+
var fnOrProgram = getParentFunctionOrProgram(path);
|
|
83
|
+
|
|
84
|
+
fnOrProgram.node[CFF_UNSAFE] = reason;
|
|
85
|
+
}
|
|
86
|
+
|
|
80
87
|
return {
|
|
81
88
|
post: () => {
|
|
82
89
|
functionsModified.forEach((node) => {
|
|
83
90
|
(node as NodeSymbol)[UNSAFE] = true;
|
|
84
91
|
});
|
|
85
92
|
},
|
|
93
|
+
|
|
86
94
|
visitor: {
|
|
95
|
+
// Unsafe detection
|
|
96
|
+
ThisExpression(path) {
|
|
97
|
+
flagFunctionToAvoid(path, "this");
|
|
98
|
+
},
|
|
99
|
+
VariableDeclaration(path) {
|
|
100
|
+
if (path.node.declarations.length !== 1) {
|
|
101
|
+
path.getAncestry().forEach((p) => {
|
|
102
|
+
p.node[CFF_UNSAFE] = "multipleDeclarations";
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
Identifier(path) {
|
|
107
|
+
if (
|
|
108
|
+
path.node.name === variableFunctionName ||
|
|
109
|
+
path.node.name === "arguments"
|
|
110
|
+
) {
|
|
111
|
+
flagFunctionToAvoid(path, "arguments");
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
"Super|MetaProperty|AwaitExpression|YieldExpression"(path) {
|
|
115
|
+
flagFunctionToAvoid(path, "functionSpecific");
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
// Main CFF transformation
|
|
87
119
|
"Program|Function": {
|
|
88
120
|
exit(_path) {
|
|
89
121
|
let programOrFunctionPath = _path as NodePath<t.Program | t.Function>;
|
|
@@ -94,6 +126,9 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
94
126
|
)
|
|
95
127
|
return;
|
|
96
128
|
|
|
129
|
+
// Exclude 'CFF_UNSAFE' functions
|
|
130
|
+
if (programOrFunctionPath.node[CFF_UNSAFE]) return;
|
|
131
|
+
|
|
97
132
|
let programPath = _path.isProgram() ? _path : null;
|
|
98
133
|
let functionPath = _path.isFunction() ? _path : null;
|
|
99
134
|
|
|
@@ -116,13 +151,16 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
116
151
|
if (blockPath.node.body.length < 3) return;
|
|
117
152
|
|
|
118
153
|
// Check user's threshold setting
|
|
119
|
-
if (!computeProbabilityMap(me.options.controlFlowFlattening)) {
|
|
154
|
+
if (!me.computeProbabilityMap(me.options.controlFlowFlattening)) {
|
|
120
155
|
return;
|
|
121
156
|
}
|
|
122
157
|
|
|
123
|
-
|
|
124
|
-
|
|
158
|
+
if (functionPath) {
|
|
159
|
+
// Avoid unsafe functions
|
|
160
|
+
if ((functionPath.node as NodeSymbol)[UNSAFE]) return;
|
|
125
161
|
|
|
162
|
+
if (functionPath.node.async || functionPath.node.generator) return;
|
|
163
|
+
}
|
|
126
164
|
programOrFunctionPath.scope.crawl();
|
|
127
165
|
|
|
128
166
|
const blockFnParent = getParentFunctionOrProgram(blockPath);
|
|
@@ -130,30 +168,7 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
130
168
|
let hasIllegalNode = false;
|
|
131
169
|
const bindingNames = new Set<string>();
|
|
132
170
|
blockPath.traverse({
|
|
133
|
-
"Super|MetaProperty|AwaitExpression|YieldExpression"(path) {
|
|
134
|
-
if (
|
|
135
|
-
getParentFunctionOrProgram(path).node === blockFnParent.node
|
|
136
|
-
) {
|
|
137
|
-
hasIllegalNode = true;
|
|
138
|
-
path.stop();
|
|
139
|
-
}
|
|
140
|
-
},
|
|
141
|
-
VariableDeclaration(path) {
|
|
142
|
-
if (path.node.declarations.length !== 1) {
|
|
143
|
-
hasIllegalNode = true;
|
|
144
|
-
path.stop();
|
|
145
|
-
}
|
|
146
|
-
},
|
|
147
171
|
Identifier(path) {
|
|
148
|
-
if (
|
|
149
|
-
path.node.name === variableFunctionName ||
|
|
150
|
-
path.node.name === "arguments"
|
|
151
|
-
) {
|
|
152
|
-
hasIllegalNode = true;
|
|
153
|
-
path.stop();
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
172
|
if (!path.isBindingIdentifier()) return;
|
|
158
173
|
const binding = path.scope.getBinding(path.node.name);
|
|
159
174
|
if (!binding) return;
|
|
@@ -319,7 +334,7 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
319
334
|
identity: "${this.propertyName}"
|
|
320
335
|
})
|
|
321
336
|
`).expression()
|
|
322
|
-
: new Template(`
|
|
337
|
+
: new Template(`({})`).expression();
|
|
323
338
|
}
|
|
324
339
|
|
|
325
340
|
getMemberExpression(name: string) {
|
|
@@ -375,6 +390,25 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
375
390
|
);
|
|
376
391
|
}
|
|
377
392
|
|
|
393
|
+
if (this === mainScope) {
|
|
394
|
+
// Reset With logic
|
|
395
|
+
properties.push(
|
|
396
|
+
t.objectProperty(
|
|
397
|
+
t.stringLiteral(resetWithProperty),
|
|
398
|
+
new Template(`
|
|
399
|
+
(function(newStateValues, alwaysUndefined){
|
|
400
|
+
{withMemberExpression} = alwaysUndefined;
|
|
401
|
+
{arrayPattern} = newStateValues
|
|
402
|
+
})
|
|
403
|
+
`).expression({
|
|
404
|
+
withMemberExpression: deepClone(withMemberExpression),
|
|
405
|
+
arrayPattern: t.arrayPattern(deepClone(stateVars)),
|
|
406
|
+
}),
|
|
407
|
+
true
|
|
408
|
+
)
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
|
|
378
412
|
return t.objectExpression(properties);
|
|
379
413
|
}
|
|
380
414
|
|
|
@@ -660,7 +694,9 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
660
694
|
!flattenFunctionDeclarations ||
|
|
661
695
|
statement.node.async ||
|
|
662
696
|
statement.node.generator ||
|
|
663
|
-
(statement.node as NodeSymbol)[UNSAFE]
|
|
697
|
+
(statement.node as NodeSymbol)[UNSAFE] ||
|
|
698
|
+
(statement.node as NodeSymbol)[CFF_UNSAFE] ||
|
|
699
|
+
isStrictMode(statement)
|
|
664
700
|
) {
|
|
665
701
|
isIllegal = true;
|
|
666
702
|
}
|
|
@@ -872,20 +908,6 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
872
908
|
|
|
873
909
|
basicBlocks.get(endLabel).allowWithDiscriminant = false;
|
|
874
910
|
|
|
875
|
-
// Add with / reset with logic
|
|
876
|
-
basicBlocks.get(startLabel).body.unshift(
|
|
877
|
-
new Template(`
|
|
878
|
-
{resetWithMemberExpression} = function(newStateValues){
|
|
879
|
-
{withMemberExpression} = undefined;
|
|
880
|
-
{arrayPattern} = newStateValues
|
|
881
|
-
}
|
|
882
|
-
`).single({
|
|
883
|
-
arrayPattern: t.arrayPattern(deepClone(stateVars)),
|
|
884
|
-
resetWithMemberExpression: deepClone(resetWithMemberExpression),
|
|
885
|
-
withMemberExpression: deepClone(withMemberExpression),
|
|
886
|
-
})
|
|
887
|
-
);
|
|
888
|
-
|
|
889
911
|
if (!isDebug && addDeadCode) {
|
|
890
912
|
// DEAD CODE 1/3: Add fake chunks that are never reached
|
|
891
913
|
const fakeChunkCount = getRandomInteger(1, 5);
|
|
@@ -1081,7 +1103,7 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
1081
1103
|
const identifierName = path.node.name;
|
|
1082
1104
|
if (identifierName === gotoFunctionName) return;
|
|
1083
1105
|
|
|
1084
|
-
var binding =
|
|
1106
|
+
var binding = path.scope.getBinding(identifierName);
|
|
1085
1107
|
if (!binding) {
|
|
1086
1108
|
return;
|
|
1087
1109
|
}
|
|
@@ -1139,6 +1161,17 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
1139
1161
|
|
|
1140
1162
|
path.replaceWith(memberExpression);
|
|
1141
1163
|
path.skip();
|
|
1164
|
+
|
|
1165
|
+
// Preserve proper 'this' context when directly calling functions
|
|
1166
|
+
// X.Y.Z() -> (1, X.Y.Z)()
|
|
1167
|
+
if (
|
|
1168
|
+
path.parentPath.isCallExpression() &&
|
|
1169
|
+
path.key === "callee"
|
|
1170
|
+
) {
|
|
1171
|
+
path.replaceWith(
|
|
1172
|
+
t.sequenceExpression([t.numericLiteral(1), path.node])
|
|
1173
|
+
);
|
|
1174
|
+
}
|
|
1142
1175
|
},
|
|
1143
1176
|
},
|
|
1144
1177
|
|
|
@@ -1212,15 +1245,9 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
1212
1245
|
// console.log(oldValue, newValue);
|
|
1213
1246
|
if (oldValue === newValue) continue; // No diff needed if the value doesn't change
|
|
1214
1247
|
|
|
1215
|
-
const leftValue = jumpBlock.withDiscriminant
|
|
1216
|
-
? jumpBlock.withDiscriminant.getMemberExpression(
|
|
1217
|
-
stateVars[i].name
|
|
1218
|
-
)
|
|
1219
|
-
: deepClone(stateVars[i]);
|
|
1220
|
-
|
|
1221
1248
|
let assignment = t.assignmentExpression(
|
|
1222
1249
|
"=",
|
|
1223
|
-
|
|
1250
|
+
deepClone(stateVars[i]),
|
|
1224
1251
|
numericLiteral(newValue)
|
|
1225
1252
|
);
|
|
1226
1253
|
|
|
@@ -1271,7 +1298,8 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
1271
1298
|
const mainScope = basicBlocks.get(startLabel).scopeManager;
|
|
1272
1299
|
const predicateNumbers = new Map<string, number>();
|
|
1273
1300
|
const predicateNumberCount =
|
|
1274
|
-
isDebug || !addPredicateTests ? 0 : getRandomInteger(
|
|
1301
|
+
isDebug || !addPredicateTests ? 0 : getRandomInteger(1, 4);
|
|
1302
|
+
|
|
1275
1303
|
for (let i = 0; i < predicateNumberCount; i++) {
|
|
1276
1304
|
const name = mainScope.getNewName(
|
|
1277
1305
|
me.getPlaceholder("predicate_" + i)
|
|
@@ -1279,27 +1307,47 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
1279
1307
|
|
|
1280
1308
|
const number = getRandomInteger(-250, 250);
|
|
1281
1309
|
predicateNumbers.set(name, number);
|
|
1310
|
+
}
|
|
1282
1311
|
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1312
|
+
const predicateSymbol = Symbol("predicate");
|
|
1313
|
+
|
|
1314
|
+
const createAssignment = (values: number[]) => {
|
|
1315
|
+
var exprStmt = new Template(`
|
|
1316
|
+
({predicateVariables} = {values})
|
|
1317
|
+
`).single({
|
|
1318
|
+
predicateVariables: t.arrayPattern(
|
|
1319
|
+
Array.from(predicateNumbers.keys()).map((name) =>
|
|
1320
|
+
mainScope.getMemberExpression(name)
|
|
1321
|
+
)
|
|
1322
|
+
),
|
|
1323
|
+
values: t.arrayExpression(
|
|
1324
|
+
values.map((value) => numericLiteral(value))
|
|
1325
|
+
),
|
|
1326
|
+
});
|
|
1291
1327
|
|
|
1292
|
-
|
|
1328
|
+
exprStmt[predicateSymbol] = true;
|
|
1293
1329
|
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1330
|
+
return exprStmt;
|
|
1331
|
+
};
|
|
1332
|
+
|
|
1333
|
+
basicBlocks
|
|
1334
|
+
.get(startLabel)
|
|
1335
|
+
.body.unshift(
|
|
1336
|
+
createAssignment(Array.from(predicateNumbers.values()))
|
|
1337
|
+
);
|
|
1338
|
+
|
|
1339
|
+
// Add random assignments to impossible blocks
|
|
1340
|
+
var fakeAssignmentCount = getRandomInteger(1, 3);
|
|
1341
|
+
|
|
1342
|
+
for (let i = 0; i < fakeAssignmentCount; i++) {
|
|
1343
|
+
var impossibleBlock = choice(getImpossibleBasicBlocks());
|
|
1344
|
+
if (impossibleBlock) {
|
|
1345
|
+
if (impossibleBlock.body[0]?.[predicateSymbol]) continue;
|
|
1346
|
+
|
|
1347
|
+
var fakeValues = new Array(predicateNumberCount)
|
|
1348
|
+
.fill(0)
|
|
1349
|
+
.map(() => getRandomInteger(-250, 250));
|
|
1350
|
+
impossibleBlock.body.unshift(createAssignment(fakeValues));
|
|
1303
1351
|
}
|
|
1304
1352
|
}
|
|
1305
1353
|
|
|
@@ -1467,9 +1515,7 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
1467
1515
|
),
|
|
1468
1516
|
t.blockStatement([
|
|
1469
1517
|
t.withStatement(
|
|
1470
|
-
new Template(
|
|
1471
|
-
`{withDiscriminant} || Object["create"](null)`
|
|
1472
|
-
).expression({
|
|
1518
|
+
new Template(`{withDiscriminant} || {}`).expression({
|
|
1473
1519
|
withDiscriminant: deepClone(withMemberExpression),
|
|
1474
1520
|
}),
|
|
1475
1521
|
t.blockStatement([switchStatement])
|
|
@@ -1533,6 +1579,17 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
1533
1579
|
);
|
|
1534
1580
|
}
|
|
1535
1581
|
|
|
1582
|
+
const startProgramObjectExpression = basicBlocks
|
|
1583
|
+
.get(startLabel)
|
|
1584
|
+
.scopeManager.getObjectExpression(startLabel);
|
|
1585
|
+
|
|
1586
|
+
const mainParameters: t.FunctionDeclaration["params"] = parameters;
|
|
1587
|
+
const scopeParameter = mainParameters.pop() as t.Identifier;
|
|
1588
|
+
|
|
1589
|
+
mainParameters.push(
|
|
1590
|
+
t.assignmentPattern(scopeParameter, startProgramObjectExpression)
|
|
1591
|
+
);
|
|
1592
|
+
|
|
1536
1593
|
const mainFnDeclaration = t.functionDeclaration(
|
|
1537
1594
|
deepClone(mainFnName),
|
|
1538
1595
|
parameters,
|
|
@@ -1544,17 +1601,19 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
1544
1601
|
var startProgramExpression = t.callExpression(deepClone(mainFnName), [
|
|
1545
1602
|
...startStateValues.map((stateValue) => numericLiteral(stateValue)),
|
|
1546
1603
|
t.identifier("undefined"),
|
|
1547
|
-
basicBlocks
|
|
1548
|
-
.get(startLabel)
|
|
1549
|
-
.scopeManager.getObjectExpression(startLabel),
|
|
1550
1604
|
]);
|
|
1551
1605
|
|
|
1552
|
-
|
|
1553
|
-
|
|
1606
|
+
const resultVar = withIdentifier("result");
|
|
1607
|
+
|
|
1608
|
+
const isTopLevel = blockPath.isProgram();
|
|
1609
|
+
const allowReturns =
|
|
1610
|
+
!isTopLevel && blockPath.find((p) => p.isFunction());
|
|
1611
|
+
|
|
1612
|
+
const startPrefix = allowReturns ? `var {resultVar} = ` : "";
|
|
1554
1613
|
|
|
1555
1614
|
const startProgramStatements = new Template(`
|
|
1556
1615
|
${allowReturns ? `var {didReturnVar};` : ""}
|
|
1557
|
-
|
|
1616
|
+
${startPrefix}{startProgramExpression};
|
|
1558
1617
|
${
|
|
1559
1618
|
allowReturns
|
|
1560
1619
|
? `
|
|
@@ -1580,9 +1639,6 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
1580
1639
|
// Reset all bindings here
|
|
1581
1640
|
blockPath.scope.bindings = Object.create(null);
|
|
1582
1641
|
|
|
1583
|
-
// Bindings changed - breaking control objects
|
|
1584
|
-
delete (blockPath.node as NodeSymbol)[CONTROL_OBJECTS];
|
|
1585
|
-
|
|
1586
1642
|
// Register new declarations
|
|
1587
1643
|
for (var node of blockPath.get("body")) {
|
|
1588
1644
|
blockPath.scope.registerDeclaration(node);
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { PluginArg, PluginObject } from "./plugin";
|
|
2
|
-
import {
|
|
2
|
+
import { choice } from "../utils/random-utils";
|
|
3
3
|
import { deadCodeTemplates } from "../templates/deadCodeTemplates";
|
|
4
|
-
import { computeProbabilityMap } from "../probability";
|
|
5
4
|
import { Order } from "../order";
|
|
6
5
|
import * as t from "@babel/types";
|
|
7
6
|
import Template from "../templates/template";
|
|
8
|
-
import { NameGen } from "../utils/NameGen";
|
|
9
7
|
import { prepend } from "../utils/ast-utils";
|
|
8
|
+
import PredicateGen from "../utils/PredicateGen";
|
|
10
9
|
|
|
11
10
|
export default ({ Plugin }: PluginArg): PluginObject => {
|
|
12
11
|
const me = Plugin(Order.DeadCode, {
|
|
@@ -14,7 +13,7 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
14
13
|
deadCode: 0,
|
|
15
14
|
},
|
|
16
15
|
});
|
|
17
|
-
let
|
|
16
|
+
let predicateGen = new PredicateGen(me);
|
|
18
17
|
|
|
19
18
|
return {
|
|
20
19
|
visitor: {
|
|
@@ -22,29 +21,41 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
22
21
|
exit(blockPath) {
|
|
23
22
|
if (blockPath.find((p) => me.isSkipped(p))) return;
|
|
24
23
|
|
|
25
|
-
if (!computeProbabilityMap(me.options.deadCode)) {
|
|
24
|
+
if (!me.computeProbabilityMap(me.options.deadCode)) {
|
|
26
25
|
return;
|
|
27
26
|
}
|
|
28
27
|
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
// Default limit on dead code
|
|
29
|
+
// May be overridden by user
|
|
30
|
+
if (
|
|
31
|
+
typeof me.options.deadCode !== "function" &&
|
|
32
|
+
typeof me.options.deadCode !== "object"
|
|
33
|
+
) {
|
|
34
|
+
let suggestedMax = 20;
|
|
31
35
|
if (me.obfuscator.parentObfuscator) {
|
|
32
36
|
// RGF should contain less dead code
|
|
33
37
|
suggestedMax = 5;
|
|
34
38
|
}
|
|
35
39
|
|
|
36
|
-
if (
|
|
40
|
+
if (me.changeData.deadCode >= suggestedMax) {
|
|
37
41
|
return;
|
|
38
|
-
|
|
42
|
+
}
|
|
39
43
|
}
|
|
40
44
|
|
|
45
|
+
// Increment dead code counter
|
|
46
|
+
me.changeData.deadCode++;
|
|
47
|
+
|
|
41
48
|
var template = choice(deadCodeTemplates);
|
|
42
49
|
var nodes = template.compile();
|
|
43
50
|
|
|
44
|
-
var containingFnName = me.getPlaceholder(
|
|
51
|
+
var containingFnName = me.getPlaceholder(
|
|
52
|
+
"dead_" + me.changeData.deadCode
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
// Insert dummy function
|
|
56
|
+
prepend(
|
|
57
|
+
blockPath,
|
|
45
58
|
|
|
46
|
-
var newPath = blockPath.unshiftContainer(
|
|
47
|
-
"body",
|
|
48
59
|
t.functionDeclaration(
|
|
49
60
|
t.identifier(containingFnName),
|
|
50
61
|
[],
|
|
@@ -52,29 +63,15 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
52
63
|
)
|
|
53
64
|
);
|
|
54
65
|
|
|
55
|
-
// Overcomplicated way to get a random property name that doesn't exist on the Function
|
|
56
|
-
var randomProperty: string;
|
|
57
|
-
var nameGen = new NameGen("randomized");
|
|
58
|
-
|
|
59
|
-
function PrototypeCollision() {}
|
|
60
|
-
PrototypeCollision(); // Call it for code coverage :D
|
|
61
|
-
|
|
62
|
-
do {
|
|
63
|
-
randomProperty = nameGen.generate();
|
|
64
|
-
} while (
|
|
65
|
-
!randomProperty ||
|
|
66
|
-
PrototypeCollision[randomProperty] !== undefined
|
|
67
|
-
);
|
|
68
|
-
|
|
69
|
-
me.changeData.deadCode++;
|
|
70
|
-
|
|
71
66
|
prepend(
|
|
72
67
|
blockPath,
|
|
73
68
|
new Template(`
|
|
74
|
-
if(
|
|
69
|
+
if({falsePredicate}) {
|
|
75
70
|
${containingFnName}()
|
|
76
71
|
}
|
|
77
|
-
`).single(
|
|
72
|
+
`).single({
|
|
73
|
+
falsePredicate: predicateGen.generateFalseExpression(blockPath),
|
|
74
|
+
})
|
|
78
75
|
);
|
|
79
76
|
|
|
80
77
|
me.skip(blockPath);
|
|
@@ -4,7 +4,6 @@ import * as t from "@babel/types";
|
|
|
4
4
|
import Template from "../templates/template";
|
|
5
5
|
import { ok } from "assert";
|
|
6
6
|
import { chance, getRandomString } from "../utils/random-utils";
|
|
7
|
-
import { computeProbabilityMap } from "../probability";
|
|
8
7
|
import { Order } from "../order";
|
|
9
8
|
import { NodeSymbol, PREDICTABLE, UNSAFE } from "../constants";
|
|
10
9
|
import {
|
|
@@ -127,11 +126,31 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
127
126
|
return;
|
|
128
127
|
}
|
|
129
128
|
|
|
129
|
+
var hasAssignmentPattern = false;
|
|
130
|
+
|
|
131
|
+
for (var param of path.get("params")) {
|
|
132
|
+
if (param.isAssignmentPattern()) {
|
|
133
|
+
hasAssignmentPattern = true;
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
param.traverse({
|
|
137
|
+
AssignmentPattern(innerPath) {
|
|
138
|
+
var fn = innerPath.getFunctionParent();
|
|
139
|
+
if (fn === path) {
|
|
140
|
+
hasAssignmentPattern = true;
|
|
141
|
+
innerPath.stop();
|
|
142
|
+
} else {
|
|
143
|
+
innerPath.skip();
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
if (hasAssignmentPattern) break;
|
|
149
|
+
}
|
|
150
|
+
|
|
130
151
|
// Functions with default parameters are not fully supported
|
|
131
152
|
// (Could be a Function Expression referencing outer scope)
|
|
132
|
-
if (
|
|
133
|
-
path.node.params.find((x) => x.type === "AssignmentPattern")
|
|
134
|
-
) {
|
|
153
|
+
if (hasAssignmentPattern) {
|
|
135
154
|
illegalNames.add(name);
|
|
136
155
|
return;
|
|
137
156
|
}
|
|
@@ -146,7 +165,7 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
146
165
|
}
|
|
147
166
|
|
|
148
167
|
for (var name of functionPaths.keys()) {
|
|
149
|
-
if (!computeProbabilityMap(me.options.dispatcher, name)) {
|
|
168
|
+
if (!me.computeProbabilityMap(me.options.dispatcher, name)) {
|
|
150
169
|
functionPaths.delete(name);
|
|
151
170
|
}
|
|
152
171
|
}
|
|
@@ -2,7 +2,11 @@ import * as t from "@babel/types";
|
|
|
2
2
|
import { ok } from "assert";
|
|
3
3
|
import { PluginArg, PluginObject } from "../plugin";
|
|
4
4
|
import { Order } from "../../order";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
ensureComputedExpression,
|
|
7
|
+
isModuleImport,
|
|
8
|
+
prepend,
|
|
9
|
+
} from "../../utils/ast-utils";
|
|
6
10
|
import { createLiteral, LiteralValue, numericLiteral } from "../../utils/node";
|
|
7
11
|
import { NodePath } from "@babel/traverse";
|
|
8
12
|
|
|
@@ -49,6 +53,11 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
49
53
|
t.Literal | t.Identifier
|
|
50
54
|
>;
|
|
51
55
|
|
|
56
|
+
// Don't change module imports
|
|
57
|
+
if (literalPath.isStringLiteral()) {
|
|
58
|
+
if (isModuleImport(literalPath)) return;
|
|
59
|
+
}
|
|
60
|
+
|
|
52
61
|
let node = literalPath.node;
|
|
53
62
|
var isUndefined = false;
|
|
54
63
|
if (literalPath.isIdentifier()) {
|
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
getObjectPropertyAsString,
|
|
8
8
|
getParentFunctionOrProgram,
|
|
9
9
|
} from "../../utils/ast-utils";
|
|
10
|
-
import { computeProbabilityMap } from "../../probability";
|
|
11
10
|
|
|
12
11
|
export default ({ Plugin }: PluginArg): PluginObject => {
|
|
13
12
|
const me = Plugin(Order.ObjectExtraction, {
|
|
@@ -152,7 +151,7 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
152
151
|
if (!isObjectSafe) return;
|
|
153
152
|
|
|
154
153
|
if (
|
|
155
|
-
!computeProbabilityMap(
|
|
154
|
+
!me.computeProbabilityMap(
|
|
156
155
|
me.options.objectExtraction,
|
|
157
156
|
identifier.node.name
|
|
158
157
|
)
|
|
@@ -11,7 +11,6 @@ import {
|
|
|
11
11
|
prependProgram,
|
|
12
12
|
} from "../utils/ast-utils";
|
|
13
13
|
import { PluginArg, PluginObject } from "./plugin";
|
|
14
|
-
import { computeProbabilityMap } from "../probability";
|
|
15
14
|
import { Order } from "../order";
|
|
16
15
|
import { NodeSymbol, PREDICTABLE, UNSAFE } from "../constants";
|
|
17
16
|
import {
|
|
@@ -58,7 +57,7 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
58
57
|
functionName = "anonymous";
|
|
59
58
|
}
|
|
60
59
|
|
|
61
|
-
if (!computeProbabilityMap(me.options.flatten, functionName)) {
|
|
60
|
+
if (!me.computeProbabilityMap(me.options.flatten, functionName)) {
|
|
62
61
|
return;
|
|
63
62
|
}
|
|
64
63
|
|
|
@@ -117,26 +116,8 @@ export default ({ Plugin }: PluginArg): PluginObject => {
|
|
|
117
116
|
return;
|
|
118
117
|
}
|
|
119
118
|
|
|
120
|
-
var
|
|
121
|
-
|
|
122
|
-
if (definedLocal.hasOwnBinding(identifierName)) return;
|
|
123
|
-
if (definedLocal === fnPath.scope) break;
|
|
124
|
-
|
|
125
|
-
definedLocal = definedLocal.parent;
|
|
126
|
-
if (definedLocal === program.scope)
|
|
127
|
-
ok(functionName + ":" + identifierName);
|
|
128
|
-
} while (definedLocal);
|
|
129
|
-
|
|
130
|
-
var cursor: Scope = fnPath.scope.parent;
|
|
131
|
-
var isOutsideVariable = false;
|
|
132
|
-
|
|
133
|
-
do {
|
|
134
|
-
if (cursor.hasBinding(identifierName)) {
|
|
135
|
-
isOutsideVariable = true;
|
|
136
|
-
break;
|
|
137
|
-
}
|
|
138
|
-
cursor = cursor.parent;
|
|
139
|
-
} while (cursor);
|
|
119
|
+
var isOutsideVariable =
|
|
120
|
+
fnPath.scope.parent.getBinding(identifierName) === binding;
|
|
140
121
|
|
|
141
122
|
if (!isOutsideVariable) {
|
|
142
123
|
return;
|