@dacely/toildefender 0.1.4 → 0.1.6
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/README.md +71 -48
- package/docs/all-modes-output.demo.js +603 -545
- package/esutils.js +11 -1
- package/obfuscator.js +194 -23
- package/package.json +3 -26
- package/processors/deadCode.js +5 -1
- package/processors/flattener.js +56 -32
- package/processors/identifiers.js +9 -15
- package/processors/methods.js +109 -7
- package/processors/normalizer.js +977 -26
- package/processors/numericVm.js +46 -4
- package/processors/scopes.js +25 -0
- package/processors/uglifier.js +199 -2
- package/processors/variables.js +86 -2
- package/traverser.js +8 -2
package/processors/numericVm.js
CHANGED
|
@@ -213,6 +213,15 @@ function veilmark$numericVmRun(program, base, tokenCount, seed, tag, constants,
|
|
|
213
213
|
return value;
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
+
function readConstant(index) {
|
|
217
|
+
var cell = constants[index];
|
|
218
|
+
if (cell && cell[0] === 0 && typeof cell[1] === "function") {
|
|
219
|
+
cell[1] = cell[1]();
|
|
220
|
+
cell[0] = 1;
|
|
221
|
+
}
|
|
222
|
+
return cell && cell[0] === 1 ? cell[1] : cell;
|
|
223
|
+
}
|
|
224
|
+
|
|
216
225
|
function read() {
|
|
217
226
|
if (ip < 0 || ip >= tokenCount) throw new Error("invalid virtual opcode");
|
|
218
227
|
var value = decodeAt(ip);
|
|
@@ -254,7 +263,7 @@ function veilmark$numericVmRun(program, base, tokenCount, seed, tag, constants,
|
|
|
254
263
|
if (op === ops[3]) { push(true); continue; }
|
|
255
264
|
if (op === ops[4]) { push(false); continue; }
|
|
256
265
|
if (op === ops[5]) { push(readUnsigned()); continue; }
|
|
257
|
-
if (op === ops[6]) { push(
|
|
266
|
+
if (op === ops[6]) { push(readConstant(readUnsigned())); continue; }
|
|
258
267
|
if (op === ops[7]) { push(frameArgs[readUnsigned()]); continue; }
|
|
259
268
|
if (op === ops[8]) { push(loadLocal(readUnsigned())); continue; }
|
|
260
269
|
if (op === ops[9]) { storeLocal(readUnsigned(), pop()); continue; }
|
|
@@ -281,7 +290,7 @@ function veilmark$numericVmRun(program, base, tokenCount, seed, tag, constants,
|
|
|
281
290
|
if (op === ops[30]) { var jf = readSigned(); if (!pop()) ip += jf; continue; }
|
|
282
291
|
if (op === ops[31]) { var jt = readSigned(); if (pop()) ip += jt; continue; }
|
|
283
292
|
if (op === ops[32]) { readUnsigned(); var argc = readUnsigned(); var ca = popArgs(argc); var fn = pop(); push(fn.apply(undefined, ca)); continue; }
|
|
284
|
-
if (op === ops[33]) { readUnsigned(); var largc = readUnsigned(); var la = popArgs(largc); var lfn =
|
|
293
|
+
if (op === ops[33]) { readUnsigned(); var largc = readUnsigned(); var la = popArgs(largc); var lfn = readConstant(readUnsigned()); push(lfn.apply(undefined, la)); continue; }
|
|
285
294
|
if (op === ops[34]) { var gpKey = pop(); var gpObj = pop(); push(gpObj[gpKey]); continue; }
|
|
286
295
|
if (op === ops[35]) { var spValue = pop(); var spKey = pop(); var spObj = pop(); spObj[spKey] = spValue; push(spValue); continue; }
|
|
287
296
|
if (op === ops[36]) { var ac = readUnsigned(); var arr = new Array(ac); var ai = ac; while (ai > 0) { ai -= 1; arr[ai] = pop(); } push(arr); continue; }
|
|
@@ -292,6 +301,8 @@ function veilmark$numericVmRun(program, base, tokenCount, seed, tag, constants,
|
|
|
292
301
|
if (op === ops[41]) { push(argsLike); continue; }
|
|
293
302
|
if (op === ops[42]) { push(typeof pop()); continue; }
|
|
294
303
|
if (op === ops[43]) { var mc = readUnsigned(); var ma = popArgs(mc); var mk = pop(); var mo = pop(); push(mo[mk].apply(mo, ma)); continue; }
|
|
304
|
+
if (op === ops[44]) { var cgpKey = readConstant(readUnsigned()); var cgpObj = pop(); push(cgpObj[cgpKey]); continue; }
|
|
305
|
+
if (op === ops[45]) { storeLocal(readUnsigned(), pop()); continue; }
|
|
295
306
|
throw new Error("invalid virtual opcode");
|
|
296
307
|
}
|
|
297
308
|
}
|
|
@@ -304,7 +315,7 @@ var OP_NAMES = [
|
|
|
304
315
|
"STRICT_EQ", "STRICT_NEQ", "LT", "LTE", "GT", "GTE", "JMP", "JMP_FALSE",
|
|
305
316
|
"JMP_TRUE", "CALL_EXT", "CALL_LOCAL", "GET_PROP", "SET_PROP", "MAKE_ARRAY",
|
|
306
317
|
"MAKE_OBJECT", "RETURN", "THROW", "PUSH_THIS", "PUSH_ARGUMENTS", "TYPEOF",
|
|
307
|
-
"CALL_METHOD"
|
|
318
|
+
"CALL_METHOD", "GET_CONST_PROP", "STORE_LOCAL_POP"
|
|
308
319
|
];
|
|
309
320
|
|
|
310
321
|
var BASES = [257, 263, 269, 521, 1031, 4099, 65537];
|
|
@@ -318,6 +329,7 @@ function unary(operator, argument) { return { type: "UnaryExpression", operator:
|
|
|
318
329
|
function member(object, property) { return { type: "MemberExpression", object: object, property: property, computed: true }; }
|
|
319
330
|
function arrayExpression(values) { return { type: "ArrayExpression", elements: values }; }
|
|
320
331
|
function returnStatement(argument) { return { type: "ReturnStatement", argument: argument }; }
|
|
332
|
+
function functionExpression(body) { return { type: "FunctionExpression", id: null, params: [], body: { type: "BlockStatement", body: body }, generator: false, expression: false, async: false }; }
|
|
321
333
|
function functionName(node) { return node.id && node.id.name ? node.id.name : ""; }
|
|
322
334
|
|
|
323
335
|
function hashSeed(seed) {
|
|
@@ -833,6 +845,29 @@ Compiler.prototype.instructionSize = function (instr, positions) {
|
|
|
833
845
|
}
|
|
834
846
|
return size;
|
|
835
847
|
};
|
|
848
|
+
Compiler.prototype.isInstruction = function (instr, op) {
|
|
849
|
+
return instr && !instr.label && instr.op === op;
|
|
850
|
+
};
|
|
851
|
+
Compiler.prototype.fuseSuperinstructions = function () {
|
|
852
|
+
var out = [];
|
|
853
|
+
for (var i = 0; i < this.instructions.length; i += 1) {
|
|
854
|
+
var one = this.instructions[i];
|
|
855
|
+
var two = this.instructions[i + 1];
|
|
856
|
+
var three = this.instructions[i + 2];
|
|
857
|
+
if (this.isInstruction(one, "PUSH_CONST") && this.isInstruction(two, "GET_PROP")) {
|
|
858
|
+
out.push({ op: "GET_CONST_PROP", args: [one.args[0]] });
|
|
859
|
+
i += 1;
|
|
860
|
+
continue;
|
|
861
|
+
}
|
|
862
|
+
if (this.isInstruction(one, "DUP") && this.isInstruction(two, "STORE_LOCAL") && this.isInstruction(three, "POP")) {
|
|
863
|
+
out.push({ op: "STORE_LOCAL_POP", args: [two.args[0]] });
|
|
864
|
+
i += 2;
|
|
865
|
+
continue;
|
|
866
|
+
}
|
|
867
|
+
out.push(one);
|
|
868
|
+
}
|
|
869
|
+
this.instructions = out;
|
|
870
|
+
};
|
|
836
871
|
Compiler.prototype.assemble = function () {
|
|
837
872
|
var positions = new Map();
|
|
838
873
|
var stable = false;
|
|
@@ -896,14 +931,21 @@ Compiler.prototype.constantExpression = function (constant) {
|
|
|
896
931
|
if (constant.kind === "undefined") return { type: "UnaryExpression", operator: "void", prefix: true, argument: literal(0) };
|
|
897
932
|
throw new Error("unsupported constant " + constant.kind);
|
|
898
933
|
};
|
|
934
|
+
Compiler.prototype.constantCellExpression = function (constant) {
|
|
935
|
+
return arrayExpression([
|
|
936
|
+
literal(0),
|
|
937
|
+
functionExpression([ returnStatement(this.constantExpression(constant)) ])
|
|
938
|
+
]);
|
|
939
|
+
};
|
|
899
940
|
Compiler.prototype.finish = function () {
|
|
941
|
+
this.fuseSuperinstructions();
|
|
900
942
|
var tokens = this.assemble();
|
|
901
943
|
var encrypted = encryptedStream(tokens, this.dialect.base, this.dialect.seed);
|
|
902
944
|
var opValues = OP_NAMES.map(name => this.dialect.opcodes[name]);
|
|
903
945
|
var record = {
|
|
904
946
|
base: this.dialect.base,
|
|
905
947
|
blob: packTokens(encrypted.encrypted, this.dialect.base),
|
|
906
|
-
constants: this.constants.map(this.
|
|
948
|
+
constants: this.constants.map(this.constantCellExpression.bind(this)),
|
|
907
949
|
opValues: opValues.map(literal),
|
|
908
950
|
seed: this.dialect.seed,
|
|
909
951
|
tag: encrypted.tag,
|
package/processors/scopes.js
CHANGED
|
@@ -9,6 +9,21 @@ var ESUtils = require("../esutils");
|
|
|
9
9
|
var traverser = require("../traverser");
|
|
10
10
|
var utils = require("../utils");
|
|
11
11
|
|
|
12
|
+
function isClassMethodFunction(stack) {
|
|
13
|
+
return stack.some(frame => frame.node.type == "MethodDefinition" || frame.node.type == "ClassBody");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function isClassMethodScope(scope) {
|
|
17
|
+
var node = scope && scope.block;
|
|
18
|
+
while (node) {
|
|
19
|
+
if (node.type == "MethodDefinition" || node.type == "ClassBody") {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
node = node.veilmark$parent;
|
|
23
|
+
}
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
|
|
12
27
|
module.exports = class Scopes {
|
|
13
28
|
|
|
14
29
|
constructor (logger) {
|
|
@@ -33,6 +48,9 @@ module.exports = class Scopes {
|
|
|
33
48
|
var scopes = scopeManager.acquireAll(ast);
|
|
34
49
|
var rngAlpha = new utils.UniqueRandomAlpha(3);
|
|
35
50
|
scopeManager.scopes.forEach(scope => {
|
|
51
|
+
if (!this.esutils.canInsertIntoScope(scope) || isClassMethodScope(scope)) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
36
54
|
var scopeVarName = `$$scope$${rngAlpha.get()}`;
|
|
37
55
|
|
|
38
56
|
var counter = 0;
|
|
@@ -132,6 +150,9 @@ module.exports = class Scopes {
|
|
|
132
150
|
});
|
|
133
151
|
});
|
|
134
152
|
} else if (def.type == "FunctionName") {
|
|
153
|
+
if (def.node.type == "FunctionExpression") {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
135
156
|
variable.references.forEach(reference => {
|
|
136
157
|
this.esutils.replaceNode(scope.block, reference.identifier, {
|
|
137
158
|
type: "CallExpression",
|
|
@@ -150,6 +171,10 @@ module.exports = class Scopes {
|
|
|
150
171
|
if (scope.block == node) {
|
|
151
172
|
return node;
|
|
152
173
|
}
|
|
174
|
+
|
|
175
|
+
if (isClassMethodFunction(stack)) {
|
|
176
|
+
return node;
|
|
177
|
+
}
|
|
153
178
|
|
|
154
179
|
if (node.type.indexOf("Function") == 0) {
|
|
155
180
|
node.params.unshift({
|
package/processors/uglifier.js
CHANGED
|
@@ -3,8 +3,202 @@
|
|
|
3
3
|
var assert = require("assert");
|
|
4
4
|
|
|
5
5
|
var esshorten = require("esshorten");
|
|
6
|
+
var escope = require("escope");
|
|
6
7
|
|
|
7
8
|
var estest = require("../estest");
|
|
9
|
+
var traverser = require("../traverser");
|
|
10
|
+
|
|
11
|
+
var RESERVED_WORDS = new Set([
|
|
12
|
+
"await",
|
|
13
|
+
"break",
|
|
14
|
+
"case",
|
|
15
|
+
"catch",
|
|
16
|
+
"class",
|
|
17
|
+
"const",
|
|
18
|
+
"continue",
|
|
19
|
+
"debugger",
|
|
20
|
+
"default",
|
|
21
|
+
"delete",
|
|
22
|
+
"do",
|
|
23
|
+
"else",
|
|
24
|
+
"enum",
|
|
25
|
+
"export",
|
|
26
|
+
"extends",
|
|
27
|
+
"false",
|
|
28
|
+
"finally",
|
|
29
|
+
"for",
|
|
30
|
+
"function",
|
|
31
|
+
"if",
|
|
32
|
+
"import",
|
|
33
|
+
"in",
|
|
34
|
+
"instanceof",
|
|
35
|
+
"new",
|
|
36
|
+
"null",
|
|
37
|
+
"return",
|
|
38
|
+
"super",
|
|
39
|
+
"switch",
|
|
40
|
+
"this",
|
|
41
|
+
"throw",
|
|
42
|
+
"true",
|
|
43
|
+
"try",
|
|
44
|
+
"typeof",
|
|
45
|
+
"var",
|
|
46
|
+
"void",
|
|
47
|
+
"while",
|
|
48
|
+
"with",
|
|
49
|
+
"yield",
|
|
50
|
+
"arguments",
|
|
51
|
+
"undefined"
|
|
52
|
+
]);
|
|
53
|
+
|
|
54
|
+
var FIRST_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$";
|
|
55
|
+
var REST_CHARS = FIRST_CHARS + "0123456789";
|
|
56
|
+
|
|
57
|
+
function containsModernBindings(ast) {
|
|
58
|
+
var found = false;
|
|
59
|
+
traverser.traverseEx(ast, [], function (node) {
|
|
60
|
+
if (
|
|
61
|
+
(node.type == "VariableDeclaration" && node.kind != "var")
|
|
62
|
+
|| node.type == "ClassDeclaration"
|
|
63
|
+
|| node.type == "ClassExpression"
|
|
64
|
+
) {
|
|
65
|
+
found = true;
|
|
66
|
+
this.abort();
|
|
67
|
+
}
|
|
68
|
+
return node;
|
|
69
|
+
});
|
|
70
|
+
return found;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function shortName(index) {
|
|
74
|
+
var name = FIRST_CHARS[index % FIRST_CHARS.length];
|
|
75
|
+
index = Math.floor(index / FIRST_CHARS.length);
|
|
76
|
+
while (index > 0) {
|
|
77
|
+
index -= 1;
|
|
78
|
+
name += REST_CHARS[index % REST_CHARS.length];
|
|
79
|
+
index = Math.floor(index / REST_CHARS.length);
|
|
80
|
+
}
|
|
81
|
+
return name;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function isRenamableVariable(scope, variable) {
|
|
85
|
+
if (scope.type == "global") {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
if (variable.name == "arguments" || variable.name == "undefined") {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
if (variable.tainted) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
if (!variable.identifiers || variable.identifiers.length == 0) {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
if (variable.defs && variable.defs.some(def => def.type == "ClassName")) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function reserveUnrenamedNames(scopeManager, renamable) {
|
|
104
|
+
var reserved = new Set(RESERVED_WORDS);
|
|
105
|
+
scopeManager.scopes.forEach(scope => {
|
|
106
|
+
scope.variables.forEach(variable => {
|
|
107
|
+
if (!renamable.has(variable)) {
|
|
108
|
+
reserved.add(variable.name);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
scope.through.forEach(reference => {
|
|
112
|
+
if (!reference.resolved) {
|
|
113
|
+
reserved.add(reference.identifier.name);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
return reserved;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function buildParentMap(ast) {
|
|
121
|
+
var parents = new WeakMap();
|
|
122
|
+
traverser.traverse(ast, [], function (node, stack) {
|
|
123
|
+
var parentFrame = stack[1];
|
|
124
|
+
if (parentFrame) {
|
|
125
|
+
parents.set(node, parentFrame.node);
|
|
126
|
+
}
|
|
127
|
+
return node;
|
|
128
|
+
});
|
|
129
|
+
return parents;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function renameIdentifier(identifier, name, parents) {
|
|
133
|
+
var parent = parents.get(identifier);
|
|
134
|
+
if (
|
|
135
|
+
parent
|
|
136
|
+
&& parent.type == "Property"
|
|
137
|
+
&& parent.shorthand === true
|
|
138
|
+
&& (parent.key === identifier || parent.value === identifier)
|
|
139
|
+
) {
|
|
140
|
+
parent.shorthand = false;
|
|
141
|
+
parent.key = {
|
|
142
|
+
type: "Identifier",
|
|
143
|
+
name: identifier.name
|
|
144
|
+
};
|
|
145
|
+
parent.value = {
|
|
146
|
+
type: "Identifier",
|
|
147
|
+
name: name
|
|
148
|
+
};
|
|
149
|
+
parents.set(parent.key, parent);
|
|
150
|
+
parents.set(parent.value, parent);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
identifier.name = name;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function modernMangle(ast) {
|
|
158
|
+
var scopeManager = escope.analyze(ast, {
|
|
159
|
+
ecmaVersion: 6,
|
|
160
|
+
optimistic: true,
|
|
161
|
+
sourceType: "script"
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
var variables = [];
|
|
165
|
+
scopeManager.scopes.forEach(scope => {
|
|
166
|
+
scope.variables.forEach(variable => {
|
|
167
|
+
if (isRenamableVariable(scope, variable)) {
|
|
168
|
+
variables.push({ scope: scope, variable: variable });
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
variables.sort((left, right) => {
|
|
174
|
+
var leftWeight = left.variable.references.length + left.variable.identifiers.length;
|
|
175
|
+
var rightWeight = right.variable.references.length + right.variable.identifiers.length;
|
|
176
|
+
return rightWeight - leftWeight;
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
var renamable = new Set(variables.map(entry => entry.variable));
|
|
180
|
+
var used = reserveUnrenamedNames(scopeManager, renamable);
|
|
181
|
+
var parents = buildParentMap(ast);
|
|
182
|
+
var next = 0;
|
|
183
|
+
|
|
184
|
+
variables.forEach(entry => {
|
|
185
|
+
var name;
|
|
186
|
+
do {
|
|
187
|
+
name = shortName(next);
|
|
188
|
+
next += 1;
|
|
189
|
+
} while (used.has(name) || RESERVED_WORDS.has(name));
|
|
190
|
+
used.add(name);
|
|
191
|
+
|
|
192
|
+
entry.variable.identifiers.forEach(identifier => {
|
|
193
|
+
renameIdentifier(identifier, name, parents);
|
|
194
|
+
});
|
|
195
|
+
entry.variable.references.forEach(reference => {
|
|
196
|
+
renameIdentifier(reference.identifier, name, parents);
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
return ast;
|
|
201
|
+
}
|
|
8
202
|
|
|
9
203
|
module.exports = class Uglifier {
|
|
10
204
|
|
|
@@ -19,8 +213,11 @@ module.exports = class Uglifier {
|
|
|
19
213
|
*/
|
|
20
214
|
uglify (ast) {
|
|
21
215
|
assert.ok(estest.isNode(ast));
|
|
22
|
-
|
|
216
|
+
|
|
217
|
+
if (containsModernBindings(ast)) {
|
|
218
|
+
return modernMangle(ast);
|
|
219
|
+
}
|
|
23
220
|
return esshorten.mangle(ast);
|
|
24
221
|
}
|
|
25
222
|
|
|
26
|
-
};
|
|
223
|
+
};
|
package/processors/variables.js
CHANGED
|
@@ -9,6 +9,74 @@ var ESUtils = require("../esutils");
|
|
|
9
9
|
var traverser = require("../traverser");
|
|
10
10
|
var utils = require("../utils");
|
|
11
11
|
|
|
12
|
+
function isReferenceIdentifier(node, stack) {
|
|
13
|
+
var parentFrame = stack[1];
|
|
14
|
+
if (!parentFrame) {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
var parent = parentFrame.node;
|
|
19
|
+
var key = parentFrame.key;
|
|
20
|
+
|
|
21
|
+
if ((parent.type == "FunctionDeclaration" || parent.type == "FunctionExpression") && (key == "id" || key == "params")) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
if ((parent.type == "ClassDeclaration" || parent.type == "ClassExpression") && key == "id") {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
if (parent.type == "VariableDeclarator" && key == "id") {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
if (parent.type == "CatchClause" && key == "param") {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
if ((parent.type == "MemberExpression" || parent.type == "Property") && key == "property" && parent.computed === false) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
if (parent.type == "Property" && key == "key" && parent.computed === false) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
if ((parent.type == "MethodDefinition" || parent.type == "PropertyDefinition" || parent.type == "FieldDefinition") && key == "key" && parent.computed === false) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
if ((parent.type == "LabeledStatement" || parent.type == "BreakStatement" || parent.type == "ContinueStatement") && key == "label") {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function functionExpressionUsesOwnName(node) {
|
|
50
|
+
assert.equal(node.type, "FunctionExpression");
|
|
51
|
+
|
|
52
|
+
if (!node.id) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
var name = node.id.name;
|
|
57
|
+
var used = false;
|
|
58
|
+
|
|
59
|
+
traverser.traverse(node.body, [], (child, stack) => {
|
|
60
|
+
if (child.type == "Identifier" && child.name == name && isReferenceIdentifier(child, stack)) {
|
|
61
|
+
used = true;
|
|
62
|
+
}
|
|
63
|
+
return child;
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
return used;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function isClassMethodScope(scope) {
|
|
70
|
+
var node = scope && scope.block;
|
|
71
|
+
while (node) {
|
|
72
|
+
if (node.type == "MethodDefinition" || node.type == "ClassBody") {
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
node = node.veilmark$parent;
|
|
76
|
+
}
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
|
|
12
80
|
module.exports = class Variables {
|
|
13
81
|
|
|
14
82
|
constructor (logger) {
|
|
@@ -25,7 +93,7 @@ module.exports = class Variables {
|
|
|
25
93
|
*/
|
|
26
94
|
removeFunctionExpressionIds (ast) {
|
|
27
95
|
return traverser.traverse(ast, [], (node, stack) => {
|
|
28
|
-
if (node.type == "FunctionExpression" && node.id) {
|
|
96
|
+
if (node.type == "FunctionExpression" && node.id && !functionExpressionUsesOwnName(node)) {
|
|
29
97
|
node.id = null;
|
|
30
98
|
}
|
|
31
99
|
return node;
|
|
@@ -46,6 +114,9 @@ module.exports = class Variables {
|
|
|
46
114
|
this.esutils.setParentsRecursive(ast);
|
|
47
115
|
|
|
48
116
|
scopeManager.scopes.forEach(scope => {
|
|
117
|
+
if (!this.esutils.canInsertIntoScope(scope) || isClassMethodScope(scope)) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
49
120
|
scope.variables.forEach(variable => {
|
|
50
121
|
variable.defs.forEach(def => {
|
|
51
122
|
if (def.type == "FunctionName") {
|
|
@@ -68,7 +139,10 @@ module.exports = class Variables {
|
|
|
68
139
|
init: {
|
|
69
140
|
type: "FunctionExpression",
|
|
70
141
|
params: def.node.params,
|
|
71
|
-
body: def.node.body
|
|
142
|
+
body: def.node.body,
|
|
143
|
+
generator: def.node.generator === true,
|
|
144
|
+
expression: def.node.expression === true,
|
|
145
|
+
async: def.node.async === true
|
|
72
146
|
}
|
|
73
147
|
}
|
|
74
148
|
]
|
|
@@ -90,6 +164,9 @@ module.exports = class Variables {
|
|
|
90
164
|
*/
|
|
91
165
|
obfuscateIdentifiers (ast, scopeManager) {
|
|
92
166
|
scopeManager.scopes.forEach(scope => {
|
|
167
|
+
if (isClassMethodScope(scope)) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
93
170
|
if (scope.isStatic()) {
|
|
94
171
|
scope.variables.sort((a, b) => {
|
|
95
172
|
if (a.tainted) {
|
|
@@ -104,6 +181,10 @@ module.exports = class Variables {
|
|
|
104
181
|
for (let variable of scope.variables) {
|
|
105
182
|
var name = "$$var$" + utils.hash(variable) + "$" + variable.name;
|
|
106
183
|
|
|
184
|
+
if (variable.defs.some(def => def.type == "ClassName")) {
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
|
|
107
188
|
if (variable.tainted) {
|
|
108
189
|
continue;
|
|
109
190
|
}
|
|
@@ -155,6 +236,9 @@ module.exports = class Variables {
|
|
|
155
236
|
var rng = new utils.UniqueRandomAlpha(3);
|
|
156
237
|
|
|
157
238
|
scopeManager.scopes.forEach(scope => {
|
|
239
|
+
if (!this.esutils.canInsertIntoScope(scope) || isClassMethodScope(scope)) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
158
242
|
scope.variables.forEach(variable => {
|
|
159
243
|
variable.defs.forEach(def => {
|
|
160
244
|
if (def.type == "Parameter") {
|
package/traverser.js
CHANGED
|
@@ -7,6 +7,12 @@ var estraverse = require("estraverse");
|
|
|
7
7
|
var estest = require("./estest");
|
|
8
8
|
var utils = require("./utils");
|
|
9
9
|
|
|
10
|
+
var VISITOR_KEYS = Object.assign({}, estraverse.VisitorKeys, {
|
|
11
|
+
ChainExpression: [ "expression" ],
|
|
12
|
+
PropertyDefinition: [ "key", "value" ],
|
|
13
|
+
FieldDefinition: [ "key", "value" ]
|
|
14
|
+
});
|
|
15
|
+
|
|
10
16
|
// Depth-first
|
|
11
17
|
exports.traverse = function (node, stack, processor) {
|
|
12
18
|
assert.ok(estest.isNode(node));
|
|
@@ -57,7 +63,7 @@ exports.visitChildren = function (node, processor) {
|
|
|
57
63
|
assert.ok(estest.isNode(node));
|
|
58
64
|
assert.equal(typeof processor, "function");
|
|
59
65
|
|
|
60
|
-
var keys =
|
|
66
|
+
var keys = VISITOR_KEYS[node.type] || [];
|
|
61
67
|
keys.forEach(key => {
|
|
62
68
|
if (Array.isArray(node[key])) {
|
|
63
69
|
node[key] = node[key].map(x => {
|
|
@@ -80,7 +86,7 @@ exports.visitChildrenEx = function (node, processor) {
|
|
|
80
86
|
assert.ok(estest.isNode(node));
|
|
81
87
|
assert.equal(typeof processor, "function");
|
|
82
88
|
|
|
83
|
-
var keys =
|
|
89
|
+
var keys = VISITOR_KEYS[node.type] || [];
|
|
84
90
|
keys.forEach(key => {
|
|
85
91
|
if (Array.isArray(node[key])) {
|
|
86
92
|
let i = node[key].length;
|