js-confuser 1.5.7 → 1.5.9
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 +51 -0
- package/dist/index.js +45 -4
- package/dist/obfuscator.js +10 -5
- package/dist/options.js +6 -7
- package/dist/order.js +3 -3
- package/dist/transforms/antiTooling.js +1 -1
- package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +16 -2
- package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +4 -2
- package/dist/transforms/dispatcher.js +3 -3
- package/dist/transforms/es5/antiClass.js +6 -2
- package/dist/transforms/es5/antiDestructuring.js +1 -1
- package/dist/transforms/eval.js +11 -0
- package/dist/transforms/extraction/duplicateLiteralsRemoval.js +4 -4
- package/dist/transforms/extraction/objectExtraction.js +6 -1
- package/dist/transforms/flatten.js +73 -50
- package/dist/transforms/hexadecimalNumbers.js +34 -9
- package/dist/transforms/identifier/movedDeclarations.js +1 -1
- package/dist/transforms/identifier/nameRecycling.js +8 -2
- package/dist/transforms/identifier/renameVariables.js +9 -0
- package/dist/transforms/lock/antiDebug.js +1 -1
- package/dist/transforms/minify.js +22 -6
- package/dist/transforms/rgf.js +4 -4
- package/dist/transforms/stack.js +1 -1
- package/dist/transforms/string/stringConcealing.js +77 -40
- package/dist/transforms/transform.js +1 -1
- package/dist/traverse.js +0 -8
- package/dist/util/compare.js +2 -2
- package/dist/util/insert.js +20 -6
- package/package.json +2 -2
- package/src/index.ts +57 -19
- package/src/obfuscator.ts +6 -1
- package/src/options.ts +20 -6
- package/src/order.ts +3 -3
- package/src/transforms/antiTooling.ts +1 -1
- package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +16 -1
- package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +14 -2
- package/src/transforms/dispatcher.ts +4 -3
- package/src/transforms/es5/antiClass.ts +10 -1
- package/src/transforms/es5/antiDestructuring.ts +1 -1
- package/src/transforms/eval.ts +18 -0
- package/src/transforms/extraction/duplicateLiteralsRemoval.ts +5 -5
- package/src/transforms/extraction/objectExtraction.ts +12 -5
- package/src/transforms/flatten.ts +181 -128
- package/src/transforms/hexadecimalNumbers.ts +37 -9
- package/src/transforms/identifier/movedDeclarations.ts +1 -1
- package/src/transforms/identifier/nameRecycling.ts +14 -3
- package/src/transforms/identifier/renameVariables.ts +19 -0
- package/src/transforms/lock/antiDebug.ts +1 -1
- package/src/transforms/minify.ts +37 -5
- package/src/transforms/rgf.ts +4 -3
- package/src/transforms/stack.ts +3 -1
- package/src/transforms/string/stringConcealing.ts +120 -56
- package/src/transforms/transform.ts +1 -1
- package/src/traverse.ts +1 -8
- package/src/types.ts +9 -1
- package/src/util/compare.ts +2 -2
- package/src/util/insert.ts +37 -8
- package/test/code/ES6.src.js +14 -0
- package/test/code/NewFeatures.test.ts +19 -0
- package/test/index.test.ts +13 -1
- package/test/transforms/antiTooling.test.ts +30 -0
- package/test/transforms/controlFlowFlattening/controlFlowFlattening.test.ts +58 -0
- package/test/transforms/dispatcher.test.ts +24 -0
- package/test/transforms/es5/antiClass.test.ts +33 -0
- package/test/transforms/eval.test.ts +53 -0
- package/test/transforms/extraction/objectExtraction.test.ts +21 -0
- package/test/transforms/flatten.test.ts +146 -3
- package/test/transforms/identifier/nameRecycling.test.ts +39 -0
- package/test/transforms/identifier/renameVariables.test.ts +64 -0
- package/test/transforms/minify.test.ts +66 -0
- package/test/transforms/rgf.test.ts +56 -0
- package/test/transforms/string/stringConcealing.test.ts +33 -0
- package/test/util/compare.test.ts +23 -1
package/src/transforms/minify.ts
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
AssignmentExpression,
|
|
16
16
|
VariableDeclarator,
|
|
17
17
|
Identifier,
|
|
18
|
+
CallExpression,
|
|
18
19
|
} from "../util/gen";
|
|
19
20
|
import {
|
|
20
21
|
getBlockBody,
|
|
@@ -22,11 +23,14 @@ import {
|
|
|
22
23
|
isForInitialize,
|
|
23
24
|
isLexContext,
|
|
24
25
|
getFunction,
|
|
26
|
+
prepend,
|
|
27
|
+
append,
|
|
25
28
|
} from "../util/insert";
|
|
26
29
|
import { isValidIdentifier, isEquivalent } from "../util/compare";
|
|
27
30
|
import { walk, isBlock } from "../traverse";
|
|
28
31
|
import { ok } from "assert";
|
|
29
32
|
import { isLexicalScope } from "../util/scope";
|
|
33
|
+
import Template from "../templates/template";
|
|
30
34
|
|
|
31
35
|
/**
|
|
32
36
|
* Basic transformations to reduce code size.
|
|
@@ -37,12 +41,13 @@ import { isLexicalScope } from "../util/scope";
|
|
|
37
41
|
* - `x['y']` **->** `x.y`
|
|
38
42
|
*/
|
|
39
43
|
export default class Minify extends Transform {
|
|
40
|
-
|
|
44
|
+
/**
|
|
45
|
+
* A helper function that is introduced preserve function semantics
|
|
46
|
+
*/
|
|
47
|
+
arrowFunctionName: string;
|
|
41
48
|
|
|
42
49
|
constructor(o) {
|
|
43
50
|
super(o, ObfuscateOrder.Minify);
|
|
44
|
-
|
|
45
|
-
this.variables = new Map();
|
|
46
51
|
}
|
|
47
52
|
|
|
48
53
|
match(object: Node, parents: Node[]) {
|
|
@@ -239,17 +244,42 @@ export default class Minify extends Transform {
|
|
|
239
244
|
});
|
|
240
245
|
|
|
241
246
|
if (canTransform) {
|
|
247
|
+
if (!this.arrowFunctionName) {
|
|
248
|
+
this.arrowFunctionName = this.getPlaceholder();
|
|
249
|
+
|
|
250
|
+
append(
|
|
251
|
+
parents[parents.length - 1] || object,
|
|
252
|
+
Template(`
|
|
253
|
+
function ${this.arrowFunctionName}(arrowFn){
|
|
254
|
+
return function(){ return arrowFn(...arguments) }
|
|
255
|
+
}
|
|
256
|
+
`).single()
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const wrap = (object: Node) => {
|
|
261
|
+
return CallExpression(Identifier(this.arrowFunctionName), [
|
|
262
|
+
clone(object),
|
|
263
|
+
]);
|
|
264
|
+
};
|
|
265
|
+
|
|
242
266
|
if (object.type == "FunctionExpression") {
|
|
243
267
|
object.type = "ArrowFunctionExpression";
|
|
268
|
+
|
|
269
|
+
this.replace(object, wrap(clone(object)));
|
|
244
270
|
} else {
|
|
245
271
|
var arrow = { ...clone(object), type: "ArrowFunctionExpression" };
|
|
246
272
|
this.replace(
|
|
247
273
|
object,
|
|
248
|
-
VariableDeclaration(
|
|
274
|
+
VariableDeclaration(
|
|
275
|
+
VariableDeclarator(object.id.name, wrap(arrow))
|
|
276
|
+
)
|
|
249
277
|
);
|
|
250
278
|
|
|
251
279
|
var x = this.transform(arrow, []);
|
|
252
|
-
x
|
|
280
|
+
if (typeof x === "function") {
|
|
281
|
+
x();
|
|
282
|
+
}
|
|
253
283
|
}
|
|
254
284
|
}
|
|
255
285
|
};
|
|
@@ -442,6 +472,8 @@ export default class Minify extends Transform {
|
|
|
442
472
|
}
|
|
443
473
|
|
|
444
474
|
if (
|
|
475
|
+
object.consequent &&
|
|
476
|
+
object.consequent.body &&
|
|
445
477
|
object.consequent.body.length == 1 &&
|
|
446
478
|
object.alternate &&
|
|
447
479
|
object.alternate.body.length == 1
|
package/src/transforms/rgf.ts
CHANGED
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
isFunction,
|
|
32
32
|
prepend,
|
|
33
33
|
getDefiningContext,
|
|
34
|
+
clone,
|
|
34
35
|
} from "../util/insert";
|
|
35
36
|
import { getRandomString } from "../util/random";
|
|
36
37
|
import Transform from "./transform";
|
|
@@ -300,7 +301,8 @@ export default class RGF extends Transform {
|
|
|
300
301
|
[],
|
|
301
302
|
[
|
|
302
303
|
ReturnStatement(
|
|
303
|
-
|
|
304
|
+
// clone() is required!
|
|
305
|
+
CallExpression(clone(memberExpression), [
|
|
304
306
|
Identifier(referenceArray),
|
|
305
307
|
SpreadElement(Identifier("arguments")),
|
|
306
308
|
])
|
|
@@ -328,8 +330,6 @@ export default class RGF extends Transform {
|
|
|
328
330
|
|
|
329
331
|
queue.forEach(([object, parents]) => {
|
|
330
332
|
var name = object?.id?.name;
|
|
331
|
-
var hasName = !!name;
|
|
332
|
-
var params = object.params.map((x) => x.name) || [];
|
|
333
333
|
var signature = referenceSignatures[names.get(name)];
|
|
334
334
|
|
|
335
335
|
var embeddedName = name || this.getPlaceholder();
|
|
@@ -349,6 +349,7 @@ export default class RGF extends Transform {
|
|
|
349
349
|
},
|
|
350
350
|
eval: false,
|
|
351
351
|
hideInitializingCode: false,
|
|
352
|
+
stringEncoding: false,
|
|
352
353
|
});
|
|
353
354
|
var transforms = Object.values(obfuscator.transforms).filter(
|
|
354
355
|
(x) => x.priority > this.priority
|
package/src/transforms/stack.ts
CHANGED
|
@@ -55,7 +55,9 @@ export default class Stack extends Transform {
|
|
|
55
55
|
return () => {
|
|
56
56
|
// Uncaught SyntaxError: Getter must not have any formal parameters.
|
|
57
57
|
// Uncaught SyntaxError: Setter must have exactly one formal parameter
|
|
58
|
-
var propIndex = parents.findIndex(
|
|
58
|
+
var propIndex = parents.findIndex(
|
|
59
|
+
(x) => x.type === "Property" || x.type === "MethodDefinition"
|
|
60
|
+
);
|
|
59
61
|
if (propIndex !== -1) {
|
|
60
62
|
if (parents[propIndex].value === (parents[propIndex - 1] || object)) {
|
|
61
63
|
if (parents[propIndex].kind !== "init" || parents[propIndex].method) {
|
|
@@ -6,22 +6,18 @@ import { isDirective } from "../../util/compare";
|
|
|
6
6
|
import {
|
|
7
7
|
ArrayExpression,
|
|
8
8
|
CallExpression,
|
|
9
|
-
ConditionalExpression,
|
|
10
|
-
FunctionDeclaration,
|
|
11
9
|
FunctionExpression,
|
|
12
10
|
Identifier,
|
|
13
|
-
IfStatement,
|
|
14
11
|
Literal,
|
|
15
12
|
MemberExpression,
|
|
16
13
|
Node,
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
ObjectExpression,
|
|
15
|
+
Property,
|
|
19
16
|
ThisExpression,
|
|
20
|
-
UpdateExpression,
|
|
21
17
|
VariableDeclaration,
|
|
22
18
|
VariableDeclarator,
|
|
23
19
|
} from "../../util/gen";
|
|
24
|
-
import { append,
|
|
20
|
+
import { append, prepend } from "../../util/insert";
|
|
25
21
|
import { choice, getRandomInteger, getRandomString } from "../../util/random";
|
|
26
22
|
import Transform from "../transform";
|
|
27
23
|
import Encoding from "./encoding";
|
|
@@ -65,6 +61,7 @@ export default class StringConcealing extends Transform {
|
|
|
65
61
|
ignore = new Set<string>();
|
|
66
62
|
variablesMade = 1;
|
|
67
63
|
encoding: { [type: string]: string } = Object.create(null);
|
|
64
|
+
gen: ReturnType<Transform["getGenerator"]>;
|
|
68
65
|
|
|
69
66
|
hasAllEncodings: boolean;
|
|
70
67
|
|
|
@@ -75,11 +72,12 @@ export default class StringConcealing extends Transform {
|
|
|
75
72
|
this.index = Object.create(null);
|
|
76
73
|
this.arrayExpression = ArrayExpression([]);
|
|
77
74
|
this.hasAllEncodings = false;
|
|
75
|
+
this.gen = this.getGenerator();
|
|
78
76
|
|
|
79
77
|
// Pad array with useless strings
|
|
80
|
-
var dead = getRandomInteger(
|
|
78
|
+
var dead = getRandomInteger(5, 15);
|
|
81
79
|
for (var i = 0; i < dead; i++) {
|
|
82
|
-
var str = getRandomString(getRandomInteger(
|
|
80
|
+
var str = getRandomString(getRandomInteger(5, 40));
|
|
83
81
|
var fn = this.transform(Literal(str), []);
|
|
84
82
|
if (fn) {
|
|
85
83
|
fn();
|
|
@@ -134,7 +132,7 @@ export default class StringConcealing extends Transform {
|
|
|
134
132
|
VariableDeclarator("a", this.arrayExpression)
|
|
135
133
|
),
|
|
136
134
|
Template(
|
|
137
|
-
`return (${flowIntegrity} ? a
|
|
135
|
+
`return (${flowIntegrity} ? a["pop"]() : ${flowIntegrity}++, a)`
|
|
138
136
|
).single(),
|
|
139
137
|
]
|
|
140
138
|
),
|
|
@@ -159,7 +157,11 @@ export default class StringConcealing extends Transform {
|
|
|
159
157
|
transform(object: Node, parents: Node[]) {
|
|
160
158
|
return () => {
|
|
161
159
|
// Empty strings are discarded
|
|
162
|
-
if (
|
|
160
|
+
if (
|
|
161
|
+
!object.value ||
|
|
162
|
+
this.ignore.has(object.value) ||
|
|
163
|
+
object.value.length == 0
|
|
164
|
+
) {
|
|
163
165
|
return;
|
|
164
166
|
}
|
|
165
167
|
|
|
@@ -188,69 +190,131 @@ export default class StringConcealing extends Transform {
|
|
|
188
190
|
var encoded = encoder.encode(object.value);
|
|
189
191
|
if (encoder.decode(encoded) != object.value) {
|
|
190
192
|
this.ignore.add(object.value);
|
|
191
|
-
this.warn(object.value.slice(0, 100));
|
|
193
|
+
this.warn(type, object.value.slice(0, 100));
|
|
192
194
|
return;
|
|
193
195
|
}
|
|
194
196
|
|
|
195
|
-
|
|
196
|
-
if (
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
index = this.arrayExpression.elements.length - 1;
|
|
201
|
-
this.index[object.value] = [index, fnName];
|
|
197
|
+
var index = -1;
|
|
198
|
+
if (!this.set.has(object.value)) {
|
|
199
|
+
this.arrayExpression.elements.push(Literal(encoded));
|
|
200
|
+
index = this.arrayExpression.elements.length - 1;
|
|
201
|
+
this.index[object.value] = [index, fnName];
|
|
202
202
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
203
|
+
this.set.add(object.value);
|
|
204
|
+
} else {
|
|
205
|
+
[index, fnName] = this.index[object.value];
|
|
206
|
+
ok(typeof index === "number");
|
|
207
|
+
}
|
|
208
208
|
|
|
209
|
-
|
|
209
|
+
ok(index != -1, "index == -1");
|
|
210
210
|
|
|
211
|
-
|
|
211
|
+
var callExpr = CallExpression(Identifier(fnName), [Literal(index)]);
|
|
212
212
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
213
|
+
// use `.apply` to fool automated de-obfuscators
|
|
214
|
+
if (Math.random() > 0.5) {
|
|
215
|
+
callExpr = CallExpression(
|
|
216
|
+
MemberExpression(Identifier(fnName), Identifier("apply"), false),
|
|
217
|
+
[Identifier("undefined"), ArrayExpression([Literal(index)])]
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// use `.call`
|
|
222
|
+
else if (Math.random() > 0.5) {
|
|
223
|
+
callExpr = CallExpression(
|
|
224
|
+
MemberExpression(Identifier(fnName), Identifier("call"), false),
|
|
225
|
+
[Identifier("undefined"), Literal(index)]
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
var referenceType = "call";
|
|
230
|
+
if (parents.length && Math.random() < 0.5 / this.variablesMade) {
|
|
231
|
+
referenceType = "constantReference";
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
var newExpr: Node = callExpr;
|
|
235
|
+
|
|
236
|
+
if (referenceType === "constantReference") {
|
|
237
|
+
// Define the string earlier, reference the name here
|
|
238
|
+
this.variablesMade++;
|
|
220
239
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
);
|
|
240
|
+
var constantReferenceType = choice(["variable", "array", "object"]);
|
|
241
|
+
|
|
242
|
+
var place = choice(parents.filter((node) => isBlock(node)));
|
|
243
|
+
if (!place) {
|
|
244
|
+
this.error(new Error("No lexical block to insert code"));
|
|
227
245
|
}
|
|
228
246
|
|
|
229
|
-
|
|
230
|
-
|
|
247
|
+
switch (constantReferenceType) {
|
|
248
|
+
case "variable":
|
|
249
|
+
var name = this.getPlaceholder();
|
|
250
|
+
|
|
251
|
+
prepend(
|
|
252
|
+
place,
|
|
253
|
+
VariableDeclaration(VariableDeclarator(name, callExpr))
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
newExpr = Identifier(name);
|
|
257
|
+
break;
|
|
258
|
+
case "array":
|
|
259
|
+
if (!place.$stringConcealingArray) {
|
|
260
|
+
place.$stringConcealingArray = ArrayExpression([]);
|
|
261
|
+
place.$stringConcealingArrayName = this.getPlaceholder();
|
|
231
262
|
|
|
232
|
-
|
|
233
|
-
|
|
263
|
+
prepend(
|
|
264
|
+
place,
|
|
265
|
+
VariableDeclaration(
|
|
266
|
+
VariableDeclarator(
|
|
267
|
+
place.$stringConcealingArrayName,
|
|
268
|
+
place.$stringConcealingArray
|
|
269
|
+
)
|
|
270
|
+
)
|
|
271
|
+
);
|
|
272
|
+
}
|
|
234
273
|
|
|
235
|
-
|
|
274
|
+
var arrayIndex = place.$stringConcealingArray.elements.length;
|
|
236
275
|
|
|
237
|
-
|
|
238
|
-
if (!place) {
|
|
239
|
-
this.error(Error("No lexical block to insert code"));
|
|
240
|
-
}
|
|
276
|
+
place.$stringConcealingArray.elements.push(callExpr);
|
|
241
277
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
278
|
+
var memberExpression = MemberExpression(
|
|
279
|
+
Identifier(place.$stringConcealingArrayName),
|
|
280
|
+
Literal(arrayIndex),
|
|
281
|
+
true
|
|
282
|
+
);
|
|
245
283
|
|
|
246
|
-
|
|
284
|
+
newExpr = memberExpression;
|
|
285
|
+
break;
|
|
286
|
+
case "object":
|
|
287
|
+
if (!place.$stringConcealingObject) {
|
|
288
|
+
place.$stringConcealingObject = ObjectExpression([]);
|
|
289
|
+
place.$stringConcealingObjectName = this.getPlaceholder();
|
|
247
290
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
291
|
+
prepend(
|
|
292
|
+
place,
|
|
293
|
+
VariableDeclaration(
|
|
294
|
+
VariableDeclarator(
|
|
295
|
+
place.$stringConcealingObjectName,
|
|
296
|
+
place.$stringConcealingObject
|
|
297
|
+
)
|
|
298
|
+
)
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
var propName = this.gen.generate();
|
|
303
|
+
var property = Property(Literal(propName), callExpr, true);
|
|
304
|
+
place.$stringConcealingObject.properties.push(property);
|
|
305
|
+
|
|
306
|
+
var memberExpression = MemberExpression(
|
|
307
|
+
Identifier(place.$stringConcealingObjectName),
|
|
308
|
+
Literal(propName),
|
|
309
|
+
true
|
|
310
|
+
);
|
|
311
|
+
|
|
312
|
+
newExpr = memberExpression;
|
|
313
|
+
break;
|
|
252
314
|
}
|
|
253
315
|
}
|
|
316
|
+
|
|
317
|
+
this.replaceIdentifierOrLiteral(object, newExpr, parents);
|
|
254
318
|
};
|
|
255
319
|
}
|
|
256
320
|
}
|
package/src/traverse.ts
CHANGED
|
@@ -39,16 +39,9 @@ export type ExitCallback = () => void;
|
|
|
39
39
|
export function walk(
|
|
40
40
|
object: Node | Node[],
|
|
41
41
|
parents: Node[],
|
|
42
|
-
onEnter: EnterCallback
|
|
43
|
-
seen = new Set<Node>()
|
|
42
|
+
onEnter: EnterCallback
|
|
44
43
|
): "EXIT" | void {
|
|
45
44
|
if (typeof object === "object" && object) {
|
|
46
|
-
if (seen.has(object as any)) {
|
|
47
|
-
console.log(object);
|
|
48
|
-
throw new Error("Already seen: " + (object as any).type);
|
|
49
|
-
}
|
|
50
|
-
seen.add(object as any);
|
|
51
|
-
|
|
52
45
|
var newParents: Node[] = [object as Node, ...parents];
|
|
53
46
|
|
|
54
47
|
if (!Array.isArray(object)) {
|
package/src/types.ts
CHANGED
|
@@ -119,4 +119,12 @@ export type IJsConfuserDebugObfuscation = (
|
|
|
119
119
|
code: string,
|
|
120
120
|
options: ObfuscateOptions,
|
|
121
121
|
callback: (name: string, complete: number, totalTransforms: number) => void
|
|
122
|
-
) => Promise<
|
|
122
|
+
) => Promise<{
|
|
123
|
+
obfuscated: string;
|
|
124
|
+
transformationTimes: { [transformName: string]: number };
|
|
125
|
+
parseTime: number;
|
|
126
|
+
compileTime: number;
|
|
127
|
+
obfuscationTime: number;
|
|
128
|
+
totalTransforms: number;
|
|
129
|
+
totalPossibleTransforms: number;
|
|
130
|
+
}>;
|
package/src/util/compare.ts
CHANGED
|
@@ -53,8 +53,8 @@ export function isValidIdentifier(name: string): boolean {
|
|
|
53
53
|
return false;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
var x = name.match(/^[A-z$_][A-z0-9$_]*/);
|
|
57
|
-
return x && x[0] == name;
|
|
56
|
+
var x = name.match(/^[A-Za-z$_][A-Za-z0-9$_]*/);
|
|
57
|
+
return !!(x && x[0] == name);
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
export function isInsideType(
|
package/src/util/insert.ts
CHANGED
|
@@ -113,8 +113,14 @@ export function getDefiningContext(o: Node, p: Node[]): Node {
|
|
|
113
113
|
var variableDeclaration = p.find((x) => x.type == "VariableDeclaration");
|
|
114
114
|
ok(variableDeclaration);
|
|
115
115
|
|
|
116
|
-
if (
|
|
117
|
-
|
|
116
|
+
if (
|
|
117
|
+
variableDeclaration.kind === "let" ||
|
|
118
|
+
variableDeclaration.kind === "const"
|
|
119
|
+
) {
|
|
120
|
+
var context = getVarContext(o, p);
|
|
121
|
+
if (context && context.type === "Program") {
|
|
122
|
+
return getLexContext(o, p);
|
|
123
|
+
}
|
|
118
124
|
}
|
|
119
125
|
}
|
|
120
126
|
|
|
@@ -178,7 +184,7 @@ export function getBlockBody(block: Node): Node[] {
|
|
|
178
184
|
return getBlockBody(block.body);
|
|
179
185
|
}
|
|
180
186
|
|
|
181
|
-
export function getIndexDirect(object: Node, parent: Node
|
|
187
|
+
export function getIndexDirect(object: Node, parent: Node): string {
|
|
182
188
|
return Object.keys(parent).find((x) => parent[x] == object);
|
|
183
189
|
}
|
|
184
190
|
|
|
@@ -255,16 +261,25 @@ export function prepend(block: Node, ...nodes: Node[]) {
|
|
|
255
261
|
ok(!Array.isArray(block), "block should not be array");
|
|
256
262
|
|
|
257
263
|
if (block.type == "Program") {
|
|
258
|
-
var
|
|
264
|
+
var moveBy = 0;
|
|
259
265
|
block.body.forEach((stmt, i) => {
|
|
260
266
|
if (stmt.type == "ImportDeclaration") {
|
|
261
|
-
if (
|
|
262
|
-
|
|
267
|
+
if (moveBy == i) {
|
|
268
|
+
moveBy++;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (
|
|
273
|
+
stmt.type === "ExpressionStatement" &&
|
|
274
|
+
typeof stmt.directive === "string"
|
|
275
|
+
) {
|
|
276
|
+
if (moveBy == i) {
|
|
277
|
+
moveBy++;
|
|
263
278
|
}
|
|
264
279
|
}
|
|
265
280
|
});
|
|
266
281
|
|
|
267
|
-
block.body.splice(
|
|
282
|
+
block.body.splice(moveBy, 0, ...nodes);
|
|
268
283
|
} else {
|
|
269
284
|
getBlockBody(block).unshift(...nodes);
|
|
270
285
|
}
|
|
@@ -313,7 +328,10 @@ export function clone<T>(object: T): T {
|
|
|
313
328
|
* @param p
|
|
314
329
|
* @returns
|
|
315
330
|
*/
|
|
316
|
-
export function isForInitialize(
|
|
331
|
+
export function isForInitialize(
|
|
332
|
+
o: Node,
|
|
333
|
+
p: Node[]
|
|
334
|
+
): "initializer" | "left-hand" | false {
|
|
317
335
|
validateChain(o, p);
|
|
318
336
|
|
|
319
337
|
var forIndex = p.findIndex(
|
|
@@ -322,6 +340,17 @@ export function isForInitialize(o, p): "initializer" | "left-hand" | false {
|
|
|
322
340
|
x.type == "ForInStatement" ||
|
|
323
341
|
x.type == "ForOfStatement"
|
|
324
342
|
);
|
|
343
|
+
|
|
344
|
+
if (
|
|
345
|
+
p
|
|
346
|
+
.slice(0, forIndex)
|
|
347
|
+
.find((x) =>
|
|
348
|
+
["ArrowFunctionExpression", "BlockStatement"].includes(x.type)
|
|
349
|
+
)
|
|
350
|
+
) {
|
|
351
|
+
return false;
|
|
352
|
+
}
|
|
353
|
+
|
|
325
354
|
if (forIndex !== -1) {
|
|
326
355
|
if (p[forIndex].type == "ForStatement") {
|
|
327
356
|
if (p[forIndex].init == (p[forIndex - 1] || o)) {
|
package/test/code/ES6.src.js
CHANGED
|
@@ -73,3 +73,17 @@ for (var x of [3, 3, 5]) {
|
|
|
73
73
|
sum += x;
|
|
74
74
|
}
|
|
75
75
|
expect(sum).toStrictEqual(11);
|
|
76
|
+
|
|
77
|
+
// Variant #12 More complex for-loop initializer
|
|
78
|
+
var outside = 12;
|
|
79
|
+
for (
|
|
80
|
+
var myFunction = function () {
|
|
81
|
+
return outside;
|
|
82
|
+
};
|
|
83
|
+
false;
|
|
84
|
+
|
|
85
|
+
) {}
|
|
86
|
+
|
|
87
|
+
var TEST_OUTPUT = myFunction();
|
|
88
|
+
|
|
89
|
+
expect(TEST_OUTPUT).toStrictEqual(12);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import JsConfuser from "../../src/index";
|
|
2
|
+
|
|
3
|
+
// https://github.com/MichaelXF/js-confuser/issues/79
|
|
4
|
+
test("Variant #1: Support BigInt Literals (1n)", async () => {
|
|
5
|
+
var code = `
|
|
6
|
+
TEST_OUTPUT = 1n;
|
|
7
|
+
`;
|
|
8
|
+
|
|
9
|
+
var output = await JsConfuser(code, {
|
|
10
|
+
target: "node",
|
|
11
|
+
renameVariables: true,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
var TEST_OUTPUT;
|
|
15
|
+
eval(output);
|
|
16
|
+
|
|
17
|
+
expect(typeof TEST_OUTPUT).toStrictEqual("bigint");
|
|
18
|
+
expect(TEST_OUTPUT).toStrictEqual(1n);
|
|
19
|
+
});
|
package/test/index.test.ts
CHANGED
|
@@ -230,7 +230,19 @@ describe("debugObfuscation", () => {
|
|
|
230
230
|
callback
|
|
231
231
|
);
|
|
232
232
|
|
|
233
|
-
expect(typeof output).toStrictEqual("
|
|
233
|
+
expect(typeof output).toStrictEqual("object");
|
|
234
|
+
expect(typeof output.obfuscated).toStrictEqual("string");
|
|
235
|
+
expect(typeof output.obfuscationTime).toStrictEqual("number");
|
|
236
|
+
expect(typeof output.compileTime).toStrictEqual("number");
|
|
237
|
+
expect(typeof output.parseTime).toStrictEqual("number");
|
|
238
|
+
expect(typeof output.totalPossibleTransforms).toStrictEqual("number");
|
|
239
|
+
expect(typeof output.totalTransforms).toStrictEqual("number");
|
|
240
|
+
expect(typeof output.transformationTimes).toStrictEqual("object");
|
|
241
|
+
expect(typeof output.transformationTimes.RenameVariables).toStrictEqual(
|
|
242
|
+
"number"
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
eval(output.obfuscated);
|
|
234
246
|
expect(called).toStrictEqual(true);
|
|
235
247
|
});
|
|
236
248
|
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import JsConfuser from "../../src/index";
|
|
2
|
+
|
|
3
|
+
// https://github.com/MichaelXF/js-confuser/issues/74
|
|
4
|
+
test("Variant #1: Don't break Symbols", async () => {
|
|
5
|
+
if (typeof Symbol !== "undefined") {
|
|
6
|
+
for (var i = 0; i < 6; i++) {
|
|
7
|
+
var output = await JsConfuser(
|
|
8
|
+
`
|
|
9
|
+
|
|
10
|
+
var sym1 = Symbol();
|
|
11
|
+
|
|
12
|
+
if (true) {
|
|
13
|
+
sym1;
|
|
14
|
+
sym1;
|
|
15
|
+
sym1;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
TEST_OUTPUT = sym1;
|
|
19
|
+
|
|
20
|
+
`,
|
|
21
|
+
{ target: "node", renameVariables: true }
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
var TEST_OUTPUT;
|
|
25
|
+
|
|
26
|
+
eval(output);
|
|
27
|
+
expect(typeof TEST_OUTPUT).toStrictEqual("symbol");
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
});
|
|
@@ -672,3 +672,61 @@ test("Variant #20: Don't apply when functions are redefined", async () => {
|
|
|
672
672
|
eval(output);
|
|
673
673
|
expect(TEST_ARRAY).toStrictEqual([0, 0, 0]);
|
|
674
674
|
});
|
|
675
|
+
|
|
676
|
+
// https://github.com/MichaelXF/js-confuser/issues/70
|
|
677
|
+
test("Variant #21: Don't move Import Declarations", async () => {
|
|
678
|
+
var output = await JsConfuser(
|
|
679
|
+
`
|
|
680
|
+
import {createHash} from "crypto";
|
|
681
|
+
var inputString = "Hash this string";
|
|
682
|
+
var hashed = createHash("sha256").update(inputString).digest("hex");
|
|
683
|
+
TEST_OUTPUT = hashed;
|
|
684
|
+
`,
|
|
685
|
+
{
|
|
686
|
+
target: "node",
|
|
687
|
+
controlFlowFlattening: true,
|
|
688
|
+
}
|
|
689
|
+
);
|
|
690
|
+
|
|
691
|
+
// Ensure Control Flow FLattening was applied
|
|
692
|
+
expect(output).toContain("switch");
|
|
693
|
+
|
|
694
|
+
// Ensure the import declaration wasn't moved
|
|
695
|
+
expect(output.startsWith("import")).toStrictEqual(true);
|
|
696
|
+
|
|
697
|
+
// Convert to runnable code
|
|
698
|
+
output = output.replace(
|
|
699
|
+
`import{createHash}from'crypto';`,
|
|
700
|
+
"const {createHash}=require('crypto');"
|
|
701
|
+
);
|
|
702
|
+
|
|
703
|
+
var TEST_OUTPUT = "";
|
|
704
|
+
|
|
705
|
+
eval(output);
|
|
706
|
+
|
|
707
|
+
expect(TEST_OUTPUT).toStrictEqual(
|
|
708
|
+
"1cac63f39fd68d8c531f27b807610fb3d50f0fc3f186995767fb6316e7200a3e"
|
|
709
|
+
);
|
|
710
|
+
});
|
|
711
|
+
|
|
712
|
+
// https://github.com/MichaelXF/js-confuser/issues/81
|
|
713
|
+
test("Variant #22: Don't break typeof expression", async () => {
|
|
714
|
+
var output = await JsConfuser(
|
|
715
|
+
`
|
|
716
|
+
TEST_OUTPUT = false;
|
|
717
|
+
if(typeof nonExistentVariable === "undefined") {
|
|
718
|
+
TEST_OUTPUT = true;
|
|
719
|
+
}
|
|
720
|
+
`,
|
|
721
|
+
{
|
|
722
|
+
target: "node",
|
|
723
|
+
controlFlowFlattening: true,
|
|
724
|
+
}
|
|
725
|
+
);
|
|
726
|
+
|
|
727
|
+
var TEST_OUTPUT;
|
|
728
|
+
|
|
729
|
+
eval(output);
|
|
730
|
+
|
|
731
|
+
expect(TEST_OUTPUT).toStrictEqual(true);
|
|
732
|
+
});
|