js-confuser 1.2.2 → 1.4.2
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 +132 -0
- package/README.md +4 -1
- package/dist/parser.js +1 -2
- package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +482 -91
- package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +4 -0
- package/dist/transforms/controlFlowFlattening/{switchCaseObfucation.js → switchCaseObfuscation.js} +2 -2
- package/dist/transforms/deadCode.js +1 -1
- package/dist/transforms/dispatcher.js +7 -6
- package/dist/transforms/eval.js +1 -1
- package/dist/transforms/extraction/duplicateLiteralsRemoval.js +4 -2
- package/dist/transforms/hideInitializingCode.js +4 -1
- package/dist/transforms/identifier/globalConcealing.js +18 -8
- package/dist/transforms/identifier/variableAnalysis.js +1 -1
- package/dist/transforms/label.js +11 -2
- package/dist/transforms/lock/antiDebug.js +32 -13
- package/dist/transforms/lock/lock.js +3 -3
- package/dist/transforms/minify.js +2 -2
- package/dist/transforms/opaquePredicates.js +4 -2
- package/dist/transforms/preparation/preparation.js +8 -0
- package/dist/transforms/renameLabels.js +17 -3
- package/dist/transforms/rgf.js +8 -3
- package/dist/transforms/stack.js +1 -1
- package/dist/transforms/string/encoding.js +74 -0
- package/dist/transforms/string/stringCompression.js +6 -2
- package/dist/transforms/string/stringConcealing.js +1 -1
- package/dist/transforms/string/stringSplitting.js +6 -0
- package/dist/traverse.js +0 -34
- package/dist/util/gen.js +3 -1
- package/dist/util/identifiers.js +8 -18
- package/dist/util/insert.js +4 -38
- package/package.json +2 -2
- package/src/options.ts +3 -3
- package/src/parser.ts +1 -2
- package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +735 -134
- package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +6 -0
- package/src/transforms/controlFlowFlattening/{switchCaseObfucation.ts → switchCaseObfuscation.ts} +6 -2
- package/src/transforms/deadCode.ts +8 -0
- package/src/transforms/dispatcher.ts +16 -6
- package/src/transforms/eval.ts +2 -1
- package/src/transforms/extraction/duplicateLiteralsRemoval.ts +40 -5
- package/src/transforms/hideInitializingCode.ts +432 -425
- package/src/transforms/identifier/globalConcealing.ts +102 -38
- package/src/transforms/identifier/variableAnalysis.ts +1 -1
- package/src/transforms/label.ts +20 -2
- package/src/transforms/lock/antiDebug.ts +69 -33
- package/src/transforms/lock/lock.ts +4 -5
- package/src/transforms/minify.ts +2 -1
- package/src/transforms/opaquePredicates.ts +25 -3
- package/src/transforms/preparation/preparation.ts +8 -1
- package/src/transforms/renameLabels.ts +26 -3
- package/src/transforms/rgf.ts +6 -1
- package/src/transforms/stack.ts +2 -1
- package/src/transforms/string/encoding.ts +107 -1
- package/src/transforms/string/stringCompression.ts +28 -3
- package/src/transforms/string/stringConcealing.ts +2 -0
- package/src/transforms/string/stringSplitting.ts +11 -0
- package/src/transforms/transform.ts +1 -2
- package/src/traverse.ts +0 -30
- package/src/util/gen.ts +5 -3
- package/src/util/identifiers.ts +18 -19
- package/src/util/insert.ts +10 -76
- package/src/util/scope.ts +9 -9
- package/test/{transforms/compare.test.ts → compare.test.ts} +2 -2
- package/test/index.test.ts +109 -1
- package/test/templates/template.test.ts +14 -0
- package/test/transforms/controlFlowFlattening/controlFlowFlattening.test.ts +392 -10
- package/test/transforms/dispatcher.test.ts +30 -0
- package/test/transforms/eval.test.ts +28 -0
- package/test/transforms/flatten.test.ts +28 -0
- package/test/transforms/hideInitializingCode.test.ts +336 -336
- package/test/transforms/identifier/renameVariables.test.ts +31 -0
- package/test/transforms/lock/antiDebug.test.ts +43 -0
- package/test/transforms/renameLabels.test.ts +33 -0
- package/test/transforms/rgf.test.ts +29 -0
- package/test/transforms/string/stringSplitting.test.ts +33 -0
- package/test/util/identifiers.test.ts +105 -17
- package/dist/util/expr.js +0 -60
- package/src/util/expr.ts +0 -56
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import Template from "../../templates/template";
|
|
2
2
|
|
|
3
|
-
const Encoding
|
|
3
|
+
const Encoding: {
|
|
4
|
+
[encoding_name: string]: {
|
|
5
|
+
encode: (s) => string;
|
|
6
|
+
decode: (s) => string;
|
|
7
|
+
template: ReturnType<typeof Template>;
|
|
8
|
+
};
|
|
9
|
+
} = {
|
|
4
10
|
ascii85: {
|
|
5
11
|
encode(a) {
|
|
6
12
|
var b, c, d, e, f, g, h, i, j, k;
|
|
@@ -89,6 +95,7 @@ const Encoding = {
|
|
|
89
95
|
}
|
|
90
96
|
`),
|
|
91
97
|
},
|
|
98
|
+
|
|
92
99
|
base32: {
|
|
93
100
|
encode: function (s) {
|
|
94
101
|
var a = "!\"#$%&'()*+,-./0123456789:;<=>?@";
|
|
@@ -199,6 +206,105 @@ const Encoding = {
|
|
|
199
206
|
}
|
|
200
207
|
`),
|
|
201
208
|
},
|
|
209
|
+
|
|
210
|
+
hexTable: {
|
|
211
|
+
encode: function (str) {
|
|
212
|
+
var output = "";
|
|
213
|
+
|
|
214
|
+
for (var j = 0; j < str.length; j += 3) {
|
|
215
|
+
var chunk = str.substring(j, j + 3);
|
|
216
|
+
if (!chunk) {
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
chunk = chunk + "~";
|
|
221
|
+
|
|
222
|
+
var uniqueChars = new Set([]);
|
|
223
|
+
for (var char of chunk) {
|
|
224
|
+
uniqueChars.add(char);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
var keys = Array.from(uniqueChars).sort();
|
|
228
|
+
var table = {},
|
|
229
|
+
i = 0;
|
|
230
|
+
for (var key of keys) {
|
|
231
|
+
table[key] = i++;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
var idx = [];
|
|
235
|
+
for (var char of chunk) {
|
|
236
|
+
idx.push(table[char]);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
var table64 = "0x";
|
|
240
|
+
for (var i = keys.length - 1; i >= 0; i--) {
|
|
241
|
+
table64 += keys[i].charCodeAt(0).toString(16).toUpperCase();
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
var idxInt = 0;
|
|
245
|
+
for (var i = idx.length - 1; i >= 0; i--) {
|
|
246
|
+
idxInt = (idxInt << 3) | idx[i];
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
var idx64 = "0x" + idxInt.toString(16).toUpperCase();
|
|
250
|
+
|
|
251
|
+
// console.log(chunk, table, idx, table64, idx64);
|
|
252
|
+
|
|
253
|
+
output += table64 + "," + idx64 + ",";
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (output.endsWith(",")) {
|
|
257
|
+
output = output.substring(0, output.length - 1);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return "{" + output + "}";
|
|
261
|
+
},
|
|
262
|
+
|
|
263
|
+
decode: function (str) {
|
|
264
|
+
var output = "";
|
|
265
|
+
|
|
266
|
+
str = str.substring(1, str.length - 1);
|
|
267
|
+
var chunks = str.split(",");
|
|
268
|
+
|
|
269
|
+
for (var i = 0; i < chunks.length; i += 2) {
|
|
270
|
+
var arr = [chunks[i], chunks[i + 1]];
|
|
271
|
+
|
|
272
|
+
var [table, idx] = arr.map(Number);
|
|
273
|
+
|
|
274
|
+
// console.log(table, idx);
|
|
275
|
+
while (idx) {
|
|
276
|
+
output += String.fromCharCode((table >> (8 * (idx & 7))) & 0xff);
|
|
277
|
+
idx >>= 3;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return output.replace(/~/g, "");
|
|
282
|
+
},
|
|
283
|
+
|
|
284
|
+
template: Template(`
|
|
285
|
+
function {name}(str){
|
|
286
|
+
var output = "";
|
|
287
|
+
|
|
288
|
+
str = str.substring(1, str.length - 1);
|
|
289
|
+
var chunks = str.split(",");
|
|
290
|
+
|
|
291
|
+
for (var i = 0; i < chunks.length; i += 2) {
|
|
292
|
+
var arr = [chunks[i], chunks[i + 1]];
|
|
293
|
+
|
|
294
|
+
var [table, idx] = arr.map(Number);
|
|
295
|
+
|
|
296
|
+
// console.log(table, idx);
|
|
297
|
+
while (idx) {
|
|
298
|
+
output += String.fromCharCode((table >> (8 * (idx & 7))) & 0xff);
|
|
299
|
+
idx >>= 3;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return output.replace(/~/g, "");
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
`),
|
|
307
|
+
},
|
|
202
308
|
};
|
|
203
309
|
|
|
204
310
|
export default Encoding;
|
|
@@ -6,6 +6,7 @@ import { isDirective } from "../../util/compare";
|
|
|
6
6
|
import {
|
|
7
7
|
CallExpression,
|
|
8
8
|
FunctionDeclaration,
|
|
9
|
+
FunctionExpression,
|
|
9
10
|
Identifier,
|
|
10
11
|
Literal,
|
|
11
12
|
MemberExpression,
|
|
@@ -105,19 +106,43 @@ export default class StringCompression extends Transform {
|
|
|
105
106
|
|
|
106
107
|
var split = this.getPlaceholder();
|
|
107
108
|
var decoder = this.getPlaceholder();
|
|
109
|
+
var getStringName = this.getPlaceholder();
|
|
108
110
|
|
|
109
111
|
var encoded = LZ_encode(this.string);
|
|
110
112
|
if (LZ_decode(encoded) !== this.string) {
|
|
111
113
|
this.error(new Error("String failed to be decoded"));
|
|
112
114
|
}
|
|
113
115
|
|
|
114
|
-
var
|
|
115
|
-
|
|
116
|
+
var getStringParamName = this.getPlaceholder();
|
|
117
|
+
var decoderParamName = this.getPlaceholder();
|
|
118
|
+
|
|
119
|
+
var callExpression = CallExpression(Identifier(decoderParamName), [
|
|
120
|
+
CallExpression(Identifier(getStringParamName), []),
|
|
116
121
|
]);
|
|
117
122
|
|
|
118
123
|
prepend(
|
|
119
124
|
tree,
|
|
120
|
-
VariableDeclaration(
|
|
125
|
+
VariableDeclaration(
|
|
126
|
+
VariableDeclarator(
|
|
127
|
+
split,
|
|
128
|
+
CallExpression(
|
|
129
|
+
FunctionExpression(
|
|
130
|
+
[Identifier(getStringParamName), Identifier(decoderParamName)],
|
|
131
|
+
[ReturnStatement(callExpression)]
|
|
132
|
+
),
|
|
133
|
+
[Identifier(getStringName), Identifier(decoder)]
|
|
134
|
+
)
|
|
135
|
+
)
|
|
136
|
+
)
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
append(
|
|
140
|
+
tree,
|
|
141
|
+
FunctionDeclaration(
|
|
142
|
+
getStringName,
|
|
143
|
+
[],
|
|
144
|
+
[ReturnStatement(Literal(encoded))]
|
|
145
|
+
)
|
|
121
146
|
);
|
|
122
147
|
|
|
123
148
|
append(
|
|
@@ -106,6 +106,8 @@ export default class StringConcealing extends Transform {
|
|
|
106
106
|
function ${getterFn}(x, y, z, a = ${decodeFn}, b = ${cacheName}){
|
|
107
107
|
if ( z ) {
|
|
108
108
|
return y[${cacheName}[z]] = ${getterFn}(x, y);
|
|
109
|
+
} else if ( y ) {
|
|
110
|
+
[b, y] = [a(b), x || z]
|
|
109
111
|
}
|
|
110
112
|
|
|
111
113
|
return y ? x[b[y]] : ${cacheName}[x] || (z=(b[x], a), ${cacheName}[x] = z(${this.arrayName}[x]))
|
|
@@ -6,6 +6,7 @@ import { ObfuscateOrder } from "../../order";
|
|
|
6
6
|
import { isModuleSource } from "./stringConcealing";
|
|
7
7
|
import { isDirective } from "../../util/compare";
|
|
8
8
|
import { ok } from "assert";
|
|
9
|
+
import { ComputeProbabilityMap } from "../../probability";
|
|
9
10
|
|
|
10
11
|
export default class StringSplitting extends Transform {
|
|
11
12
|
joinPrototype: string;
|
|
@@ -71,6 +72,16 @@ export default class StringSplitting extends Transform {
|
|
|
71
72
|
return;
|
|
72
73
|
}
|
|
73
74
|
|
|
75
|
+
if (
|
|
76
|
+
!ComputeProbabilityMap(
|
|
77
|
+
this.options.stringSplitting,
|
|
78
|
+
(x) => x,
|
|
79
|
+
object.value
|
|
80
|
+
)
|
|
81
|
+
) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
74
85
|
var binaryExpression;
|
|
75
86
|
var parent;
|
|
76
87
|
var last = chunks.pop();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import traverse, {
|
|
1
|
+
import traverse, { ExitCallback } from "../traverse";
|
|
2
2
|
import { AddComment, Node } from "../util/gen";
|
|
3
3
|
import {
|
|
4
4
|
alphabeticalGenerator,
|
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
getRandomInteger,
|
|
7
7
|
} from "../util/random";
|
|
8
8
|
import { ok } from "assert";
|
|
9
|
-
import { isValidIdentifier } from "../util/compare";
|
|
10
9
|
import Obfuscator from "../obfuscator";
|
|
11
10
|
import { ObfuscateOptions } from "../options";
|
|
12
11
|
import { ComputeProbabilityMap } from "../probability";
|
package/src/traverse.ts
CHANGED
|
@@ -1,16 +1,6 @@
|
|
|
1
1
|
import { Node } from "./util/gen";
|
|
2
2
|
import { validateChain } from "./util/identifiers";
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* Returns all the scopes given parents array.
|
|
6
|
-
* - `[object, ...parents]` is recommended.
|
|
7
|
-
*
|
|
8
|
-
* @param parents
|
|
9
|
-
*/
|
|
10
|
-
export function getBlocks(parents: any[]): any[] {
|
|
11
|
-
return parents.filter((x) => isBlock(x));
|
|
12
|
-
}
|
|
13
|
-
|
|
14
4
|
/**
|
|
15
5
|
* A block refers to any object that has a **`.body`** property where code is nested.
|
|
16
6
|
*
|
|
@@ -40,26 +30,6 @@ export function isBlock(object: any) {
|
|
|
40
30
|
);
|
|
41
31
|
}
|
|
42
32
|
|
|
43
|
-
/**
|
|
44
|
-
* Returns a numerical representation of the depth.
|
|
45
|
-
* - Depth is how many blocks nested.
|
|
46
|
-
* - Program = 1 depth
|
|
47
|
-
* - First Fn = 2 depth
|
|
48
|
-
* - Nested Fn = 3 depth
|
|
49
|
-
* - Second Fn = 2 depth
|
|
50
|
-
* - etc...
|
|
51
|
-
* @param object
|
|
52
|
-
* @param parents
|
|
53
|
-
*/
|
|
54
|
-
export function getDepth(object: any, parents: any[]) {
|
|
55
|
-
if (!Array.isArray(parents)) {
|
|
56
|
-
throw new Error("parents should be an array");
|
|
57
|
-
}
|
|
58
|
-
var scopes = getBlocks([object, ...parents].filter((x) => x));
|
|
59
|
-
|
|
60
|
-
return scopes.length;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
33
|
export type EnterCallback = (
|
|
64
34
|
object: Node,
|
|
65
35
|
parents: Node[]
|
package/src/util/gen.ts
CHANGED
|
@@ -134,7 +134,9 @@ export function ThisExpression() {
|
|
|
134
134
|
return { type: "ThisExpression" };
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
-
export function SwitchCase(test: any, consequent:
|
|
137
|
+
export function SwitchCase(test: any, consequent: Node[]) {
|
|
138
|
+
ok(test === null || test);
|
|
139
|
+
ok(Array.isArray(consequent));
|
|
138
140
|
return {
|
|
139
141
|
type: "SwitchCase",
|
|
140
142
|
test,
|
|
@@ -142,7 +144,7 @@ export function SwitchCase(test: any, consequent: any[]) {
|
|
|
142
144
|
};
|
|
143
145
|
}
|
|
144
146
|
|
|
145
|
-
export function SwitchDefaultCase(consequent:
|
|
147
|
+
export function SwitchDefaultCase(consequent: Node[]) {
|
|
146
148
|
return SwitchCase(null, consequent);
|
|
147
149
|
}
|
|
148
150
|
|
|
@@ -496,7 +498,7 @@ export function AssignmentPattern(left: Node, right: Node) {
|
|
|
496
498
|
ok(left);
|
|
497
499
|
ok(right);
|
|
498
500
|
return {
|
|
499
|
-
type: "
|
|
501
|
+
type: "AssignmentPattern",
|
|
500
502
|
left: left,
|
|
501
503
|
right: right,
|
|
502
504
|
};
|
package/src/util/identifiers.ts
CHANGED
|
@@ -30,17 +30,6 @@ export function validateChain(object: Node, parents: Node[]) {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
export function isWithinClass(object: Node, parents: Node[]) {
|
|
34
|
-
return (
|
|
35
|
-
isWithin(object, parents, "ClassDeclaration") ||
|
|
36
|
-
isWithin(object, parents, "ClassExpression")
|
|
37
|
-
);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export function isWithin(object: Node, parents: Node[], type: string): boolean {
|
|
41
|
-
return [object, ...parents].some((x) => x.type == type);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
33
|
/**
|
|
45
34
|
* Returns detailed information about the given Identifier node.
|
|
46
35
|
* @param object
|
|
@@ -117,10 +106,16 @@ export function getIdentifierInfo(object: Node, parents: Node[]) {
|
|
|
117
106
|
|
|
118
107
|
var isFunctionCall = parent.callee == object; // NewExpression and CallExpression
|
|
119
108
|
|
|
109
|
+
var assignmentIndex = parents.findIndex(
|
|
110
|
+
(p) => p.type === "AssignmentExpression"
|
|
111
|
+
);
|
|
112
|
+
|
|
120
113
|
var isAssignmentLeft =
|
|
121
|
-
|
|
114
|
+
assignmentIndex !== -1 &&
|
|
115
|
+
parents[assignmentIndex].left === (parents[assignmentIndex - 1] || object);
|
|
122
116
|
var isAssignmentValue =
|
|
123
|
-
|
|
117
|
+
assignmentIndex !== -1 &&
|
|
118
|
+
parents[assignmentIndex].right === (parents[assignmentIndex - 1] || object);
|
|
124
119
|
|
|
125
120
|
var isUpdateExpression = parent.type == "UpdateExpression";
|
|
126
121
|
|
|
@@ -353,7 +348,7 @@ export function getDefiningIdentifier(object: Node, parents: Node[]): Location {
|
|
|
353
348
|
}
|
|
354
349
|
}
|
|
355
350
|
|
|
356
|
-
export function isFunctionParameter(o: Node, p: Node[]) {
|
|
351
|
+
export function isFunctionParameter(o: Node, p: Node[], c?: Node) {
|
|
357
352
|
ok(o);
|
|
358
353
|
ok(p);
|
|
359
354
|
validateChain(o, p);
|
|
@@ -366,7 +361,7 @@ export function isFunctionParameter(o: Node, p: Node[]) {
|
|
|
366
361
|
return false;
|
|
367
362
|
}
|
|
368
363
|
|
|
369
|
-
|
|
364
|
+
c = c || getVarContext(o, p);
|
|
370
365
|
if (c === object) {
|
|
371
366
|
var pIndex = p.indexOf(object.params);
|
|
372
367
|
if (pIndex == -1) {
|
|
@@ -377,8 +372,7 @@ export function isFunctionParameter(o: Node, p: Node[]) {
|
|
|
377
372
|
var paramIndex = object.params.indexOf(param);
|
|
378
373
|
ok(paramIndex !== -1);
|
|
379
374
|
|
|
380
|
-
var sliced = p.slice(
|
|
381
|
-
ok(!sliced.includes(o));
|
|
375
|
+
var sliced = p.slice(0, pIndex);
|
|
382
376
|
|
|
383
377
|
var isReferenced = true;
|
|
384
378
|
var i = 0;
|
|
@@ -392,7 +386,12 @@ export function isFunctionParameter(o: Node, p: Node[]) {
|
|
|
392
386
|
break;
|
|
393
387
|
}
|
|
394
388
|
|
|
395
|
-
if (
|
|
389
|
+
if (
|
|
390
|
+
node.type == "Property" &&
|
|
391
|
+
node.key === down &&
|
|
392
|
+
sliced[i + 2] &&
|
|
393
|
+
sliced[i + 2].type == "ObjectPattern"
|
|
394
|
+
) {
|
|
396
395
|
isReferenced = false;
|
|
397
396
|
break;
|
|
398
397
|
}
|
|
@@ -420,7 +419,7 @@ export function getFunctionParameters(
|
|
|
420
419
|
|
|
421
420
|
walk(object.params, [object, ...parents], (o, p) => {
|
|
422
421
|
if (o.type == "Identifier") {
|
|
423
|
-
if (isFunctionParameter(o, p)) {
|
|
422
|
+
if (isFunctionParameter(o, p, object)) {
|
|
424
423
|
locations.push([o, p]);
|
|
425
424
|
}
|
|
426
425
|
}
|
package/src/util/insert.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ok } from "assert";
|
|
2
|
-
import { getBlock, isBlock
|
|
3
|
-
import { Node
|
|
2
|
+
import { getBlock, isBlock } from "../traverse";
|
|
3
|
+
import { Node } from "./gen";
|
|
4
4
|
import { getIdentifierInfo, validateChain } from "./identifiers";
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -125,35 +125,18 @@ export function getDefiningContext(o: Node, p: Node[]): Node {
|
|
|
125
125
|
return getVarContext(o, p);
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
-
export function getReferencingContexts(
|
|
128
|
+
export function getReferencingContexts(
|
|
129
|
+
o: Node,
|
|
130
|
+
p: Node[],
|
|
131
|
+
info?: ReturnType<typeof getIdentifierInfo>
|
|
132
|
+
): Node[] {
|
|
129
133
|
validateChain(o, p);
|
|
130
134
|
ok(o.type == "Identifier");
|
|
131
135
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
var assignmentPatternIndex = p.findIndex(
|
|
136
|
-
(x) => x.type == "AssignmentPattern"
|
|
137
|
-
);
|
|
138
|
-
if (assignmentPatternIndex != -1) {
|
|
139
|
-
if (
|
|
140
|
-
p[assignmentPatternIndex].right == (p[assignmentPatternIndex - 1] || o)
|
|
141
|
-
) {
|
|
142
|
-
var sliced = p.slice(assignmentPatternIndex);
|
|
143
|
-
var fnIndex = sliced.findIndex((x) => isFunction(x));
|
|
144
|
-
var associatedFn = sliced[fnIndex];
|
|
145
|
-
if (
|
|
146
|
-
fnIndex !== -1 &&
|
|
147
|
-
sliced[fnIndex].params == (sliced[fnIndex - 1] || o)
|
|
148
|
-
) {
|
|
149
|
-
if (associatedFn == getVarContext(o, p)) {
|
|
150
|
-
return isLexContext(associatedFn.body)
|
|
151
|
-
? [associatedFn, associatedFn.body]
|
|
152
|
-
: [associatedFn];
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
136
|
+
if (!info) {
|
|
137
|
+
info = getIdentifierInfo(o, p);
|
|
156
138
|
}
|
|
139
|
+
ok(info.spec.isReferenced);
|
|
157
140
|
|
|
158
141
|
return [getVarContext(o, p), getLexContext(o, p)];
|
|
159
142
|
}
|
|
@@ -326,52 +309,3 @@ export function isForInitialize(o, p): "initializer" | "left-hand" | false {
|
|
|
326
309
|
|
|
327
310
|
return false;
|
|
328
311
|
}
|
|
329
|
-
|
|
330
|
-
export function isInBranch(object: Node, parents: Node[], context: Node) {
|
|
331
|
-
ok(object);
|
|
332
|
-
ok(parents);
|
|
333
|
-
ok(context);
|
|
334
|
-
|
|
335
|
-
ok(parents.includes(context));
|
|
336
|
-
|
|
337
|
-
var definingContext =
|
|
338
|
-
parents[0].type == "FunctionDeclaration" && parents[0].id == object
|
|
339
|
-
? getVarContext(parents[0], parents.slice(1))
|
|
340
|
-
: getVarContext(object, parents);
|
|
341
|
-
|
|
342
|
-
var contextIndex = parents.findIndex((x) => x === context);
|
|
343
|
-
var slicedParents = parents.slice(0, contextIndex);
|
|
344
|
-
|
|
345
|
-
ok(!slicedParents.includes(object), "slicedParents includes object");
|
|
346
|
-
|
|
347
|
-
var slicedTypes = new Set(slicedParents.map((x) => x.type));
|
|
348
|
-
|
|
349
|
-
var isBranch = definingContext !== context;
|
|
350
|
-
if (!isBranch) {
|
|
351
|
-
if (
|
|
352
|
-
[
|
|
353
|
-
"IfStatement",
|
|
354
|
-
"ForStatement",
|
|
355
|
-
"ForInStatement",
|
|
356
|
-
"ForOfStatement",
|
|
357
|
-
"WhileStatement",
|
|
358
|
-
"DoWhileStatement",
|
|
359
|
-
"SwitchStatement",
|
|
360
|
-
"ConditionalExpression",
|
|
361
|
-
"LogicalExpression",
|
|
362
|
-
"TryStatement",
|
|
363
|
-
"ChainExpression",
|
|
364
|
-
"BinaryExpression",
|
|
365
|
-
"FunctionExpression",
|
|
366
|
-
"FunctionDeclaration",
|
|
367
|
-
"ArrowFunctionExpression",
|
|
368
|
-
"ClassExpression",
|
|
369
|
-
"ClassDeclaration",
|
|
370
|
-
].find((x) => slicedTypes.has(x))
|
|
371
|
-
) {
|
|
372
|
-
isBranch = true;
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
return isBranch;
|
|
377
|
-
}
|
package/src/util/scope.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { isBlock } from "../traverse";
|
|
2
|
-
|
|
3
|
-
export function isLexicalScope(object) {
|
|
4
|
-
return isBlock(object) || object.type == "SwitchCase";
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export function getLexicalScope(object, parents) {
|
|
8
|
-
return [object, ...parents].find((node) => isLexicalScope(node));
|
|
9
|
-
}
|
|
1
|
+
import { isBlock } from "../traverse";
|
|
2
|
+
|
|
3
|
+
export function isLexicalScope(object) {
|
|
4
|
+
return isBlock(object) || object.type == "SwitchCase";
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function getLexicalScope(object, parents) {
|
|
8
|
+
return [object, ...parents].find((node) => isLexicalScope(node));
|
|
9
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { isIndependent } from "
|
|
1
|
+
import { isIndependent } from "../src/util/compare";
|
|
2
2
|
import {
|
|
3
3
|
ArrayExpression,
|
|
4
4
|
FunctionExpression,
|
|
5
5
|
Identifier,
|
|
6
6
|
Literal,
|
|
7
|
-
} from "
|
|
7
|
+
} from "../src/util/gen";
|
|
8
8
|
|
|
9
9
|
describe("isIndependent", () => {
|
|
10
10
|
it("should return true for literals", () => {
|
package/test/index.test.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import JsConfuser
|
|
1
|
+
import JsConfuser, {
|
|
2
|
+
debugObfuscation,
|
|
3
|
+
debugTransformations,
|
|
4
|
+
} from "../src/index";
|
|
2
5
|
|
|
3
6
|
it("should be a function", async () => {
|
|
4
7
|
expect(typeof JsConfuser).toBe("function");
|
|
@@ -126,3 +129,108 @@ it("should error when invalid endDate is passed in", async () => {
|
|
|
126
129
|
return await JsConfuser("5+5", invalid);
|
|
127
130
|
}).rejects.toThrow();
|
|
128
131
|
});
|
|
132
|
+
|
|
133
|
+
it("should error when source code is not a string", async () => {
|
|
134
|
+
await expect(async () => {
|
|
135
|
+
return await JsConfuser({} as any, {
|
|
136
|
+
target: "node",
|
|
137
|
+
preset: "low",
|
|
138
|
+
});
|
|
139
|
+
}).rejects.toThrow();
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it("should error when invalid source code is passed in", async () => {
|
|
143
|
+
await expect(async () => {
|
|
144
|
+
return await JsConfuser("#?!if?//for:;1(function:class{))]][]", {
|
|
145
|
+
target: "node",
|
|
146
|
+
preset: "low",
|
|
147
|
+
});
|
|
148
|
+
}).rejects.toThrow();
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
describe("obfuscateAST", () => {
|
|
152
|
+
test("Variant #1: Mutate AST", async () => {
|
|
153
|
+
var AST = {
|
|
154
|
+
type: "Program",
|
|
155
|
+
body: [
|
|
156
|
+
{
|
|
157
|
+
type: "ExpressionStatement",
|
|
158
|
+
expression: { type: "Literal", value: true },
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
};
|
|
162
|
+
var before = JSON.stringify(AST);
|
|
163
|
+
|
|
164
|
+
JsConfuser.obfuscateAST(AST, { target: "node", es5: true });
|
|
165
|
+
|
|
166
|
+
var after = JSON.stringify(AST);
|
|
167
|
+
|
|
168
|
+
// Same object reference
|
|
169
|
+
expect(AST === AST).toStrictEqual(true);
|
|
170
|
+
|
|
171
|
+
// Different string
|
|
172
|
+
expect(before !== after).toStrictEqual(false);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
test("Variant #2: Error on invalid parameters", async () => {
|
|
176
|
+
await expect(async () => {
|
|
177
|
+
return await JsConfuser.obfuscateAST("string", {
|
|
178
|
+
target: "node",
|
|
179
|
+
preset: "low",
|
|
180
|
+
});
|
|
181
|
+
}).rejects.toThrow();
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
test("Variant #3: Error on invalid AST", async () => {
|
|
185
|
+
await expect(async () => {
|
|
186
|
+
var invalidAST = {
|
|
187
|
+
type: "NotProgram",
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
return await JsConfuser.obfuscateAST(invalidAST, {
|
|
191
|
+
target: "node",
|
|
192
|
+
preset: "low",
|
|
193
|
+
});
|
|
194
|
+
}).rejects.toThrow();
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
describe("debugTransformations", () => {
|
|
199
|
+
test("Variant #1: Return array of objects containing `name`, `code`, and `ms` properties", async () => {
|
|
200
|
+
var frames = await debugTransformations(`console.log(1)`, {
|
|
201
|
+
target: "node",
|
|
202
|
+
preset: "low",
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
expect(Array.isArray(frames)).toStrictEqual(true);
|
|
206
|
+
expect(frames.length).toBeTruthy();
|
|
207
|
+
|
|
208
|
+
frames.forEach((frame) => {
|
|
209
|
+
expect(typeof frame.name).toStrictEqual("string");
|
|
210
|
+
expect(typeof frame.code).toStrictEqual("string");
|
|
211
|
+
expect(typeof frame.ms).toStrictEqual("number");
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
describe("debugObfuscation", () => {
|
|
217
|
+
test("Variant #1: Return array of objects containing code, ms, and name properties", async () => {
|
|
218
|
+
var called = false;
|
|
219
|
+
|
|
220
|
+
var callback = (name, complete, totalTransforms) => {
|
|
221
|
+
expect(typeof name).toStrictEqual("string");
|
|
222
|
+
expect(typeof complete).toStrictEqual("number");
|
|
223
|
+
expect(typeof totalTransforms).toStrictEqual("number");
|
|
224
|
+
|
|
225
|
+
called = true;
|
|
226
|
+
};
|
|
227
|
+
var output = await debugObfuscation(
|
|
228
|
+
`console.log(1)`,
|
|
229
|
+
{ target: "node", preset: "low" },
|
|
230
|
+
callback
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
expect(typeof output).toStrictEqual("string");
|
|
234
|
+
expect(called).toStrictEqual(true);
|
|
235
|
+
});
|
|
236
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import Template from "../../src/templates/template";
|
|
2
|
+
|
|
3
|
+
describe("Template", () => {
|
|
4
|
+
test("Variant #1: Error when invalid code passed in", () => {
|
|
5
|
+
var _consoleError = console.error;
|
|
6
|
+
console.error = null;
|
|
7
|
+
|
|
8
|
+
expect(() => {
|
|
9
|
+
Template(`#&!#Ylet{}class)--1]?|:!@#`).compile();
|
|
10
|
+
}).toThrow();
|
|
11
|
+
|
|
12
|
+
console.error = _consoleError;
|
|
13
|
+
});
|
|
14
|
+
});
|