@dacely/toildefender 0.1.3 → 0.1.5
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 +86 -57
- package/docs/all-modes-output.demo.js +1016 -670
- 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 +946 -22
- package/processors/numericVm.js +179 -77
- package/processors/scopes.js +25 -0
- package/processors/variables.js +86 -2
- package/traverser.js +8 -2
package/processors/numericVm.js
CHANGED
|
@@ -36,6 +36,21 @@ function veilmark$numericVmPow(a, b) {
|
|
|
36
36
|
return Math.pow(a, b);
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
function veilmark$numericVmDigit(program, baseBig, index, powers) {
|
|
40
|
+
if (powers) {
|
|
41
|
+
while (powers.length <= index) {
|
|
42
|
+
powers[powers.length] = powers[powers.length - 1] * baseBig;
|
|
43
|
+
}
|
|
44
|
+
return Number((program / powers[index]) % baseBig);
|
|
45
|
+
}
|
|
46
|
+
var pow = BigInt(1);
|
|
47
|
+
while (index > 0) {
|
|
48
|
+
pow *= baseBig;
|
|
49
|
+
index -= 1;
|
|
50
|
+
}
|
|
51
|
+
return Number((program / pow) % baseBig);
|
|
52
|
+
}
|
|
53
|
+
|
|
39
54
|
function veilmark$hashMeshMix(current, value) {
|
|
40
55
|
var h = (current ^ value) >>> 0;
|
|
41
56
|
h = Math.imul(h ^ (h >>> 16), 2246822507) >>> 0;
|
|
@@ -87,34 +102,21 @@ function veilmark$hashMeshStream(key, index, base, salt) {
|
|
|
87
102
|
return hash % base;
|
|
88
103
|
}
|
|
89
104
|
|
|
90
|
-
function veilmark$hashMeshUnlock(program, base,
|
|
91
|
-
var
|
|
92
|
-
|
|
93
|
-
var baseBig = BigInt(base);
|
|
94
|
-
var out = BigInt(0);
|
|
95
|
-
var pow = BigInt(1);
|
|
96
|
-
var i = 0;
|
|
97
|
-
while (i < tokenCount) {
|
|
98
|
-
var cipher = Number(program % baseBig);
|
|
99
|
-
program = program / baseBig;
|
|
100
|
-
var plain = (cipher - veilmark$hashMeshStream(key, i, base, salt) + base) % base;
|
|
101
|
-
out += BigInt(plain) * pow;
|
|
102
|
-
pow *= baseBig;
|
|
103
|
-
i += 1;
|
|
104
|
-
}
|
|
105
|
-
return out;
|
|
105
|
+
function veilmark$hashMeshUnlock(program, base, baseBig, index, key, salt, powers) {
|
|
106
|
+
var cipher = veilmark$numericVmDigit(program, baseBig, index, powers);
|
|
107
|
+
return (cipher - veilmark$hashMeshStream(key, index, base, salt) + base) % base;
|
|
106
108
|
}
|
|
107
109
|
|
|
108
110
|
function veilmark$numericVmRun(program, base, tokenCount, seed, tag, constants, argsLike, self, ops, mesh) {
|
|
111
|
+
var baseBig = BigInt(base);
|
|
112
|
+
var digitPowers = [BigInt(1)];
|
|
113
|
+
var meshKey = 0;
|
|
114
|
+
var meshSalt = 0;
|
|
109
115
|
if (mesh) {
|
|
110
|
-
|
|
116
|
+
meshKey = veilmark$hashMeshKey(mesh, base, tokenCount, seed, tag, ops);
|
|
117
|
+
meshSalt = mesh[5] >>> 0;
|
|
111
118
|
}
|
|
112
119
|
|
|
113
|
-
var tokens = [];
|
|
114
|
-
var state = seed >>> 0;
|
|
115
|
-
var seen = seed >>> 0;
|
|
116
|
-
var baseBig = BigInt(base);
|
|
117
|
-
|
|
118
120
|
function inverse(value, modulo) {
|
|
119
121
|
var t = 0, nt = 1;
|
|
120
122
|
var r = modulo, nr = value % modulo;
|
|
@@ -136,28 +138,95 @@ function veilmark$numericVmRun(program, base, tokenCount, seed, tag, constants,
|
|
|
136
138
|
return (mixed ^ (mixed >>> 13)) >>> 0;
|
|
137
139
|
}
|
|
138
140
|
|
|
141
|
+
function encryptedAt(index) {
|
|
142
|
+
if (mesh) return veilmark$hashMeshUnlock(program, base, baseBig, index, meshKey, meshSalt, digitPowers);
|
|
143
|
+
return veilmark$numericVmDigit(program, baseBig, index, digitPowers);
|
|
144
|
+
}
|
|
145
|
+
|
|
139
146
|
var i = 0;
|
|
147
|
+
var seen = seed >>> 0;
|
|
140
148
|
while (i < tokenCount) {
|
|
141
|
-
var encrypted =
|
|
142
|
-
program = program / baseBig;
|
|
143
|
-
var mul = 1 + ((state >>> 5) % (base - 1));
|
|
144
|
-
var add = state % base;
|
|
145
|
-
var plain = (((encrypted - add + base) % base) * inverse(mul, base)) % base;
|
|
146
|
-
tokens.push(plain);
|
|
149
|
+
var encrypted = encryptedAt(i);
|
|
147
150
|
seen = mix(seen, encrypted, i);
|
|
148
|
-
state = mix(state, encrypted, i);
|
|
149
151
|
i += 1;
|
|
150
152
|
}
|
|
151
153
|
|
|
152
154
|
if ((seen >>> 0) !== (tag >>> 0)) throw new Error("invalid numeric vm program");
|
|
153
155
|
|
|
154
|
-
var
|
|
155
|
-
var
|
|
156
|
+
var decodeIndex = 0;
|
|
157
|
+
var decodeState = seed >>> 0;
|
|
158
|
+
|
|
159
|
+
function stateBefore(index) {
|
|
160
|
+
if (index < decodeIndex) {
|
|
161
|
+
decodeIndex = 0;
|
|
162
|
+
decodeState = seed >>> 0;
|
|
163
|
+
}
|
|
164
|
+
while (decodeIndex < index) {
|
|
165
|
+
var skipped = encryptedAt(decodeIndex);
|
|
166
|
+
decodeState = mix(decodeState, skipped, decodeIndex);
|
|
167
|
+
decodeIndex += 1;
|
|
168
|
+
}
|
|
169
|
+
return decodeState;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function decodeAt(index) {
|
|
173
|
+
var state = stateBefore(index);
|
|
174
|
+
var encrypted = encryptedAt(index);
|
|
175
|
+
var mul = 1 + ((state >>> 5) % (base - 1));
|
|
176
|
+
var add = state % base;
|
|
177
|
+
var plain = (((encrypted - add + base) % base) * inverse(mul, base)) % base;
|
|
178
|
+
if (index === decodeIndex) {
|
|
179
|
+
decodeState = mix(state, encrypted, index);
|
|
180
|
+
decodeIndex = index + 1;
|
|
181
|
+
}
|
|
182
|
+
return plain;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
var layout = seed & 1;
|
|
186
|
+
var stack = layout ? null : [];
|
|
187
|
+
var locals = layout ? null : [];
|
|
188
|
+
var cells = layout ? { s: [], l: Object.create(null) } : null;
|
|
156
189
|
var frameArgs = Array.prototype.slice.call(argsLike);
|
|
157
190
|
var ip = 0;
|
|
158
191
|
|
|
192
|
+
function push(value) {
|
|
193
|
+
if (layout) cells.s[cells.s.length] = value;
|
|
194
|
+
else stack.push(value);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function pop() {
|
|
198
|
+
return layout ? cells.s.pop() : stack.pop();
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function peek() {
|
|
202
|
+
var current = layout ? cells.s : stack;
|
|
203
|
+
return current[current.length - 1];
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function loadLocal(slot) {
|
|
207
|
+
return layout ? cells.l["$" + slot] : locals[slot];
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function storeLocal(slot, value) {
|
|
211
|
+
if (layout) cells.l["$" + slot] = value;
|
|
212
|
+
else locals[slot] = value;
|
|
213
|
+
return value;
|
|
214
|
+
}
|
|
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
|
+
|
|
159
225
|
function read() {
|
|
160
|
-
|
|
226
|
+
if (ip < 0 || ip >= tokenCount) throw new Error("invalid virtual opcode");
|
|
227
|
+
var value = decodeAt(ip);
|
|
228
|
+
ip += 1;
|
|
229
|
+
return value;
|
|
161
230
|
}
|
|
162
231
|
|
|
163
232
|
function readUnsigned() {
|
|
@@ -181,7 +250,7 @@ function veilmark$numericVmRun(program, base, tokenCount, seed, tag, constants,
|
|
|
181
250
|
var i = count;
|
|
182
251
|
while (i > 0) {
|
|
183
252
|
i -= 1;
|
|
184
|
-
out[i] =
|
|
253
|
+
out[i] = pop();
|
|
185
254
|
}
|
|
186
255
|
return out;
|
|
187
256
|
}
|
|
@@ -189,49 +258,51 @@ function veilmark$numericVmRun(program, base, tokenCount, seed, tag, constants,
|
|
|
189
258
|
while (true) {
|
|
190
259
|
var op = read();
|
|
191
260
|
if (op === ops[0]) continue;
|
|
192
|
-
if (op === ops[1]) {
|
|
193
|
-
if (op === ops[2]) {
|
|
194
|
-
if (op === ops[3]) {
|
|
195
|
-
if (op === ops[4]) {
|
|
196
|
-
if (op === ops[5]) {
|
|
197
|
-
if (op === ops[6]) {
|
|
198
|
-
if (op === ops[7]) {
|
|
199
|
-
if (op === ops[8]) {
|
|
200
|
-
if (op === ops[9]) {
|
|
201
|
-
if (op === ops[10]) {
|
|
202
|
-
if (op === ops[11]) {
|
|
203
|
-
if (op === ops[12]) { var addB =
|
|
204
|
-
if (op === ops[13]) { var subB =
|
|
205
|
-
if (op === ops[14]) { var mulB =
|
|
206
|
-
if (op === ops[15]) { var divB =
|
|
207
|
-
if (op === ops[16]) { var modB =
|
|
208
|
-
if (op === ops[17]) { var powB =
|
|
209
|
-
if (op === ops[18]) {
|
|
210
|
-
if (op === ops[19]) {
|
|
211
|
-
if (op === ops[20]) {
|
|
212
|
-
if (op === ops[21]) { var eqB =
|
|
213
|
-
if (op === ops[22]) { var neqB =
|
|
214
|
-
if (op === ops[23]) { var seqB =
|
|
215
|
-
if (op === ops[24]) { var sneB =
|
|
216
|
-
if (op === ops[25]) { var ltB =
|
|
217
|
-
if (op === ops[26]) { var lteB =
|
|
218
|
-
if (op === ops[27]) { var gtB =
|
|
219
|
-
if (op === ops[28]) { var gteB =
|
|
261
|
+
if (op === ops[1]) { push(undefined); continue; }
|
|
262
|
+
if (op === ops[2]) { push(null); continue; }
|
|
263
|
+
if (op === ops[3]) { push(true); continue; }
|
|
264
|
+
if (op === ops[4]) { push(false); continue; }
|
|
265
|
+
if (op === ops[5]) { push(readUnsigned()); continue; }
|
|
266
|
+
if (op === ops[6]) { push(readConstant(readUnsigned())); continue; }
|
|
267
|
+
if (op === ops[7]) { push(frameArgs[readUnsigned()]); continue; }
|
|
268
|
+
if (op === ops[8]) { push(loadLocal(readUnsigned())); continue; }
|
|
269
|
+
if (op === ops[9]) { storeLocal(readUnsigned(), pop()); continue; }
|
|
270
|
+
if (op === ops[10]) { push(peek()); continue; }
|
|
271
|
+
if (op === ops[11]) { pop(); continue; }
|
|
272
|
+
if (op === ops[12]) { var addB = pop(); var addA = pop(); push(addA + addB); continue; }
|
|
273
|
+
if (op === ops[13]) { var subB = pop(); var subA = pop(); push(subA - subB); continue; }
|
|
274
|
+
if (op === ops[14]) { var mulB = pop(); var mulA = pop(); push(mulA * mulB); continue; }
|
|
275
|
+
if (op === ops[15]) { var divB = pop(); var divA = pop(); push(divA / divB); continue; }
|
|
276
|
+
if (op === ops[16]) { var modB = pop(); var modA = pop(); push(modA % modB); continue; }
|
|
277
|
+
if (op === ops[17]) { var powB = pop(); var powA = pop(); push(veilmark$numericVmPow(powA, powB)); continue; }
|
|
278
|
+
if (op === ops[18]) { push(-pop()); continue; }
|
|
279
|
+
if (op === ops[19]) { push(!pop()); continue; }
|
|
280
|
+
if (op === ops[20]) { push(~pop()); continue; }
|
|
281
|
+
if (op === ops[21]) { var eqB = pop(); var eqA = pop(); push(eqA == eqB); continue; }
|
|
282
|
+
if (op === ops[22]) { var neqB = pop(); var neqA = pop(); push(neqA != neqB); continue; }
|
|
283
|
+
if (op === ops[23]) { var seqB = pop(); var seqA = pop(); push(seqA === seqB); continue; }
|
|
284
|
+
if (op === ops[24]) { var sneB = pop(); var sneA = pop(); push(sneA !== sneB); continue; }
|
|
285
|
+
if (op === ops[25]) { var ltB = pop(); var ltA = pop(); push(ltA < ltB); continue; }
|
|
286
|
+
if (op === ops[26]) { var lteB = pop(); var lteA = pop(); push(lteA <= lteB); continue; }
|
|
287
|
+
if (op === ops[27]) { var gtB = pop(); var gtA = pop(); push(gtA > gtB); continue; }
|
|
288
|
+
if (op === ops[28]) { var gteB = pop(); var gteA = pop(); push(gteA >= gteB); continue; }
|
|
220
289
|
if (op === ops[29]) { var jmp = readSigned(); ip += jmp; continue; }
|
|
221
|
-
if (op === ops[30]) { var jf = readSigned(); if (!
|
|
222
|
-
if (op === ops[31]) { var jt = readSigned(); if (
|
|
223
|
-
if (op === ops[32]) { readUnsigned(); var argc = readUnsigned(); var ca = popArgs(argc); var fn =
|
|
224
|
-
if (op === ops[33]) { readUnsigned(); var largc = readUnsigned(); var la = popArgs(largc); var lfn =
|
|
225
|
-
if (op === ops[34]) { var gpKey =
|
|
226
|
-
if (op === ops[35]) { var spValue =
|
|
227
|
-
if (op === ops[36]) { var ac = readUnsigned(); var arr = new Array(ac); var ai = ac; while (ai > 0) { ai -= 1; arr[ai] =
|
|
228
|
-
if (op === ops[37]) { var oc = readUnsigned(); var pairs = new Array(oc); var oi = oc; while (oi > 0) { oi -= 1; var ov =
|
|
229
|
-
if (op === ops[38]) return
|
|
230
|
-
if (op === ops[39]) throw
|
|
231
|
-
if (op === ops[40]) {
|
|
232
|
-
if (op === ops[41]) {
|
|
233
|
-
if (op === ops[42]) {
|
|
234
|
-
if (op === ops[43]) { var mc = readUnsigned(); var ma = popArgs(mc); var mk =
|
|
290
|
+
if (op === ops[30]) { var jf = readSigned(); if (!pop()) ip += jf; continue; }
|
|
291
|
+
if (op === ops[31]) { var jt = readSigned(); if (pop()) ip += jt; continue; }
|
|
292
|
+
if (op === ops[32]) { readUnsigned(); var argc = readUnsigned(); var ca = popArgs(argc); var fn = pop(); push(fn.apply(undefined, ca)); continue; }
|
|
293
|
+
if (op === ops[33]) { readUnsigned(); var largc = readUnsigned(); var la = popArgs(largc); var lfn = readConstant(readUnsigned()); push(lfn.apply(undefined, la)); continue; }
|
|
294
|
+
if (op === ops[34]) { var gpKey = pop(); var gpObj = pop(); push(gpObj[gpKey]); continue; }
|
|
295
|
+
if (op === ops[35]) { var spValue = pop(); var spKey = pop(); var spObj = pop(); spObj[spKey] = spValue; push(spValue); continue; }
|
|
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; }
|
|
297
|
+
if (op === ops[37]) { var oc = readUnsigned(); var pairs = new Array(oc); var oi = oc; while (oi > 0) { oi -= 1; var ov = pop(); var ok = pop(); pairs[oi] = [ok, ov]; } var obj = {}; var pi = 0; while (pi < oc) { obj[pairs[pi][0]] = pairs[pi][1]; pi += 1; } push(obj); continue; }
|
|
298
|
+
if (op === ops[38]) return pop();
|
|
299
|
+
if (op === ops[39]) throw pop();
|
|
300
|
+
if (op === ops[40]) { push(self); continue; }
|
|
301
|
+
if (op === ops[41]) { push(argsLike); continue; }
|
|
302
|
+
if (op === ops[42]) { push(typeof pop()); continue; }
|
|
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; }
|
|
235
306
|
throw new Error("invalid virtual opcode");
|
|
236
307
|
}
|
|
237
308
|
}
|
|
@@ -244,7 +315,7 @@ var OP_NAMES = [
|
|
|
244
315
|
"STRICT_EQ", "STRICT_NEQ", "LT", "LTE", "GT", "GTE", "JMP", "JMP_FALSE",
|
|
245
316
|
"JMP_TRUE", "CALL_EXT", "CALL_LOCAL", "GET_PROP", "SET_PROP", "MAKE_ARRAY",
|
|
246
317
|
"MAKE_OBJECT", "RETURN", "THROW", "PUSH_THIS", "PUSH_ARGUMENTS", "TYPEOF",
|
|
247
|
-
"CALL_METHOD"
|
|
318
|
+
"CALL_METHOD", "GET_CONST_PROP", "STORE_LOCAL_POP"
|
|
248
319
|
];
|
|
249
320
|
|
|
250
321
|
var BASES = [257, 263, 269, 521, 1031, 4099, 65537];
|
|
@@ -258,6 +329,7 @@ function unary(operator, argument) { return { type: "UnaryExpression", operator:
|
|
|
258
329
|
function member(object, property) { return { type: "MemberExpression", object: object, property: property, computed: true }; }
|
|
259
330
|
function arrayExpression(values) { return { type: "ArrayExpression", elements: values }; }
|
|
260
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 }; }
|
|
261
333
|
function functionName(node) { return node.id && node.id.name ? node.id.name : ""; }
|
|
262
334
|
|
|
263
335
|
function hashSeed(seed) {
|
|
@@ -773,6 +845,29 @@ Compiler.prototype.instructionSize = function (instr, positions) {
|
|
|
773
845
|
}
|
|
774
846
|
return size;
|
|
775
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
|
+
};
|
|
776
871
|
Compiler.prototype.assemble = function () {
|
|
777
872
|
var positions = new Map();
|
|
778
873
|
var stable = false;
|
|
@@ -836,14 +931,21 @@ Compiler.prototype.constantExpression = function (constant) {
|
|
|
836
931
|
if (constant.kind === "undefined") return { type: "UnaryExpression", operator: "void", prefix: true, argument: literal(0) };
|
|
837
932
|
throw new Error("unsupported constant " + constant.kind);
|
|
838
933
|
};
|
|
934
|
+
Compiler.prototype.constantCellExpression = function (constant) {
|
|
935
|
+
return arrayExpression([
|
|
936
|
+
literal(0),
|
|
937
|
+
functionExpression([ returnStatement(this.constantExpression(constant)) ])
|
|
938
|
+
]);
|
|
939
|
+
};
|
|
839
940
|
Compiler.prototype.finish = function () {
|
|
941
|
+
this.fuseSuperinstructions();
|
|
840
942
|
var tokens = this.assemble();
|
|
841
943
|
var encrypted = encryptedStream(tokens, this.dialect.base, this.dialect.seed);
|
|
842
944
|
var opValues = OP_NAMES.map(name => this.dialect.opcodes[name]);
|
|
843
945
|
var record = {
|
|
844
946
|
base: this.dialect.base,
|
|
845
947
|
blob: packTokens(encrypted.encrypted, this.dialect.base),
|
|
846
|
-
constants: this.constants.map(this.
|
|
948
|
+
constants: this.constants.map(this.constantCellExpression.bind(this)),
|
|
847
949
|
opValues: opValues.map(literal),
|
|
848
950
|
seed: this.dialect.seed,
|
|
849
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/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;
|