js-confuser 1.5.0 → 1.5.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 +17 -0
- package/README.md +2 -0
- package/dist/transforms/controlFlowFlattening/switchCaseObfuscation.js +1 -1
- package/dist/transforms/extraction/objectExtraction.js +7 -4
- package/dist/transforms/flatten.js +43 -11
- package/dist/transforms/minify.js +1 -1
- package/dist/util/guard.js +10 -0
- package/package.json +1 -1
- package/src/transforms/controlFlowFlattening/switchCaseObfuscation.ts +2 -0
- package/src/transforms/extraction/objectExtraction.ts +11 -5
- package/src/transforms/flatten.ts +166 -28
- package/src/transforms/minify.ts +2 -0
- package/src/util/gen.ts +1 -1
- package/src/util/guard.ts +7 -0
- package/test/transforms/controlFlowFlattening/switchCaseObfuscation.test.ts +44 -0
- package/test/transforms/extraction/objectExtraction.test.ts +23 -0
- package/test/transforms/flatten.test.ts +3 -3
- package/test/transforms/minify.test.ts +22 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
# `1.5.2`
|
|
2
|
+
Mini fixes
|
|
3
|
+
|
|
4
|
+
- Fixed [#41](https://github.com/MichaelXF/js-confuser/issues/41)
|
|
5
|
+
- - Obfuscator mishandled switch statements with a `default` case
|
|
6
|
+
|
|
7
|
+
- Fixed [#43](https://github.com/MichaelXF/js-confuser/issues/43)
|
|
8
|
+
- - Obfuscator mishandled variable destructuring in for-loops
|
|
9
|
+
|
|
10
|
+
# `1.5.1`
|
|
11
|
+
Object Extraction Fix
|
|
12
|
+
|
|
13
|
+
- Fixed [#37](https://github.com/MichaelXF/js-confuser/issues/37)
|
|
14
|
+
- - Object Extraction was applying to objects with get/set methods, fixed in this version.
|
|
15
|
+
|
|
16
|
+
- Slight improvement to `Flatten`
|
|
17
|
+
|
|
1
18
|
# `1.5.0`
|
|
2
19
|
Hexadecimal Numbers
|
|
3
20
|
|
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
JS-Confuser is a JavaScript obfuscation tool to make your programs _impossible_ to read. [Try the web version](https://jsconfuser.com).
|
|
4
4
|
|
|
5
|
+
[](https://npmjs.com/package/js-confuser) [](https://github.com/MichaelXF/js-confuser) [](https://jsconfuser.com)
|
|
6
|
+
|
|
5
7
|
## Key features
|
|
6
8
|
|
|
7
9
|
- Variable renaming
|
|
@@ -28,7 +28,7 @@ class SwitchCaseObfuscation extends _transform.default {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
match(object, parents) {
|
|
31
|
-
return object.type == "SwitchStatement" && !object.cases.find(x => !(x.test.type == "Literal" && typeof x.test.value === "number" && Math.abs(x.test.value) < 100000));
|
|
31
|
+
return object.type == "SwitchStatement" && !object.cases.find(x => !(x.test && typeof x.test === "object" && x.test.type == "Literal" && typeof x.test.value === "number" && Math.abs(x.test.value) < 100000));
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
transform(object, parents) {
|
|
@@ -23,6 +23,8 @@ var _probability = require("../../probability");
|
|
|
23
23
|
|
|
24
24
|
var _assert = require("assert");
|
|
25
25
|
|
|
26
|
+
var _guard = require("../../util/guard");
|
|
27
|
+
|
|
26
28
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
27
29
|
|
|
28
30
|
/**
|
|
@@ -84,17 +86,18 @@ class ObjectExtraction extends _transform.default {
|
|
|
84
86
|
illegal.add(name);
|
|
85
87
|
return;
|
|
86
88
|
} // check for computed properties
|
|
89
|
+
// Change String literals to non-computed
|
|
87
90
|
|
|
88
91
|
|
|
89
92
|
object.properties.forEach(prop => {
|
|
90
|
-
if (prop.computed && prop.key
|
|
93
|
+
if (prop.computed && (0, _guard.isStringLiteral)(prop.key)) {
|
|
91
94
|
prop.computed = false;
|
|
92
95
|
}
|
|
93
96
|
});
|
|
94
|
-
var
|
|
97
|
+
var nonInitOrComputed = object.properties.find(x => x.kind !== "init" || x.computed);
|
|
95
98
|
|
|
96
|
-
if (
|
|
97
|
-
this.log(name + " has computed property: " +
|
|
99
|
+
if (nonInitOrComputed) {
|
|
100
|
+
this.log(name + " has non-init/computed property: " + nonInitOrComputed.key.name || nonInitOrComputed.key.value);
|
|
98
101
|
illegal.add(name);
|
|
99
102
|
return;
|
|
100
103
|
} else {
|
|
@@ -17,6 +17,8 @@ var _identifiers = require("../util/identifiers");
|
|
|
17
17
|
|
|
18
18
|
var _insert = require("../util/insert");
|
|
19
19
|
|
|
20
|
+
var _random = require("../util/random");
|
|
21
|
+
|
|
20
22
|
var _transform = _interopRequireDefault(require("./transform"));
|
|
21
23
|
|
|
22
24
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
@@ -44,7 +46,16 @@ class Flatten extends _transform.default {
|
|
|
44
46
|
|
|
45
47
|
_defineProperty(this, "definedNames", void 0);
|
|
46
48
|
|
|
49
|
+
_defineProperty(this, "flatMapName", void 0);
|
|
50
|
+
|
|
51
|
+
_defineProperty(this, "flatNode", void 0);
|
|
52
|
+
|
|
53
|
+
_defineProperty(this, "gen", void 0);
|
|
54
|
+
|
|
47
55
|
this.definedNames = new Map();
|
|
56
|
+
this.flatMapName = null;
|
|
57
|
+
this.flatNode = null;
|
|
58
|
+
this.gen = this.getGenerator();
|
|
48
59
|
}
|
|
49
60
|
|
|
50
61
|
apply(tree) {
|
|
@@ -175,7 +186,10 @@ class Flatten extends _transform.default {
|
|
|
175
186
|
}
|
|
176
187
|
|
|
177
188
|
var output = Array.from(modified);
|
|
178
|
-
var newName =
|
|
189
|
+
var newName = this.gen.generate();
|
|
190
|
+
var valName = this.getPlaceholder();
|
|
191
|
+
var resultName = this.getPlaceholder();
|
|
192
|
+
var propName = this.gen.generate();
|
|
179
193
|
(0, _insert.getBlockBody)(object.body).push((0, _gen.ReturnStatement)());
|
|
180
194
|
(0, _traverse.walk)(object.body, [object, ...parents], (o, p) => {
|
|
181
195
|
return () => {
|
|
@@ -187,33 +201,51 @@ class Flatten extends _transform.default {
|
|
|
187
201
|
}
|
|
188
202
|
|
|
189
203
|
o.argument = (0, _gen.ArrayExpression)(elements);
|
|
204
|
+
o.argument = (0, _gen.AssignmentExpression)("=", (0, _gen.MemberExpression)((0, _gen.Identifier)(resultName), (0, _gen.Identifier)(propName), false), o.argument);
|
|
190
205
|
}
|
|
191
206
|
};
|
|
192
207
|
});
|
|
193
208
|
var newBody = (0, _insert.getBlockBody)(object.body);
|
|
209
|
+
newBody.unshift((0, _gen.VariableDeclaration)((0, _gen.VariableDeclarator)((0, _gen.ArrayPattern)([(0, _gen.ArrayPattern)(input.map(_gen.Identifier)), (0, _gen.ArrayPattern)((0, _insert.clone)(object.params)), (0, _gen.Identifier)(resultName)]), (0, _gen.Identifier)(valName))));
|
|
194
210
|
|
|
195
|
-
if (
|
|
196
|
-
|
|
211
|
+
if (!this.flatMapName) {
|
|
212
|
+
this.flatMapName = this.getPlaceholder();
|
|
213
|
+
(0, _insert.prepend)(parents[parents.length - 1], (0, _gen.VariableDeclaration)((0, _gen.VariableDeclarator)(this.flatMapName, this.flatNode = (0, _gen.ObjectExpression)([]))));
|
|
197
214
|
}
|
|
198
215
|
|
|
199
|
-
var
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
(0,
|
|
216
|
+
var newFunctionExpression = (0, _gen.FunctionExpression)([(0, _gen.Identifier)(valName)], newBody);
|
|
217
|
+
newFunctionExpression.async = !!object.async;
|
|
218
|
+
newFunctionExpression.generator = !!object.generator;
|
|
219
|
+
var property = (0, _gen.Property)((0, _gen.Identifier)(newName), newFunctionExpression, false);
|
|
220
|
+
property.kind = "set";
|
|
221
|
+
this.flatNode.properties.push(property);
|
|
222
|
+
var identifier = (0, _gen.MemberExpression)((0, _gen.Identifier)(this.flatMapName), (0, _gen.Identifier)(newName), false);
|
|
203
223
|
var newParamNodes = object.params.map(() => (0, _gen.Identifier)(this.getPlaceholder())); // var result = newFn.call([...refs], ...arguments)
|
|
204
224
|
|
|
205
|
-
var call = (0, _gen.VariableDeclaration)((0, _gen.VariableDeclarator)(
|
|
225
|
+
var call = (0, _gen.VariableDeclaration)([(0, _gen.VariableDeclarator)(resultName, (0, _gen.ArrayExpression)([])), (0, _gen.VariableDeclarator)("_", (0, _gen.AssignmentExpression)("=", identifier, (0, _gen.ArrayExpression)([(0, _gen.ArrayExpression)(input.map(_gen.Identifier)), (0, _gen.ArrayExpression)([...newParamNodes]), (0, _gen.Identifier)(resultName)])))]); // result.pop()
|
|
206
226
|
|
|
207
|
-
var pop = (0, _gen.CallExpression)((0, _gen.MemberExpression)((0, _gen.Identifier)(
|
|
227
|
+
var pop = (0, _gen.CallExpression)((0, _gen.MemberExpression)((0, _gen.MemberExpression)((0, _gen.Identifier)(resultName), (0, _gen.Identifier)(propName), false), (0, _gen.Identifier)("pop"), false), []); // var result = newFn.call([...refs], ...arguments)
|
|
208
228
|
// modified1 = result.pop();
|
|
209
229
|
// modified2 = result.pop();
|
|
210
230
|
// ...modifiedN = result.pop();...
|
|
211
231
|
//
|
|
212
232
|
// return result.pop()
|
|
213
233
|
|
|
214
|
-
|
|
234
|
+
var newObjectBody = [call];
|
|
235
|
+
var outputReversed = [...output].reverse(); // DECOY STATEMENTS
|
|
236
|
+
|
|
237
|
+
var decoyKey = this.gen.generate();
|
|
238
|
+
var decoyNodes = [(0, _gen.IfStatement)((0, _gen.MemberExpression)((0, _gen.Identifier)(resultName), (0, _gen.Identifier)(this.gen.generate()), false), [(0, _gen.ThrowStatement)((0, _gen.NewExpression)((0, _gen.Identifier)("Error"), [(0, _gen.Literal)(this.getPlaceholder())]))]), (0, _gen.IfStatement)((0, _gen.MemberExpression)((0, _gen.Identifier)(resultName), (0, _gen.Identifier)(this.gen.generate()), false), [(0, _gen.ReturnStatement)((0, _gen.Identifier)(resultName))]), (0, _gen.IfStatement)((0, _gen.MemberExpression)((0, _gen.Identifier)(resultName), (0, _gen.Identifier)(this.gen.generate()), false), [(0, _gen.ReturnStatement)((0, _gen.Identifier)(resultName))]), (0, _gen.IfStatement)((0, _gen.MemberExpression)((0, _gen.Identifier)(resultName), (0, _gen.Identifier)(decoyKey), false), [(0, _gen.ReturnStatement)((0, _gen.MemberExpression)((0, _gen.Identifier)(resultName), (0, _gen.Identifier)(decoyKey), false))]), (0, _gen.IfStatement)((0, _gen.MemberExpression)((0, _gen.Identifier)(resultName), (0, _gen.Identifier)(this.gen.generate()), false), [(0, _gen.ReturnStatement)((0, _gen.MemberExpression)((0, _gen.Identifier)(resultName), (0, _gen.Identifier)(this.gen.generate()), false))])];
|
|
239
|
+
(0, _random.shuffle)(decoyNodes);
|
|
240
|
+
decoyNodes.forEach(decoyNode => {
|
|
241
|
+
if (Math.random() < 0.5) {
|
|
242
|
+
newObjectBody.push(decoyNode);
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
newObjectBody.push(...outputReversed.map(name => {
|
|
215
246
|
return (0, _gen.ExpressionStatement)((0, _gen.AssignmentExpression)("=", (0, _gen.Identifier)(name), (0, _insert.clone)(pop)));
|
|
216
|
-
}), (0, _gen.ReturnStatement)((0, _insert.clone)(pop))
|
|
247
|
+
}), (0, _gen.ReturnStatement)((0, _insert.clone)(pop)));
|
|
248
|
+
object.body = (0, _gen.BlockStatement)(newObjectBody);
|
|
217
249
|
object.params = newParamNodes;
|
|
218
250
|
};
|
|
219
251
|
}
|
|
@@ -457,7 +457,7 @@ class Minify extends _transform.default {
|
|
|
457
457
|
} // check for redundant patterns
|
|
458
458
|
|
|
459
459
|
|
|
460
|
-
if (object.id.type == "ArrayPattern" && object.init.type == "ArrayExpression") {
|
|
460
|
+
if (object.id.type == "ArrayPattern" && object.init && typeof object.init === "object" && object.init.type == "ArrayExpression") {
|
|
461
461
|
if (object.id.elements.length == 1 && object.init.elements.length == 1) {
|
|
462
462
|
object.id = object.id.elements[0];
|
|
463
463
|
object.init = object.init.elements[0];
|
package/package.json
CHANGED
|
@@ -19,6 +19,7 @@ import { getIdentifierInfo } from "../../util/identifiers";
|
|
|
19
19
|
import { isValidIdentifier } from "../../util/compare";
|
|
20
20
|
import { ComputeProbabilityMap } from "../../probability";
|
|
21
21
|
import { ok } from "assert";
|
|
22
|
+
import { isStringLiteral } from "../../util/guard";
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
25
|
* Extracts keys out of an object if possible.
|
|
@@ -87,17 +88,22 @@ export default class ObjectExtraction extends Transform {
|
|
|
87
88
|
}
|
|
88
89
|
|
|
89
90
|
// check for computed properties
|
|
91
|
+
// Change String literals to non-computed
|
|
90
92
|
object.properties.forEach((prop) => {
|
|
91
|
-
if (prop.computed && prop.key
|
|
93
|
+
if (prop.computed && isStringLiteral(prop.key)) {
|
|
92
94
|
prop.computed = false;
|
|
93
95
|
}
|
|
94
96
|
});
|
|
95
97
|
|
|
96
|
-
var
|
|
97
|
-
|
|
98
|
+
var nonInitOrComputed = object.properties.find(
|
|
99
|
+
(x) => x.kind !== "init" || x.computed
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
if (nonInitOrComputed) {
|
|
98
103
|
this.log(
|
|
99
|
-
name +
|
|
100
|
-
computed
|
|
104
|
+
name +
|
|
105
|
+
" has non-init/computed property: " +
|
|
106
|
+
nonInitOrComputed.key.name || nonInitOrComputed.key.value
|
|
101
107
|
);
|
|
102
108
|
illegal.add(name);
|
|
103
109
|
return;
|
|
@@ -16,6 +16,14 @@ import {
|
|
|
16
16
|
Node,
|
|
17
17
|
BlockStatement,
|
|
18
18
|
ArrayPattern,
|
|
19
|
+
FunctionExpression,
|
|
20
|
+
ObjectExpression,
|
|
21
|
+
Property,
|
|
22
|
+
SpreadElement,
|
|
23
|
+
Literal,
|
|
24
|
+
IfStatement,
|
|
25
|
+
ThrowStatement,
|
|
26
|
+
NewExpression,
|
|
19
27
|
} from "../util/gen";
|
|
20
28
|
import { getIdentifierInfo } from "../util/identifiers";
|
|
21
29
|
import {
|
|
@@ -25,6 +33,7 @@ import {
|
|
|
25
33
|
prepend,
|
|
26
34
|
clone,
|
|
27
35
|
} from "../util/insert";
|
|
36
|
+
import { shuffle } from "../util/random";
|
|
28
37
|
import Transform from "./transform";
|
|
29
38
|
|
|
30
39
|
/**
|
|
@@ -41,10 +50,17 @@ import Transform from "./transform";
|
|
|
41
50
|
export default class Flatten extends Transform {
|
|
42
51
|
definedNames: Map<Node, Set<string>>;
|
|
43
52
|
|
|
53
|
+
flatMapName: string;
|
|
54
|
+
flatNode: Node;
|
|
55
|
+
gen: any;
|
|
56
|
+
|
|
44
57
|
constructor(o) {
|
|
45
58
|
super(o, ObfuscateOrder.Flatten);
|
|
46
59
|
|
|
47
60
|
this.definedNames = new Map();
|
|
61
|
+
this.flatMapName = null;
|
|
62
|
+
this.flatNode = null;
|
|
63
|
+
this.gen = this.getGenerator();
|
|
48
64
|
}
|
|
49
65
|
|
|
50
66
|
apply(tree) {
|
|
@@ -200,11 +216,10 @@ export default class Flatten extends Transform {
|
|
|
200
216
|
|
|
201
217
|
var output = Array.from(modified);
|
|
202
218
|
|
|
203
|
-
var newName =
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
((object.id && object.id.name) || "fn");
|
|
219
|
+
var newName = this.gen.generate();
|
|
220
|
+
var valName = this.getPlaceholder();
|
|
221
|
+
var resultName = this.getPlaceholder();
|
|
222
|
+
var propName = this.gen.generate();
|
|
208
223
|
|
|
209
224
|
getBlockBody(object.body).push(ReturnStatement());
|
|
210
225
|
walk(object.body, [object, ...parents], (o, p) => {
|
|
@@ -222,51 +237,100 @@ export default class Flatten extends Transform {
|
|
|
222
237
|
}
|
|
223
238
|
|
|
224
239
|
o.argument = ArrayExpression(elements);
|
|
240
|
+
|
|
241
|
+
o.argument = AssignmentExpression(
|
|
242
|
+
"=",
|
|
243
|
+
MemberExpression(
|
|
244
|
+
Identifier(resultName),
|
|
245
|
+
Identifier(propName),
|
|
246
|
+
false
|
|
247
|
+
),
|
|
248
|
+
o.argument
|
|
249
|
+
);
|
|
225
250
|
}
|
|
226
251
|
};
|
|
227
252
|
});
|
|
228
253
|
|
|
229
254
|
var newBody = getBlockBody(object.body);
|
|
230
255
|
|
|
231
|
-
|
|
232
|
-
|
|
256
|
+
newBody.unshift(
|
|
257
|
+
VariableDeclaration(
|
|
258
|
+
VariableDeclarator(
|
|
259
|
+
ArrayPattern([
|
|
260
|
+
ArrayPattern(input.map(Identifier)),
|
|
261
|
+
ArrayPattern(clone(object.params)),
|
|
262
|
+
Identifier(resultName),
|
|
263
|
+
]),
|
|
264
|
+
|
|
265
|
+
Identifier(valName)
|
|
266
|
+
)
|
|
267
|
+
)
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
if (!this.flatMapName) {
|
|
271
|
+
this.flatMapName = this.getPlaceholder();
|
|
272
|
+
prepend(
|
|
273
|
+
parents[parents.length - 1],
|
|
233
274
|
VariableDeclaration(
|
|
234
275
|
VariableDeclarator(
|
|
235
|
-
|
|
236
|
-
|
|
276
|
+
this.flatMapName,
|
|
277
|
+
(this.flatNode = ObjectExpression([]))
|
|
237
278
|
)
|
|
238
279
|
)
|
|
239
280
|
);
|
|
240
281
|
}
|
|
241
282
|
|
|
242
|
-
var
|
|
243
|
-
|
|
244
|
-
clone(object.params),
|
|
283
|
+
var newFunctionExpression = FunctionExpression(
|
|
284
|
+
[Identifier(valName)],
|
|
245
285
|
newBody
|
|
246
286
|
);
|
|
247
|
-
newFunctionDeclaration.async = !!object.async;
|
|
248
|
-
newFunctionDeclaration.generator = !!object.generator;
|
|
249
287
|
|
|
250
|
-
|
|
288
|
+
newFunctionExpression.async = !!object.async;
|
|
289
|
+
newFunctionExpression.generator = !!object.generator;
|
|
290
|
+
|
|
291
|
+
var property = Property(
|
|
292
|
+
Identifier(newName),
|
|
293
|
+
newFunctionExpression,
|
|
294
|
+
false
|
|
295
|
+
);
|
|
296
|
+
property.kind = "set";
|
|
297
|
+
|
|
298
|
+
this.flatNode.properties.push(property);
|
|
299
|
+
|
|
300
|
+
var identifier = MemberExpression(
|
|
301
|
+
Identifier(this.flatMapName),
|
|
302
|
+
Identifier(newName),
|
|
303
|
+
false
|
|
304
|
+
);
|
|
251
305
|
|
|
252
306
|
var newParamNodes = object.params.map(() =>
|
|
253
307
|
Identifier(this.getPlaceholder())
|
|
254
308
|
);
|
|
255
309
|
|
|
256
310
|
// var result = newFn.call([...refs], ...arguments)
|
|
257
|
-
var call = VariableDeclaration(
|
|
311
|
+
var call = VariableDeclaration([
|
|
312
|
+
VariableDeclarator(resultName, ArrayExpression([])),
|
|
258
313
|
VariableDeclarator(
|
|
259
|
-
"
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
314
|
+
"_",
|
|
315
|
+
AssignmentExpression(
|
|
316
|
+
"=",
|
|
317
|
+
identifier,
|
|
318
|
+
ArrayExpression([
|
|
319
|
+
ArrayExpression(input.map(Identifier)),
|
|
320
|
+
ArrayExpression([...newParamNodes]),
|
|
321
|
+
Identifier(resultName),
|
|
322
|
+
])
|
|
263
323
|
)
|
|
264
|
-
)
|
|
265
|
-
);
|
|
324
|
+
),
|
|
325
|
+
]);
|
|
266
326
|
|
|
267
327
|
// result.pop()
|
|
268
328
|
var pop = CallExpression(
|
|
269
|
-
MemberExpression(
|
|
329
|
+
MemberExpression(
|
|
330
|
+
MemberExpression(Identifier(resultName), Identifier(propName), false),
|
|
331
|
+
Identifier("pop"),
|
|
332
|
+
false
|
|
333
|
+
),
|
|
270
334
|
[]
|
|
271
335
|
);
|
|
272
336
|
|
|
@@ -277,16 +341,90 @@ export default class Flatten extends Transform {
|
|
|
277
341
|
//
|
|
278
342
|
// return result.pop()
|
|
279
343
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
344
|
+
var newObjectBody: Node[] = [call];
|
|
345
|
+
var outputReversed = [...output].reverse();
|
|
346
|
+
|
|
347
|
+
// DECOY STATEMENTS
|
|
348
|
+
var decoyKey = this.gen.generate();
|
|
349
|
+
var decoyNodes = [
|
|
350
|
+
IfStatement(
|
|
351
|
+
MemberExpression(
|
|
352
|
+
Identifier(resultName),
|
|
353
|
+
Identifier(this.gen.generate()),
|
|
354
|
+
false
|
|
355
|
+
),
|
|
356
|
+
[
|
|
357
|
+
ThrowStatement(
|
|
358
|
+
NewExpression(Identifier("Error"), [
|
|
359
|
+
Literal(this.getPlaceholder()),
|
|
360
|
+
])
|
|
361
|
+
),
|
|
362
|
+
]
|
|
363
|
+
),
|
|
364
|
+
IfStatement(
|
|
365
|
+
MemberExpression(
|
|
366
|
+
Identifier(resultName),
|
|
367
|
+
Identifier(this.gen.generate()),
|
|
368
|
+
false
|
|
369
|
+
),
|
|
370
|
+
[ReturnStatement(Identifier(resultName))]
|
|
371
|
+
),
|
|
372
|
+
IfStatement(
|
|
373
|
+
MemberExpression(
|
|
374
|
+
Identifier(resultName),
|
|
375
|
+
Identifier(this.gen.generate()),
|
|
376
|
+
false
|
|
377
|
+
),
|
|
378
|
+
[ReturnStatement(Identifier(resultName))]
|
|
379
|
+
),
|
|
380
|
+
IfStatement(
|
|
381
|
+
MemberExpression(Identifier(resultName), Identifier(decoyKey), false),
|
|
382
|
+
[
|
|
383
|
+
ReturnStatement(
|
|
384
|
+
MemberExpression(
|
|
385
|
+
Identifier(resultName),
|
|
386
|
+
Identifier(decoyKey),
|
|
387
|
+
false
|
|
388
|
+
)
|
|
389
|
+
),
|
|
390
|
+
]
|
|
391
|
+
),
|
|
392
|
+
IfStatement(
|
|
393
|
+
MemberExpression(
|
|
394
|
+
Identifier(resultName),
|
|
395
|
+
Identifier(this.gen.generate()),
|
|
396
|
+
false
|
|
397
|
+
),
|
|
398
|
+
[
|
|
399
|
+
ReturnStatement(
|
|
400
|
+
MemberExpression(
|
|
401
|
+
Identifier(resultName),
|
|
402
|
+
Identifier(this.gen.generate()),
|
|
403
|
+
false
|
|
404
|
+
)
|
|
405
|
+
),
|
|
406
|
+
]
|
|
407
|
+
),
|
|
408
|
+
];
|
|
409
|
+
|
|
410
|
+
shuffle(decoyNodes);
|
|
411
|
+
decoyNodes.forEach((decoyNode) => {
|
|
412
|
+
if (Math.random() < 0.5) {
|
|
413
|
+
newObjectBody.push(decoyNode);
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
newObjectBody.push(
|
|
418
|
+
...outputReversed.map((name) => {
|
|
283
419
|
return ExpressionStatement(
|
|
284
420
|
AssignmentExpression("=", Identifier(name), clone(pop))
|
|
285
421
|
);
|
|
286
422
|
}),
|
|
287
423
|
|
|
288
|
-
ReturnStatement(clone(pop))
|
|
289
|
-
|
|
424
|
+
ReturnStatement(clone(pop))
|
|
425
|
+
);
|
|
426
|
+
|
|
427
|
+
object.body = BlockStatement(newObjectBody);
|
|
290
428
|
|
|
291
429
|
object.params = newParamNodes;
|
|
292
430
|
};
|
package/src/transforms/minify.ts
CHANGED
package/src/util/gen.ts
CHANGED
|
@@ -58,7 +58,7 @@ export type EvalCallback = {
|
|
|
58
58
|
*/
|
|
59
59
|
export type Chain = Node[];
|
|
60
60
|
|
|
61
|
-
export function Literal(value: string | number | boolean) {
|
|
61
|
+
export function Literal(value: string | number | boolean): Node {
|
|
62
62
|
if (typeof value === "undefined") {
|
|
63
63
|
throw new Error("value is undefined");
|
|
64
64
|
}
|
|
@@ -74,3 +74,47 @@ it("should not obfuscate switch statements with complex discriminants (SwitchCas
|
|
|
74
74
|
|
|
75
75
|
eval(output);
|
|
76
76
|
});
|
|
77
|
+
|
|
78
|
+
// https://github.com/MichaelXF/js-confuser/issues/41
|
|
79
|
+
it("Not apply to switch statements with default cases", async ()=>{
|
|
80
|
+
|
|
81
|
+
var code = `
|
|
82
|
+
var array = [];
|
|
83
|
+
|
|
84
|
+
function runOnce(stateParam){
|
|
85
|
+
switch(stateParam){
|
|
86
|
+
case 1: array.push(1, 2, 3); break;
|
|
87
|
+
case 2: array.push(4, 5, 6); break;
|
|
88
|
+
case 3: array.push(7, 8, 9); break;
|
|
89
|
+
default: array.push(10); break;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
runOnce(1);
|
|
94
|
+
runOnce(2);
|
|
95
|
+
runOnce(3);
|
|
96
|
+
runOnce(-1); // default case
|
|
97
|
+
|
|
98
|
+
input(array);
|
|
99
|
+
`;
|
|
100
|
+
|
|
101
|
+
var output = await JsConfuser(code, {
|
|
102
|
+
target: "browser",
|
|
103
|
+
controlFlowFlattening: true,
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
expect(
|
|
107
|
+
output.includes("case 1:") &&
|
|
108
|
+
output.includes("case 2:") &&
|
|
109
|
+
output.includes("case 3:")
|
|
110
|
+
).toStrictEqual(true);
|
|
111
|
+
|
|
112
|
+
function input(array) {
|
|
113
|
+
expect(array).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
eval(output);
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
});
|
|
@@ -423,3 +423,26 @@ it("should properly use custom callback to exclude certain names from being chan
|
|
|
423
423
|
|
|
424
424
|
eval(output);
|
|
425
425
|
});
|
|
426
|
+
|
|
427
|
+
it("should not apply to objects with non-init properties (method, set, get)", async () => {
|
|
428
|
+
var code = `
|
|
429
|
+
|
|
430
|
+
var realValue = 0;
|
|
431
|
+
var TEST_OBJECT = {
|
|
432
|
+
set key(newValue){
|
|
433
|
+
realValue = newValue;
|
|
434
|
+
},
|
|
435
|
+
get key(){
|
|
436
|
+
return realValue;
|
|
437
|
+
}
|
|
438
|
+
};
|
|
439
|
+
`;
|
|
440
|
+
|
|
441
|
+
var output = await JsConfuser(code, {
|
|
442
|
+
target: "node",
|
|
443
|
+
objectExtraction: true,
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
expect(output).toContain("TEST_OBJECT");
|
|
447
|
+
expect(output).toContain("set ");
|
|
448
|
+
});
|
|
@@ -17,7 +17,7 @@ it("should bring independent to the global level", async () => {
|
|
|
17
17
|
}
|
|
18
18
|
);
|
|
19
19
|
|
|
20
|
-
expect(output.
|
|
20
|
+
expect(output).toContain("set");
|
|
21
21
|
});
|
|
22
22
|
|
|
23
23
|
it("should have correct return values", async () => {
|
|
@@ -227,7 +227,7 @@ it("should not change functions with const", async () => {
|
|
|
227
227
|
}
|
|
228
228
|
);
|
|
229
229
|
|
|
230
|
-
expect(output).not.toContain("
|
|
230
|
+
expect(output).not.toContain("set");
|
|
231
231
|
|
|
232
232
|
var value = "never_called",
|
|
233
233
|
input = (x) => (value = x);
|
|
@@ -255,7 +255,7 @@ it("should work when pattern-based assignment expressions are involved", async (
|
|
|
255
255
|
}
|
|
256
256
|
);
|
|
257
257
|
|
|
258
|
-
expect(output).toContain("
|
|
258
|
+
expect(output).toContain("set");
|
|
259
259
|
|
|
260
260
|
var value = "never_called",
|
|
261
261
|
input = (x) => (value = x);
|
|
@@ -299,3 +299,25 @@ test("Variant #15: Removing implied 'return'", async () => {
|
|
|
299
299
|
|
|
300
300
|
expect(output2).toContain("return");
|
|
301
301
|
});
|
|
302
|
+
|
|
303
|
+
// https://github.com/MichaelXF/js-confuser/issues/43
|
|
304
|
+
test("Variant #16: Handle deconstructuring in for loop", async ()=>{
|
|
305
|
+
// Valid
|
|
306
|
+
var output = await JsConfuser(
|
|
307
|
+
`
|
|
308
|
+
for(const [a] of [[1]]) {
|
|
309
|
+
input(a);
|
|
310
|
+
}
|
|
311
|
+
`,
|
|
312
|
+
{ target: "node", minify: true }
|
|
313
|
+
);
|
|
314
|
+
|
|
315
|
+
var value;
|
|
316
|
+
function input(valueIn){
|
|
317
|
+
value = valueIn;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
eval(output);
|
|
321
|
+
|
|
322
|
+
expect(value).toStrictEqual(1);
|
|
323
|
+
})
|