js-confuser 1.5.8 → 1.6.0
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/.github/workflows/node.js.yml +2 -2
- package/CHANGELOG.md +69 -0
- package/README.md +143 -7
- package/dist/index.js +33 -4
- package/dist/obfuscator.js +30 -31
- package/dist/options.js +4 -5
- package/dist/order.js +4 -6
- package/dist/probability.js +2 -4
- package/dist/templates/bufferToString.js +13 -0
- package/dist/templates/crash.js +2 -2
- package/dist/templates/es5.js +18 -0
- package/dist/transforms/antiTooling.js +1 -1
- package/dist/transforms/calculator.js +77 -21
- package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +980 -367
- package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +8 -3
- package/dist/transforms/controlFlowFlattening/switchCaseObfuscation.js +25 -26
- package/dist/transforms/deadCode.js +33 -25
- package/dist/transforms/dispatcher.js +7 -6
- package/dist/transforms/es5/antiClass.js +6 -2
- package/dist/transforms/es5/antiDestructuring.js +3 -1
- package/dist/transforms/es5/es5.js +31 -34
- package/dist/transforms/eval.js +11 -0
- package/dist/transforms/extraction/duplicateLiteralsRemoval.js +8 -5
- package/dist/transforms/extraction/objectExtraction.js +6 -1
- package/dist/transforms/finalizer.js +82 -0
- package/dist/transforms/flatten.js +82 -55
- package/dist/transforms/hexadecimalNumbers.js +34 -9
- package/dist/transforms/identifier/globalAnalysis.js +88 -0
- package/dist/transforms/identifier/globalConcealing.js +10 -83
- package/dist/transforms/identifier/movedDeclarations.js +2 -8
- package/dist/transforms/identifier/renameVariables.js +39 -27
- package/dist/transforms/identifier/variableAnalysis.js +58 -62
- package/dist/transforms/minify.js +80 -61
- package/dist/transforms/opaquePredicates.js +1 -1
- package/dist/transforms/preparation/preparation.js +2 -2
- package/dist/transforms/preparation.js +231 -0
- package/dist/transforms/renameLabels.js +1 -1
- package/dist/transforms/rgf.js +4 -5
- package/dist/transforms/stack.js +87 -26
- package/dist/transforms/string/encoding.js +150 -179
- package/dist/transforms/string/stringCompression.js +14 -15
- package/dist/transforms/string/stringConcealing.js +25 -8
- package/dist/transforms/string/stringEncoding.js +13 -24
- package/dist/transforms/transform.js +11 -18
- package/dist/traverse.js +24 -18
- package/dist/util/compare.js +2 -2
- package/dist/util/gen.js +15 -0
- package/dist/util/insert.js +31 -7
- package/dist/util/random.js +15 -0
- package/package.json +5 -5
- package/src/index.ts +57 -19
- package/src/obfuscator.ts +26 -29
- package/src/options.ts +17 -21
- package/src/order.ts +4 -8
- package/src/probability.ts +2 -3
- package/src/templates/bufferToString.ts +68 -0
- package/src/templates/crash.ts +5 -9
- package/src/templates/es5.ts +131 -0
- package/src/transforms/antiTooling.ts +1 -1
- package/src/transforms/calculator.ts +122 -59
- package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +1583 -571
- package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +18 -3
- package/src/transforms/deadCode.ts +383 -26
- package/src/transforms/dispatcher.ts +8 -6
- package/src/transforms/es5/antiClass.ts +10 -1
- package/src/transforms/es5/antiDestructuring.ts +3 -1
- package/src/transforms/es5/es5.ts +32 -77
- package/src/transforms/eval.ts +18 -0
- package/src/transforms/extraction/duplicateLiteralsRemoval.ts +9 -6
- package/src/transforms/extraction/objectExtraction.ts +12 -5
- package/src/transforms/finalizer.ts +75 -0
- package/src/transforms/flatten.ts +194 -151
- package/src/transforms/identifier/globalAnalysis.ts +85 -0
- package/src/transforms/identifier/globalConcealing.ts +14 -103
- package/src/transforms/identifier/movedDeclarations.ts +4 -11
- package/src/transforms/identifier/renameVariables.ts +37 -30
- package/src/transforms/identifier/variableAnalysis.ts +66 -73
- package/src/transforms/minify.ts +116 -77
- package/src/transforms/opaquePredicates.ts +2 -2
- package/src/transforms/preparation.ts +238 -0
- package/src/transforms/renameLabels.ts +2 -2
- package/src/transforms/rgf.ts +6 -7
- package/src/transforms/stack.ts +97 -37
- package/src/transforms/string/encoding.ts +115 -212
- package/src/transforms/string/stringCompression.ts +27 -18
- package/src/transforms/string/stringConcealing.ts +41 -11
- package/src/transforms/string/stringEncoding.ts +18 -18
- package/src/transforms/transform.ts +15 -21
- package/src/traverse.ts +24 -12
- package/src/types.ts +11 -2
- package/src/util/compare.ts +2 -2
- package/src/util/gen.ts +21 -1
- package/src/util/insert.ts +49 -9
- package/src/util/random.ts +13 -0
- package/test/code/Cash.test.ts +1 -1
- package/test/code/Dynamic.test.ts +12 -10
- package/test/code/ES6.src.js +136 -0
- package/test/code/ES6.test.ts +28 -2
- package/test/code/NewFeatures.test.ts +19 -0
- package/test/index.test.ts +15 -2
- package/test/probability.test.ts +44 -0
- package/test/templates/template.test.ts +1 -1
- package/test/transforms/antiTooling.test.ts +52 -0
- package/test/transforms/calculator.test.ts +40 -0
- package/test/transforms/controlFlowFlattening/controlFlowFlattening.test.ts +713 -149
- package/test/transforms/controlFlowFlattening/expressionObfuscation.test.ts +173 -0
- package/test/transforms/deadCode.test.ts +66 -15
- package/test/transforms/dispatcher.test.ts +44 -1
- package/test/transforms/es5/antiClass.test.ts +33 -0
- package/test/transforms/es5/antiDestructuring.test.ts +16 -0
- package/test/transforms/eval.test.ts +53 -0
- package/test/transforms/extraction/objectExtraction.test.ts +21 -0
- package/test/transforms/flatten.test.ts +195 -3
- package/test/transforms/identifier/movedDeclarations.test.ts +27 -0
- package/test/transforms/identifier/renameVariables.test.ts +108 -0
- package/test/transforms/lock/antiDebug.test.ts +2 -2
- package/test/transforms/minify.test.ts +151 -0
- package/test/transforms/preparation.test.ts +157 -0
- package/test/transforms/rgf.test.ts +56 -29
- package/test/transforms/stack.test.ts +91 -21
- package/test/transforms/string/stringCompression.test.ts +39 -0
- package/test/transforms/string/stringConcealing.test.ts +115 -0
- package/test/transforms/string/stringEncoding.test.ts +53 -2
- package/test/transforms/transform.test.ts +66 -0
- package/test/traverse.test.ts +139 -0
- package/test/util/compare.test.ts +23 -1
- package/src/transforms/controlFlowFlattening/choiceFlowObfuscation.ts +0 -87
- package/src/transforms/controlFlowFlattening/controlFlowObfuscation.ts +0 -203
- package/src/transforms/controlFlowFlattening/switchCaseObfuscation.ts +0 -130
- package/src/transforms/hexadecimalNumbers.ts +0 -31
- package/src/transforms/hideInitializingCode.ts +0 -432
- package/src/transforms/label.ts +0 -64
- package/src/transforms/preparation/nameConflicts.ts +0 -102
- package/src/transforms/preparation/preparation.ts +0 -176
- package/test/transforms/controlFlowFlattening/controlFlowObfuscation.test.ts +0 -101
- package/test/transforms/controlFlowFlattening/switchCaseObfuscation.test.ts +0 -120
- package/test/transforms/hideInitializingCode.test.ts +0 -336
- package/test/transforms/preparation/nameConflicts.test.ts +0 -52
- package/test/transforms/preparation/preparation.test.ts +0 -62
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
import { append, prepend } from "../../util/insert";
|
|
18
18
|
import Transform from "../transform";
|
|
19
19
|
import { isModuleSource } from "./stringConcealing";
|
|
20
|
+
import { chance } from "../../util/random";
|
|
20
21
|
function LZ_encode(c) {
|
|
21
22
|
ok(c);
|
|
22
23
|
var x = "charCodeAt",
|
|
@@ -83,7 +84,7 @@ export default class StringCompression extends Transform {
|
|
|
83
84
|
map: Map<string, number>;
|
|
84
85
|
ignore: Set<string>;
|
|
85
86
|
string: string;
|
|
86
|
-
delimiter = "
|
|
87
|
+
delimiter = "|";
|
|
87
88
|
|
|
88
89
|
fnName: string;
|
|
89
90
|
|
|
@@ -110,7 +111,11 @@ export default class StringCompression extends Transform {
|
|
|
110
111
|
|
|
111
112
|
var encoded = LZ_encode(this.string);
|
|
112
113
|
if (LZ_decode(encoded) !== this.string) {
|
|
113
|
-
this.error(
|
|
114
|
+
this.error(
|
|
115
|
+
new Error(
|
|
116
|
+
"String failed to be decoded. Try disabling the 'stringCompression' option."
|
|
117
|
+
)
|
|
118
|
+
);
|
|
114
119
|
}
|
|
115
120
|
|
|
116
121
|
var getStringParamName = this.getPlaceholder();
|
|
@@ -195,37 +200,41 @@ export default class StringCompression extends Transform {
|
|
|
195
200
|
return;
|
|
196
201
|
}
|
|
197
202
|
|
|
198
|
-
if (
|
|
203
|
+
if (
|
|
204
|
+
!ComputeProbabilityMap(
|
|
205
|
+
this.options.stringCompression,
|
|
206
|
+
(x) => x,
|
|
207
|
+
object.value
|
|
208
|
+
)
|
|
209
|
+
) {
|
|
199
210
|
return;
|
|
200
211
|
}
|
|
201
212
|
|
|
213
|
+
// HARD CODED LIMIT of 10,000 (after 1,000 elements)
|
|
214
|
+
if (this.map.size > 1000 && !chance(this.map.size / 100)) return;
|
|
215
|
+
|
|
202
216
|
var index = this.map.get(object.value);
|
|
217
|
+
|
|
218
|
+
// New string, add it!
|
|
203
219
|
if (typeof index !== "number") {
|
|
220
|
+
// Ensure the string gets properly decoded
|
|
204
221
|
if (LZ_decode(LZ_encode(object.value)) !== object.value) {
|
|
205
222
|
this.ignore.add(object.value);
|
|
206
223
|
return;
|
|
207
224
|
}
|
|
208
225
|
|
|
209
|
-
var before = this.string;
|
|
210
|
-
|
|
211
226
|
index = this.map.size;
|
|
212
227
|
this.map.set(object.value, index);
|
|
213
228
|
this.string += object.value + this.delimiter;
|
|
214
|
-
|
|
215
|
-
// allow rollback if string becomes corrupted
|
|
216
|
-
if (LZ_decode(LZ_encode(this.string)) !== this.string) {
|
|
217
|
-
this.string = before;
|
|
218
|
-
this.map.delete(object.value);
|
|
219
|
-
this.ignore.add(object.value);
|
|
220
|
-
return;
|
|
221
|
-
}
|
|
222
229
|
}
|
|
223
230
|
ok(typeof index === "number");
|
|
224
231
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
232
|
+
return () => {
|
|
233
|
+
this.replaceIdentifierOrLiteral(
|
|
234
|
+
object,
|
|
235
|
+
CallExpression(Identifier(this.fnName), [Literal(index)]),
|
|
236
|
+
parents
|
|
237
|
+
);
|
|
238
|
+
};
|
|
230
239
|
}
|
|
231
240
|
}
|
|
@@ -13,14 +13,20 @@ import {
|
|
|
13
13
|
Node,
|
|
14
14
|
ObjectExpression,
|
|
15
15
|
Property,
|
|
16
|
-
ThisExpression,
|
|
17
16
|
VariableDeclaration,
|
|
18
17
|
VariableDeclarator,
|
|
19
18
|
} from "../../util/gen";
|
|
20
19
|
import { append, prepend } from "../../util/insert";
|
|
21
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
chance,
|
|
22
|
+
choice,
|
|
23
|
+
getRandomInteger,
|
|
24
|
+
getRandomString,
|
|
25
|
+
} from "../../util/random";
|
|
22
26
|
import Transform from "../transform";
|
|
23
27
|
import Encoding from "./encoding";
|
|
28
|
+
import { ComputeProbabilityMap } from "../../probability";
|
|
29
|
+
import { BufferToStringTemplate } from "../../templates/bufferToString";
|
|
24
30
|
|
|
25
31
|
export function isModuleSource(object: Node, parents: Node[]) {
|
|
26
32
|
if (!parents[0]) {
|
|
@@ -89,13 +95,23 @@ export default class StringConcealing extends Transform {
|
|
|
89
95
|
super.apply(tree);
|
|
90
96
|
|
|
91
97
|
var cacheName = this.getPlaceholder();
|
|
98
|
+
var bufferToStringName = this.getPlaceholder();
|
|
99
|
+
|
|
100
|
+
// This helper functions convert UInt8 Array to UTf-string
|
|
101
|
+
prepend(
|
|
102
|
+
tree,
|
|
103
|
+
...BufferToStringTemplate.compile({ name: bufferToStringName })
|
|
104
|
+
);
|
|
92
105
|
|
|
93
106
|
Object.keys(this.encoding).forEach((type) => {
|
|
94
107
|
var { template } = Encoding[type];
|
|
95
108
|
var decodeFn = this.getPlaceholder();
|
|
96
109
|
var getterFn = this.encoding[type];
|
|
97
110
|
|
|
98
|
-
append(
|
|
111
|
+
append(
|
|
112
|
+
tree,
|
|
113
|
+
template.single({ name: decodeFn, bufferToString: bufferToStringName })
|
|
114
|
+
);
|
|
99
115
|
|
|
100
116
|
append(
|
|
101
117
|
tree,
|
|
@@ -165,10 +181,24 @@ export default class StringConcealing extends Transform {
|
|
|
165
181
|
return;
|
|
166
182
|
}
|
|
167
183
|
|
|
184
|
+
// Allow user to choose which strings get changed
|
|
185
|
+
if (
|
|
186
|
+
!ComputeProbabilityMap(
|
|
187
|
+
this.options.stringConcealing,
|
|
188
|
+
(x) => x,
|
|
189
|
+
object.value
|
|
190
|
+
)
|
|
191
|
+
) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// HARD CODED LIMIT of 10,000 (after 1,000 elements)
|
|
196
|
+
if (this.set.size > 1000 && !chance(this.set.size / 100)) return;
|
|
197
|
+
|
|
168
198
|
var types = Object.keys(this.encoding);
|
|
169
199
|
|
|
170
200
|
var type = choice(types);
|
|
171
|
-
if (!type || (!this.hasAllEncodings &&
|
|
201
|
+
if (!type || (!this.hasAllEncodings && chance(10))) {
|
|
172
202
|
var allowed = Object.keys(Encoding).filter(
|
|
173
203
|
(type) => !this.encoding[type]
|
|
174
204
|
);
|
|
@@ -211,23 +241,23 @@ export default class StringConcealing extends Transform {
|
|
|
211
241
|
var callExpr = CallExpression(Identifier(fnName), [Literal(index)]);
|
|
212
242
|
|
|
213
243
|
// use `.apply` to fool automated de-obfuscators
|
|
214
|
-
if (
|
|
244
|
+
if (chance(10)) {
|
|
215
245
|
callExpr = CallExpression(
|
|
216
|
-
MemberExpression(Identifier(fnName),
|
|
217
|
-
[
|
|
246
|
+
MemberExpression(Identifier(fnName), Literal("apply"), true),
|
|
247
|
+
[Identifier("undefined"), ArrayExpression([Literal(index)])]
|
|
218
248
|
);
|
|
219
249
|
}
|
|
220
250
|
|
|
221
251
|
// use `.call`
|
|
222
|
-
else if (
|
|
252
|
+
else if (chance(10)) {
|
|
223
253
|
callExpr = CallExpression(
|
|
224
|
-
MemberExpression(Identifier(fnName),
|
|
225
|
-
[
|
|
254
|
+
MemberExpression(Identifier(fnName), Literal("call"), true),
|
|
255
|
+
[Identifier("undefined"), Literal(index)]
|
|
226
256
|
);
|
|
227
257
|
}
|
|
228
258
|
|
|
229
259
|
var referenceType = "call";
|
|
230
|
-
if (parents.length &&
|
|
260
|
+
if (parents.length && chance(50 - this.variablesMade)) {
|
|
231
261
|
referenceType = "constantReference";
|
|
232
262
|
}
|
|
233
263
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import Transform from "../transform";
|
|
2
2
|
import { choice } from "../../util/random";
|
|
3
|
-
import { ObfuscateOrder } from "../../order";
|
|
4
3
|
import { isDirective } from "../../util/compare";
|
|
5
4
|
import { isModuleSource } from "./stringConcealing";
|
|
5
|
+
import { ComputeProbabilityMap } from "../../probability";
|
|
6
|
+
import { Identifier } from "../../util/gen";
|
|
6
7
|
|
|
7
8
|
function pad(x: string, len: number): string {
|
|
8
9
|
while (x.length < len) {
|
|
@@ -54,32 +55,30 @@ function toUnicodeRepresentation(str: string) {
|
|
|
54
55
|
* - Cost Low
|
|
55
56
|
*/
|
|
56
57
|
export default class StringEncoding extends Transform {
|
|
57
|
-
seen: Set<Node>;
|
|
58
|
-
|
|
59
58
|
constructor(o) {
|
|
60
|
-
super(o
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
apply(tree) {
|
|
64
|
-
this.seen = new Set();
|
|
65
|
-
super.apply(tree);
|
|
59
|
+
super(o);
|
|
66
60
|
}
|
|
67
61
|
|
|
68
62
|
match(object, parents) {
|
|
69
63
|
return (
|
|
70
64
|
object.type == "Literal" &&
|
|
71
65
|
typeof object.value === "string" &&
|
|
66
|
+
object.value.length > 0 &&
|
|
72
67
|
!isModuleSource(object, parents) &&
|
|
73
68
|
!isDirective(object, parents)
|
|
74
69
|
);
|
|
75
70
|
}
|
|
76
71
|
|
|
77
72
|
transform(object, parents) {
|
|
78
|
-
//
|
|
79
|
-
if (
|
|
73
|
+
// Allow percentages
|
|
74
|
+
if (
|
|
75
|
+
!ComputeProbabilityMap(
|
|
76
|
+
this.options.stringEncoding,
|
|
77
|
+
(x) => x,
|
|
78
|
+
object.value
|
|
79
|
+
)
|
|
80
|
+
)
|
|
80
81
|
return;
|
|
81
|
-
}
|
|
82
|
-
this.seen.add(object);
|
|
83
82
|
|
|
84
83
|
var type = choice(["hexadecimal", "unicode"]);
|
|
85
84
|
|
|
@@ -87,10 +86,11 @@ export default class StringEncoding extends Transform {
|
|
|
87
86
|
type == "hexadecimal" ? toHexRepresentation : toUnicodeRepresentation
|
|
88
87
|
)(object.value);
|
|
89
88
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
89
|
+
return () => {
|
|
90
|
+
if (object.type !== "Literal") return;
|
|
91
|
+
|
|
92
|
+
// ESCodeGen tries to escape backslashes, here is a work-around
|
|
93
|
+
this.replace(object, Identifier(`'${escapedString}'`));
|
|
94
|
+
};
|
|
95
95
|
}
|
|
96
96
|
}
|
|
@@ -74,11 +74,6 @@ export default class Transform {
|
|
|
74
74
|
*/
|
|
75
75
|
after: Transform[];
|
|
76
76
|
|
|
77
|
-
/**
|
|
78
|
-
* Transformations to run at the same time (can cause conflicts so use sparingly)
|
|
79
|
-
*/
|
|
80
|
-
concurrent: Transform[];
|
|
81
|
-
|
|
82
77
|
constructor(obfuscator, priority: number = -1) {
|
|
83
78
|
ok(obfuscator instanceof Obfuscator, "obfuscator should be an Obfuscator");
|
|
84
79
|
|
|
@@ -89,8 +84,6 @@ export default class Transform {
|
|
|
89
84
|
|
|
90
85
|
this.before = [];
|
|
91
86
|
this.after = [];
|
|
92
|
-
|
|
93
|
-
this.concurrent = [];
|
|
94
87
|
}
|
|
95
88
|
|
|
96
89
|
/**
|
|
@@ -120,14 +113,11 @@ export default class Transform {
|
|
|
120
113
|
*/
|
|
121
114
|
this.before.forEach((x) => x.apply(tree));
|
|
122
115
|
|
|
116
|
+
/**
|
|
117
|
+
* Run this transformation
|
|
118
|
+
*/
|
|
123
119
|
traverse(tree, (object, parents) => {
|
|
124
|
-
|
|
125
|
-
fns.push(this.input(object, parents));
|
|
126
|
-
|
|
127
|
-
// Fix 1. Increase performance with multiple transforms on one iteration.
|
|
128
|
-
this.concurrent.forEach((x) => fns.push(x.input(object, parents)));
|
|
129
|
-
|
|
130
|
-
return () => fns.forEach((x) => x && x());
|
|
120
|
+
return this.input(object, parents);
|
|
131
121
|
});
|
|
132
122
|
|
|
133
123
|
/**
|
|
@@ -191,18 +181,18 @@ export default class Transform {
|
|
|
191
181
|
|
|
192
182
|
/**
|
|
193
183
|
* Returns an independent name generator with it's own counter.
|
|
194
|
-
* @param
|
|
184
|
+
* @param overrideMode - Override the user's `identifierGenerator` option
|
|
195
185
|
* @returns
|
|
196
186
|
*/
|
|
197
|
-
getGenerator(
|
|
198
|
-
var count =
|
|
187
|
+
getGenerator(overrideMode?: string) {
|
|
188
|
+
var count = 0;
|
|
199
189
|
var identifiers = new Set();
|
|
200
190
|
return {
|
|
201
191
|
generate: () => {
|
|
202
|
-
var retValue;
|
|
192
|
+
var retValue: string;
|
|
203
193
|
do {
|
|
204
194
|
count++;
|
|
205
|
-
retValue = this.generateIdentifier(-1, count);
|
|
195
|
+
retValue = this.generateIdentifier(-1, count, overrideMode);
|
|
206
196
|
} while (identifiers.has(retValue));
|
|
207
197
|
|
|
208
198
|
identifiers.add(retValue);
|
|
@@ -217,7 +207,11 @@ export default class Transform {
|
|
|
217
207
|
* @param length Default length is 6 to 10 characters.
|
|
218
208
|
* @returns **`string`**
|
|
219
209
|
*/
|
|
220
|
-
generateIdentifier(
|
|
210
|
+
generateIdentifier(
|
|
211
|
+
length: number = -1,
|
|
212
|
+
count = -1,
|
|
213
|
+
overrideMode?: string
|
|
214
|
+
): string {
|
|
221
215
|
if (length == -1) {
|
|
222
216
|
length = getRandomInteger(6, 8);
|
|
223
217
|
}
|
|
@@ -233,7 +227,7 @@ export default class Transform {
|
|
|
233
227
|
var identifier;
|
|
234
228
|
do {
|
|
235
229
|
identifier = ComputeProbabilityMap(
|
|
236
|
-
this.options.identifierGenerator,
|
|
230
|
+
overrideMode || this.options.identifierGenerator,
|
|
237
231
|
(mode = "randomized") => {
|
|
238
232
|
switch (mode) {
|
|
239
233
|
case "randomized":
|
package/src/traverse.ts
CHANGED
|
@@ -39,21 +39,14 @@ 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
|
-
if (!Array.isArray(object)) {
|
|
55
|
-
|
|
56
|
-
}
|
|
47
|
+
// if (!Array.isArray(object)) {
|
|
48
|
+
// validateChain(object, parents);
|
|
49
|
+
// }
|
|
57
50
|
|
|
58
51
|
// 1. Call `onEnter` function and remember any onExit callback returned
|
|
59
52
|
var onExit = onEnter(object as Node, parents);
|
|
@@ -66,7 +59,6 @@ export function walk(
|
|
|
66
59
|
return "EXIT";
|
|
67
60
|
}
|
|
68
61
|
}
|
|
69
|
-
copy.forEach((x) => {});
|
|
70
62
|
} else {
|
|
71
63
|
var keys = Object.keys(object);
|
|
72
64
|
for (var key of keys) {
|
|
@@ -106,3 +98,23 @@ export function walk(
|
|
|
106
98
|
export default function traverse(tree, onEnter: EnterCallback) {
|
|
107
99
|
walk(tree, [], onEnter);
|
|
108
100
|
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* This is debugging function used to test for circular references.
|
|
104
|
+
*/
|
|
105
|
+
export function assertNoCircular(object) {
|
|
106
|
+
var seen = new Set();
|
|
107
|
+
|
|
108
|
+
traverse(object, (node, nodeParents) => {
|
|
109
|
+
if (node && typeof node === "object") {
|
|
110
|
+
if (seen.has(node)) {
|
|
111
|
+
console.log(nodeParents);
|
|
112
|
+
console.log(node);
|
|
113
|
+
|
|
114
|
+
throw new Error("FOUND CIRCULAR REFERENCE");
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
seen.add(node);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -118,5 +118,14 @@ export type IJsConfuserDebugTransformations = (
|
|
|
118
118
|
export type IJsConfuserDebugObfuscation = (
|
|
119
119
|
code: string,
|
|
120
120
|
options: ObfuscateOptions,
|
|
121
|
-
callback: (name: string, complete: number, totalTransforms: number) => void
|
|
122
|
-
|
|
121
|
+
callback: (name: string, complete: number, totalTransforms: number) => void,
|
|
122
|
+
performance: Performance
|
|
123
|
+
) => Promise<{
|
|
124
|
+
obfuscated: string;
|
|
125
|
+
transformationTimes: { [transformName: string]: number };
|
|
126
|
+
parseTime: number;
|
|
127
|
+
compileTime: number;
|
|
128
|
+
obfuscationTime: number;
|
|
129
|
+
totalTransforms: number;
|
|
130
|
+
totalPossibleTransforms: number;
|
|
131
|
+
}>;
|
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/gen.ts
CHANGED
|
@@ -557,6 +557,22 @@ export function ClassDeclaration(
|
|
|
557
557
|
} as Node;
|
|
558
558
|
}
|
|
559
559
|
|
|
560
|
+
export function ClassExpression(
|
|
561
|
+
id: Node | null,
|
|
562
|
+
superClass: Node = null,
|
|
563
|
+
body: Node[] = []
|
|
564
|
+
) {
|
|
565
|
+
return {
|
|
566
|
+
type: "ClassExpression",
|
|
567
|
+
id: id,
|
|
568
|
+
superClass: superClass,
|
|
569
|
+
body: {
|
|
570
|
+
type: "ClassBody",
|
|
571
|
+
body: body,
|
|
572
|
+
},
|
|
573
|
+
} as Node;
|
|
574
|
+
}
|
|
575
|
+
|
|
560
576
|
export function ThrowStatement(argument: Node) {
|
|
561
577
|
return {
|
|
562
578
|
type: "ThrowStatement",
|
|
@@ -607,7 +623,11 @@ export function CatchClause(param: Node = null, body) {
|
|
|
607
623
|
};
|
|
608
624
|
}
|
|
609
625
|
|
|
610
|
-
export function TryStatement(
|
|
626
|
+
export function TryStatement(
|
|
627
|
+
body: Node[],
|
|
628
|
+
handler: Node,
|
|
629
|
+
finallyBody?: Node[]
|
|
630
|
+
) {
|
|
611
631
|
ok(handler);
|
|
612
632
|
ok(handler.type == "CatchClause");
|
|
613
633
|
return {
|
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,18 +261,38 @@ 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);
|
|
283
|
+
} else if (block.type === "SwitchCase") {
|
|
284
|
+
block.consequent.unshift(...nodes);
|
|
268
285
|
} else {
|
|
269
|
-
getBlockBody(block)
|
|
286
|
+
var bodyArray = getBlockBody(block);
|
|
287
|
+
|
|
288
|
+
// Check for 'use strict'
|
|
289
|
+
if (bodyArray[0] && bodyArray[0].directive) {
|
|
290
|
+
// Insert under 'use strict' directive
|
|
291
|
+
bodyArray.splice(1, 0, ...nodes);
|
|
292
|
+
} else {
|
|
293
|
+
// Prepend at the top of the block
|
|
294
|
+
bodyArray.unshift(...nodes);
|
|
295
|
+
}
|
|
270
296
|
}
|
|
271
297
|
}
|
|
272
298
|
|
|
@@ -313,7 +339,10 @@ export function clone<T>(object: T): T {
|
|
|
313
339
|
* @param p
|
|
314
340
|
* @returns
|
|
315
341
|
*/
|
|
316
|
-
export function isForInitialize(
|
|
342
|
+
export function isForInitialize(
|
|
343
|
+
o: Node,
|
|
344
|
+
p: Node[]
|
|
345
|
+
): "initializer" | "left-hand" | false {
|
|
317
346
|
validateChain(o, p);
|
|
318
347
|
|
|
319
348
|
var forIndex = p.findIndex(
|
|
@@ -322,6 +351,17 @@ export function isForInitialize(o, p): "initializer" | "left-hand" | false {
|
|
|
322
351
|
x.type == "ForInStatement" ||
|
|
323
352
|
x.type == "ForOfStatement"
|
|
324
353
|
);
|
|
354
|
+
|
|
355
|
+
if (
|
|
356
|
+
p
|
|
357
|
+
.slice(0, forIndex)
|
|
358
|
+
.find((x) =>
|
|
359
|
+
["ArrowFunctionExpression", "BlockStatement"].includes(x.type)
|
|
360
|
+
)
|
|
361
|
+
) {
|
|
362
|
+
return false;
|
|
363
|
+
}
|
|
364
|
+
|
|
325
365
|
if (forIndex !== -1) {
|
|
326
366
|
if (p[forIndex].type == "ForStatement") {
|
|
327
367
|
if (p[forIndex].init == (p[forIndex - 1] || o)) {
|
package/src/util/random.ts
CHANGED
|
@@ -8,11 +8,24 @@ import {
|
|
|
8
8
|
ArrayExpression,
|
|
9
9
|
} from "./gen";
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Returns a random element from the given array
|
|
13
|
+
* @param choices Array of items
|
|
14
|
+
* @returns One of the items in the array at random
|
|
15
|
+
*/
|
|
11
16
|
export function choice<T>(choices: T[]): T {
|
|
12
17
|
var index = Math.floor(Math.random() * choices.length);
|
|
13
18
|
return choices[index];
|
|
14
19
|
}
|
|
15
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Returns a true/false based on the percent chance (0%-100%)
|
|
23
|
+
* @param percentChance AS A PERCENTAGE 0 - 100%
|
|
24
|
+
*/
|
|
25
|
+
export function chance(percentChance: number): boolean {
|
|
26
|
+
return Math.random() < percentChance / 100;
|
|
27
|
+
}
|
|
28
|
+
|
|
16
29
|
/**
|
|
17
30
|
* **Mutates the given array**
|
|
18
31
|
* @param array
|
package/test/code/Cash.test.ts
CHANGED
|
@@ -4,7 +4,7 @@ import JsConfuser from "../../src/index";
|
|
|
4
4
|
|
|
5
5
|
var CASH_JS = readFileSync(join(__dirname, "./Cash.src.js"), "utf-8");
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
test("Variant #1: Cash.js on High Preset (Strict Mode)", async () => {
|
|
8
8
|
var output = await JsConfuser(CASH_JS, {
|
|
9
9
|
target: "browser",
|
|
10
10
|
preset: "high",
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { readFileSync, writeFileSync } from "fs";
|
|
2
2
|
import { join } from "path";
|
|
3
3
|
import JsConfuser from "../../src/index";
|
|
4
|
+
import { ObfuscateOptions } from "../../src/options";
|
|
4
5
|
|
|
5
6
|
var SOURCE_JS = readFileSync(join(__dirname, "./Dynamic.src.js"), "utf-8");
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
test.concurrent("Variant #1: Dynamic.src.js on High Preset", async () => {
|
|
8
9
|
// `input` is an embedded variable, therefore globalConcealing must be turned off
|
|
9
10
|
var output = await JsConfuser(SOURCE_JS, {
|
|
10
11
|
target: "browser",
|
|
@@ -22,19 +23,20 @@ it("works on High Preset", async () => {
|
|
|
22
23
|
expect(value).toStrictEqual(1738.1738);
|
|
23
24
|
});
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
var output = await JsConfuser(SOURCE_JS, {
|
|
26
|
+
test.concurrent("Variant #2: Dynamic.src.js on 2x High Preset", async () => {
|
|
27
|
+
var options: ObfuscateOptions = {
|
|
28
28
|
target: "node",
|
|
29
29
|
preset: "high",
|
|
30
30
|
globalConcealing: false,
|
|
31
|
-
}
|
|
31
|
+
};
|
|
32
32
|
|
|
33
|
-
var
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
var output = await JsConfuser(SOURCE_JS, options);
|
|
34
|
+
|
|
35
|
+
// writeFileSync("./dev.error.1.js", output, "utf-8");
|
|
36
|
+
|
|
37
|
+
var doublyObfuscated = await JsConfuser(output, options);
|
|
38
|
+
|
|
39
|
+
// writeFileSync("./dev.error.2.js", doublyObfuscated, "utf-8");
|
|
38
40
|
|
|
39
41
|
var value = "never_called";
|
|
40
42
|
function input(x) {
|