js-confuser 2.0.0-alpha.2 → 2.0.0-alpha.3
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 +24 -6
- package/dist/constants.js +6 -2
- package/dist/index.js +12 -0
- package/dist/obfuscator.js +117 -6
- package/dist/order.js +0 -1
- package/dist/probability.js +1 -96
- package/dist/templates/getGlobalTemplate.js +4 -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 +2 -6
- package/dist/transforms/deadCode.js +8 -15
- package/dist/transforms/dispatcher.js +1 -2
- 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 +1 -2
- package/dist/transforms/identifier/movedDeclarations.js +12 -5
- package/dist/transforms/identifier/renameVariables.js +7 -6
- package/dist/transforms/lock/lock.js +9 -2
- package/dist/transforms/minify.js +14 -1
- package/dist/transforms/opaquePredicates.js +5 -6
- package/dist/transforms/pack.js +5 -0
- package/dist/transforms/plugin.js +20 -39
- package/dist/transforms/renameLabels.js +1 -2
- package/dist/transforms/rgf.js +29 -11
- package/dist/transforms/shuffle.js +10 -11
- package/dist/transforms/string/stringCompression.js +14 -10
- package/dist/transforms/string/stringConcealing.js +4 -4
- package/dist/transforms/string/stringEncoding.js +4 -2
- package/dist/transforms/string/stringSplitting.js +4 -2
- package/dist/transforms/variableMasking.js +1 -2
- package/dist/utils/NameGen.js +3 -2
- package/dist/utils/PredicateGen.js +62 -0
- package/dist/utils/ast-utils.js +24 -9
- package/dist/validateOptions.js +2 -2
- package/package.json +2 -2
- package/src/constants.ts +6 -5
- package/src/index.ts +1 -0
- package/src/obfuscator.ts +148 -7
- package/src/options.ts +14 -6
- package/src/order.ts +0 -2
- package/src/probability.ts +0 -110
- package/src/templates/getGlobalTemplate.ts +5 -1
- 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 +2 -7
- package/src/transforms/deadCode.ts +11 -23
- package/src/transforms/dispatcher.ts +1 -2
- 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 +4 -2
- package/src/transforms/identifier/movedDeclarations.ts +18 -6
- package/src/transforms/identifier/renameVariables.ts +10 -6
- package/src/transforms/lock/lock.ts +14 -3
- package/src/transforms/minify.ts +24 -2
- package/src/transforms/opaquePredicates.ts +5 -8
- package/src/transforms/pack.ts +6 -0
- package/src/transforms/plugin.ts +47 -69
- package/src/transforms/renameLabels.ts +1 -2
- package/src/transforms/rgf.ts +39 -14
- 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 +11 -7
- package/src/transforms/string/stringEncoding.ts +6 -2
- package/src/transforms/string/stringSplitting.ts +9 -4
- package/src/transforms/variableMasking.ts +1 -2
- package/src/utils/NameGen.ts +4 -2
- package/src/utils/PredicateGen.ts +61 -0
- package/src/utils/ast-utils.ts +16 -9
- package/src/validateOptions.ts +7 -4
- package/src/transforms/functionOutlining.ts +0 -225
- package/src/utils/ControlObject.ts +0 -141
|
@@ -1,225 +0,0 @@
|
|
|
1
|
-
import { NodePath } from "@babel/traverse";
|
|
2
|
-
import { PluginArg, PluginObject } from "./plugin";
|
|
3
|
-
import { Order } from "../order";
|
|
4
|
-
import { ensureComputedExpression, prepend } from "../utils/ast-utils";
|
|
5
|
-
import * as t from "@babel/types";
|
|
6
|
-
import { NameGen } from "../utils/NameGen";
|
|
7
|
-
import { chance, getRandomInteger } from "../utils/random-utils";
|
|
8
|
-
import { Binding, Visitor } from "@babel/traverse";
|
|
9
|
-
import { computeProbabilityMap } from "../probability";
|
|
10
|
-
|
|
11
|
-
function isSafeForOutlining(path: NodePath): {
|
|
12
|
-
isSafe: boolean;
|
|
13
|
-
bindings?: Binding[];
|
|
14
|
-
} {
|
|
15
|
-
if (path.isIdentifier() || path.isLiteral()) return { isSafe: false };
|
|
16
|
-
|
|
17
|
-
// Skip direct invocations ('this' will be different)
|
|
18
|
-
if (path.key === "callee" && path.parentPath.isCallExpression()) {
|
|
19
|
-
return { isSafe: false };
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// Skip typeof and delete expressions (identifier behavior is different)
|
|
23
|
-
if (path.key === "argument" && path.parentPath.isUnaryExpression()) {
|
|
24
|
-
return { isSafe: false };
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
if (
|
|
28
|
-
path.isReturnStatement() ||
|
|
29
|
-
path.isYieldExpression() ||
|
|
30
|
-
path.isAwaitExpression() ||
|
|
31
|
-
path.isContinueStatement() ||
|
|
32
|
-
path.isBreakStatement() ||
|
|
33
|
-
path.isThrowStatement() ||
|
|
34
|
-
path.isDebuggerStatement() ||
|
|
35
|
-
path.isImportDeclaration() ||
|
|
36
|
-
path.isExportDeclaration()
|
|
37
|
-
) {
|
|
38
|
-
return { isSafe: false };
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
var isSafe = true;
|
|
42
|
-
var bindings: Binding[] = [];
|
|
43
|
-
var fnPath = path.getFunctionParent();
|
|
44
|
-
|
|
45
|
-
var visitor: Visitor = {
|
|
46
|
-
ThisExpression(path) {
|
|
47
|
-
isSafe = false;
|
|
48
|
-
path.stop();
|
|
49
|
-
},
|
|
50
|
-
Identifier(path) {
|
|
51
|
-
if (["arguments", "eval"].includes(path.node.name)) {
|
|
52
|
-
isSafe = false;
|
|
53
|
-
path.stop();
|
|
54
|
-
}
|
|
55
|
-
},
|
|
56
|
-
BindingIdentifier(path) {
|
|
57
|
-
var binding = path.scope.getBinding(path.node.name);
|
|
58
|
-
if (binding) {
|
|
59
|
-
bindings.push(binding);
|
|
60
|
-
}
|
|
61
|
-
},
|
|
62
|
-
// Function flow guard
|
|
63
|
-
"ReturnStatement|YieldExpression|AwaitExpression"(path) {
|
|
64
|
-
if (path.getFunctionParent() === fnPath) {
|
|
65
|
-
isSafe = false;
|
|
66
|
-
path.stop();
|
|
67
|
-
}
|
|
68
|
-
},
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
// Exclude 'ThisExpression' and semantic 'Identifier' nodes
|
|
72
|
-
if (visitor[path.type]) return { isSafe: false };
|
|
73
|
-
|
|
74
|
-
path.traverse(visitor);
|
|
75
|
-
|
|
76
|
-
return { isSafe, bindings };
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export default ({ Plugin }: PluginArg): PluginObject => {
|
|
80
|
-
const me = Plugin(Order.FunctionOutlining, {
|
|
81
|
-
changeData: {
|
|
82
|
-
functionsMade: 0,
|
|
83
|
-
},
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
var changesMade = 0;
|
|
87
|
-
|
|
88
|
-
function checkProbability() {
|
|
89
|
-
if (!computeProbabilityMap(me.options.functionOutlining)) return false;
|
|
90
|
-
|
|
91
|
-
if (changesMade > 100 && chance(changesMade - 100)) return false;
|
|
92
|
-
|
|
93
|
-
return true;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return {
|
|
97
|
-
visitor: {
|
|
98
|
-
Block: {
|
|
99
|
-
exit(blockPath) {
|
|
100
|
-
if (blockPath.isProgram()) {
|
|
101
|
-
blockPath.scope.crawl();
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (blockPath.find((p) => me.isSkipped(p))) return;
|
|
105
|
-
|
|
106
|
-
if (!checkProbability()) return;
|
|
107
|
-
|
|
108
|
-
// Extract a random number of statements
|
|
109
|
-
|
|
110
|
-
var statements = blockPath.get("body");
|
|
111
|
-
// var startIndex = getRandomInteger(0, statements.length);
|
|
112
|
-
// var endIndex = getRandomInteger(startIndex, statements.length);
|
|
113
|
-
|
|
114
|
-
var startIndex = 0;
|
|
115
|
-
var endIndex = statements.length;
|
|
116
|
-
|
|
117
|
-
var extractedStatements = statements.slice(startIndex, endIndex);
|
|
118
|
-
if (!extractedStatements.length) return;
|
|
119
|
-
|
|
120
|
-
var bindings: Binding[] = [];
|
|
121
|
-
|
|
122
|
-
for (var statement of extractedStatements) {
|
|
123
|
-
// Don't override the control node
|
|
124
|
-
if (me.isSkipped(statement)) return;
|
|
125
|
-
|
|
126
|
-
var result = isSafeForOutlining(statement);
|
|
127
|
-
if (!result.isSafe) {
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
bindings.push(...result.bindings);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const extractedStatementSet = new Set<NodePath>(extractedStatements);
|
|
135
|
-
|
|
136
|
-
for (var binding of bindings) {
|
|
137
|
-
for (var referencePath of binding.referencePaths) {
|
|
138
|
-
var found = referencePath.find((p) =>
|
|
139
|
-
extractedStatementSet.has(p)
|
|
140
|
-
);
|
|
141
|
-
if (!found) {
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
for (var constantViolation of binding.constantViolations) {
|
|
146
|
-
var found = constantViolation.find((p) =>
|
|
147
|
-
extractedStatementSet.has(p)
|
|
148
|
-
);
|
|
149
|
-
if (!found) {
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
changesMade++;
|
|
156
|
-
|
|
157
|
-
var isFirst = true;
|
|
158
|
-
for (var statement of extractedStatements) {
|
|
159
|
-
if (isFirst) {
|
|
160
|
-
isFirst = false;
|
|
161
|
-
var memberExpression = me
|
|
162
|
-
.getControlObject(blockPath)
|
|
163
|
-
.addProperty(
|
|
164
|
-
t.functionExpression(
|
|
165
|
-
null,
|
|
166
|
-
[],
|
|
167
|
-
t.blockStatement(extractedStatements.map((x) => x.node))
|
|
168
|
-
)
|
|
169
|
-
);
|
|
170
|
-
|
|
171
|
-
me.changeData.functionsMade++;
|
|
172
|
-
|
|
173
|
-
var callExpression = t.callExpression(memberExpression, []);
|
|
174
|
-
|
|
175
|
-
statement.replaceWith(callExpression);
|
|
176
|
-
continue;
|
|
177
|
-
}
|
|
178
|
-
statement.remove();
|
|
179
|
-
}
|
|
180
|
-
},
|
|
181
|
-
},
|
|
182
|
-
Expression: {
|
|
183
|
-
exit(path) {
|
|
184
|
-
// Skip assignment left
|
|
185
|
-
if (
|
|
186
|
-
path.find(
|
|
187
|
-
(p) =>
|
|
188
|
-
p.key === "left" &&
|
|
189
|
-
p.parentPath?.type === "AssignmentExpression"
|
|
190
|
-
)
|
|
191
|
-
) {
|
|
192
|
-
return;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
if (!checkProbability()) return;
|
|
196
|
-
|
|
197
|
-
if (path.find((p) => me.isSkipped(p))) return;
|
|
198
|
-
if (!isSafeForOutlining(path).isSafe) return;
|
|
199
|
-
|
|
200
|
-
changesMade++;
|
|
201
|
-
|
|
202
|
-
var blockPath = path.find((p) => p.isBlock()) as NodePath<t.Block>;
|
|
203
|
-
|
|
204
|
-
var memberExpression = me
|
|
205
|
-
.getControlObject(blockPath)
|
|
206
|
-
.addProperty(
|
|
207
|
-
t.functionExpression(
|
|
208
|
-
null,
|
|
209
|
-
[],
|
|
210
|
-
t.blockStatement([t.returnStatement(t.cloneNode(path.node))])
|
|
211
|
-
)
|
|
212
|
-
);
|
|
213
|
-
|
|
214
|
-
me.changeData.functionsMade++;
|
|
215
|
-
|
|
216
|
-
var callExpression = t.callExpression(memberExpression, []);
|
|
217
|
-
|
|
218
|
-
ensureComputedExpression(path);
|
|
219
|
-
path.replaceWith(callExpression);
|
|
220
|
-
me.skip(path);
|
|
221
|
-
},
|
|
222
|
-
},
|
|
223
|
-
},
|
|
224
|
-
};
|
|
225
|
-
};
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
import { NodePath } from "@babel/traverse";
|
|
2
|
-
import * as t from "@babel/types";
|
|
3
|
-
import { PluginInstance } from "../transforms/plugin";
|
|
4
|
-
import { NameGen } from "./NameGen";
|
|
5
|
-
import { prepend } from "./ast-utils";
|
|
6
|
-
import { chance, choice } from "./random-utils";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* A Control Object is an object that is used to store properties that are used in multiple places.
|
|
10
|
-
*/
|
|
11
|
-
export default class ControlObject {
|
|
12
|
-
propertyNames = new Set<string>();
|
|
13
|
-
nameGen: NameGen;
|
|
14
|
-
objectName: string | null = null;
|
|
15
|
-
objectPath: NodePath<t.Declaration> | null = null;
|
|
16
|
-
objectExpression: t.ObjectExpression | null = null;
|
|
17
|
-
|
|
18
|
-
constructor(public me: PluginInstance, public blockPath: NodePath<t.Block>) {
|
|
19
|
-
this.nameGen = new NameGen(me.options.identifierGenerator, {
|
|
20
|
-
avoidReserved: true,
|
|
21
|
-
avoidObjectPrototype: true,
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
createMemberExpression(propertyName: string): t.MemberExpression {
|
|
26
|
-
return t.memberExpression(
|
|
27
|
-
t.identifier(this.objectName),
|
|
28
|
-
t.stringLiteral(propertyName),
|
|
29
|
-
true
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
createPredicate() {
|
|
34
|
-
this.ensureCreated();
|
|
35
|
-
|
|
36
|
-
var propertyName = choice(Array.from(this.propertyNames));
|
|
37
|
-
if (!propertyName || chance(50)) {
|
|
38
|
-
propertyName = this.nameGen.generate();
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return {
|
|
42
|
-
node: t.binaryExpression(
|
|
43
|
-
"in",
|
|
44
|
-
t.stringLiteral(propertyName),
|
|
45
|
-
t.identifier(this.objectName)
|
|
46
|
-
),
|
|
47
|
-
value: this.propertyNames.has(propertyName),
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
createTruePredicate() {
|
|
52
|
-
var { node, value } = this.createPredicate();
|
|
53
|
-
if (value) {
|
|
54
|
-
return node;
|
|
55
|
-
}
|
|
56
|
-
return t.unaryExpression("!", node);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
createFalsePredicate() {
|
|
60
|
-
var { node, value } = this.createPredicate();
|
|
61
|
-
if (!value) {
|
|
62
|
-
return node;
|
|
63
|
-
}
|
|
64
|
-
return t.unaryExpression("!", node);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
private ensureCreated(node?: t.Node) {
|
|
68
|
-
if (!this.objectName) {
|
|
69
|
-
// Object hasn't been created yet
|
|
70
|
-
this.objectName = this.me.getPlaceholder() + "_controlObject";
|
|
71
|
-
|
|
72
|
-
if (node && t.isFunctionExpression(node) && !node.id) {
|
|
73
|
-
// Use function declaration as object
|
|
74
|
-
|
|
75
|
-
let newNode: t.FunctionDeclaration = node as any;
|
|
76
|
-
newNode.type = "FunctionDeclaration";
|
|
77
|
-
newNode.id = t.identifier(this.objectName);
|
|
78
|
-
|
|
79
|
-
let newPath = prepend(
|
|
80
|
-
this.blockPath,
|
|
81
|
-
newNode
|
|
82
|
-
)[0] as NodePath<t.FunctionDeclaration>;
|
|
83
|
-
this.me.skip(newPath);
|
|
84
|
-
|
|
85
|
-
this.objectPath = newPath;
|
|
86
|
-
|
|
87
|
-
return t.identifier(this.objectName);
|
|
88
|
-
} else {
|
|
89
|
-
// Create plain object
|
|
90
|
-
let newPath = prepend(
|
|
91
|
-
this.blockPath,
|
|
92
|
-
t.variableDeclaration("var", [
|
|
93
|
-
t.variableDeclarator(
|
|
94
|
-
t.identifier(this.objectName),
|
|
95
|
-
t.objectExpression([])
|
|
96
|
-
),
|
|
97
|
-
])
|
|
98
|
-
)[0] as NodePath<t.VariableDeclaration>;
|
|
99
|
-
this.me.skip(newPath);
|
|
100
|
-
|
|
101
|
-
this.objectPath = newPath;
|
|
102
|
-
|
|
103
|
-
var objectExpression = newPath.node.declarations[0]
|
|
104
|
-
.init as t.ObjectExpression;
|
|
105
|
-
|
|
106
|
-
this.objectExpression = objectExpression;
|
|
107
|
-
this.me.skip(this.objectExpression);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
addProperty(node: t.Expression) {
|
|
113
|
-
var initialNode = this.ensureCreated(node);
|
|
114
|
-
if (initialNode) return initialNode;
|
|
115
|
-
|
|
116
|
-
const propertyName = this.nameGen.generate();
|
|
117
|
-
this.propertyNames.add(propertyName);
|
|
118
|
-
|
|
119
|
-
// Add an initial property
|
|
120
|
-
if (this.objectExpression) {
|
|
121
|
-
this.objectExpression.properties.push(
|
|
122
|
-
t.objectProperty(t.identifier(propertyName), node)
|
|
123
|
-
);
|
|
124
|
-
} else {
|
|
125
|
-
// Add as assignment expression
|
|
126
|
-
|
|
127
|
-
let assignment = t.assignmentExpression(
|
|
128
|
-
"=",
|
|
129
|
-
this.createMemberExpression(propertyName),
|
|
130
|
-
node
|
|
131
|
-
);
|
|
132
|
-
|
|
133
|
-
var newPath = this.objectPath.insertAfter(
|
|
134
|
-
t.expressionStatement(assignment)
|
|
135
|
-
)[0];
|
|
136
|
-
this.me.skip(newPath);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return this.createMemberExpression(propertyName);
|
|
140
|
-
}
|
|
141
|
-
}
|