js-confuser 1.5.9 → 1.7.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 +55 -0
- package/README.md +346 -165
- package/dist/constants.js +6 -2
- package/dist/index.js +9 -21
- package/dist/obfuscator.js +19 -31
- package/dist/options.js +5 -5
- package/dist/order.js +1 -3
- package/dist/presets.js +6 -7
- package/dist/probability.js +2 -4
- package/dist/templates/bufferToString.js +13 -0
- package/dist/templates/crash.js +3 -3
- package/dist/templates/es5.js +18 -0
- package/dist/templates/functionLength.js +16 -0
- package/dist/transforms/calculator.js +77 -21
- package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +980 -367
- package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +4 -1
- package/dist/transforms/controlFlowFlattening/switchCaseObfuscation.js +25 -26
- package/dist/transforms/deadCode.js +33 -25
- package/dist/transforms/dispatcher.js +8 -4
- package/dist/transforms/es5/antiDestructuring.js +2 -0
- package/dist/transforms/es5/es5.js +31 -34
- package/dist/transforms/extraction/duplicateLiteralsRemoval.js +92 -58
- package/dist/transforms/finalizer.js +82 -0
- package/dist/transforms/flatten.js +229 -148
- package/dist/transforms/identifier/globalAnalysis.js +88 -0
- package/dist/transforms/identifier/globalConcealing.js +10 -83
- package/dist/transforms/identifier/movedDeclarations.js +35 -88
- package/dist/transforms/identifier/renameVariables.js +124 -59
- package/dist/transforms/identifier/variableAnalysis.js +58 -62
- package/dist/transforms/lock/lock.js +0 -37
- package/dist/transforms/minify.js +60 -57
- 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 +139 -247
- package/dist/transforms/stack.js +128 -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 +12 -19
- package/dist/traverse.js +24 -10
- package/dist/util/gen.js +17 -1
- package/dist/util/identifiers.js +37 -3
- package/dist/util/insert.js +35 -4
- package/dist/util/random.js +15 -0
- package/docs/ControlFlowFlattening.md +595 -0
- package/{Countermeasures.md → docs/Countermeasures.md} +1 -15
- package/{Integrity.md → docs/Integrity.md} +2 -2
- package/docs/RGF.md +419 -0
- package/package.json +5 -5
- package/src/constants.ts +3 -0
- package/src/index.ts +2 -2
- package/src/obfuscator.ts +19 -31
- package/src/options.ts +14 -103
- package/src/order.ts +1 -5
- package/src/presets.ts +6 -7
- package/src/probability.ts +2 -3
- package/src/templates/bufferToString.ts +68 -0
- package/src/templates/crash.ts +15 -19
- package/src/templates/es5.ts +131 -0
- package/src/templates/functionLength.ts +14 -0
- package/src/transforms/calculator.ts +122 -59
- package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +1583 -571
- package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +4 -1
- package/src/transforms/deadCode.ts +383 -26
- package/src/transforms/dispatcher.ts +9 -4
- package/src/transforms/es5/antiDestructuring.ts +2 -0
- package/src/transforms/es5/es5.ts +32 -77
- package/src/transforms/extraction/duplicateLiteralsRemoval.ts +133 -129
- package/src/transforms/{hexadecimalNumbers.ts → finalizer.ts} +29 -13
- package/src/transforms/flatten.ts +357 -300
- package/src/transforms/identifier/globalAnalysis.ts +85 -0
- package/src/transforms/identifier/globalConcealing.ts +14 -103
- package/src/transforms/identifier/movedDeclarations.ts +49 -102
- package/src/transforms/identifier/renameVariables.ts +149 -78
- package/src/transforms/identifier/variableAnalysis.ts +66 -73
- package/src/transforms/lock/lock.ts +1 -42
- package/src/transforms/minify.ts +91 -75
- 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 +213 -405
- package/src/transforms/stack.ts +156 -36
- package/src/transforms/string/encoding.ts +115 -212
- package/src/transforms/string/stringCompression.ts +27 -18
- package/src/transforms/string/stringConcealing.ts +39 -9
- package/src/transforms/string/stringEncoding.ts +18 -18
- package/src/transforms/transform.ts +21 -23
- package/src/traverse.ts +23 -4
- package/src/types.ts +2 -1
- package/src/util/gen.ts +28 -3
- package/src/util/identifiers.ts +43 -2
- package/src/util/insert.ts +38 -3
- 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 +146 -0
- package/test/code/ES6.test.ts +28 -2
- package/test/index.test.ts +2 -1
- package/test/probability.test.ts +44 -0
- package/test/templates/template.test.ts +1 -1
- package/test/transforms/antiTooling.test.ts +22 -0
- package/test/transforms/calculator.test.ts +40 -0
- package/test/transforms/controlFlowFlattening/controlFlowFlattening.test.ts +702 -160
- package/test/transforms/controlFlowFlattening/expressionObfuscation.test.ts +173 -0
- package/test/transforms/deadCode.test.ts +66 -15
- package/test/transforms/dispatcher.test.ts +20 -1
- package/test/transforms/es5/antiDestructuring.test.ts +16 -0
- package/test/transforms/flatten.test.ts +399 -86
- package/test/transforms/identifier/movedDeclarations.test.ts +63 -8
- package/test/transforms/identifier/renameVariables.test.ts +119 -0
- package/test/transforms/lock/antiDebug.test.ts +2 -2
- package/test/transforms/lock/lock.test.ts +1 -48
- package/test/transforms/minify.test.ts +104 -0
- package/test/transforms/preparation.test.ts +157 -0
- package/test/transforms/rgf.test.ts +261 -381
- package/test/transforms/stack.test.ts +143 -21
- package/test/transforms/string/stringCompression.test.ts +39 -0
- package/test/transforms/string/stringConcealing.test.ts +82 -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/identifiers.test.ts +113 -1
- package/test/util/insert.test.ts +57 -3
- 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/eval.ts +0 -89
- package/src/transforms/hideInitializingCode.ts +0 -432
- package/src/transforms/identifier/nameRecycling.ts +0 -280
- 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/eval.test.ts +0 -131
- package/test/transforms/hideInitializingCode.test.ts +0 -336
- package/test/transforms/identifier/nameRecycling.test.ts +0 -205
- 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),
|
|
246
|
+
MemberExpression(Identifier(fnName), Literal("apply"), true),
|
|
217
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),
|
|
254
|
+
MemberExpression(Identifier(fnName), Literal("call"), true),
|
|
225
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
|
}
|
|
@@ -9,7 +9,11 @@ import { ok } from "assert";
|
|
|
9
9
|
import Obfuscator from "../obfuscator";
|
|
10
10
|
import { ObfuscateOptions } from "../options";
|
|
11
11
|
import { ComputeProbabilityMap } from "../probability";
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
placeholderVariablePrefix,
|
|
14
|
+
reservedIdentifiers,
|
|
15
|
+
reservedKeywords,
|
|
16
|
+
} from "../constants";
|
|
13
17
|
import { ObfuscateOrder } from "../order";
|
|
14
18
|
|
|
15
19
|
/**
|
|
@@ -74,11 +78,6 @@ export default class Transform {
|
|
|
74
78
|
*/
|
|
75
79
|
after: Transform[];
|
|
76
80
|
|
|
77
|
-
/**
|
|
78
|
-
* Transformations to run at the same time (can cause conflicts so use sparingly)
|
|
79
|
-
*/
|
|
80
|
-
concurrent: Transform[];
|
|
81
|
-
|
|
82
81
|
constructor(obfuscator, priority: number = -1) {
|
|
83
82
|
ok(obfuscator instanceof Obfuscator, "obfuscator should be an Obfuscator");
|
|
84
83
|
|
|
@@ -89,8 +88,6 @@ export default class Transform {
|
|
|
89
88
|
|
|
90
89
|
this.before = [];
|
|
91
90
|
this.after = [];
|
|
92
|
-
|
|
93
|
-
this.concurrent = [];
|
|
94
91
|
}
|
|
95
92
|
|
|
96
93
|
/**
|
|
@@ -120,14 +117,11 @@ export default class Transform {
|
|
|
120
117
|
*/
|
|
121
118
|
this.before.forEach((x) => x.apply(tree));
|
|
122
119
|
|
|
120
|
+
/**
|
|
121
|
+
* Run this transformation
|
|
122
|
+
*/
|
|
123
123
|
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());
|
|
124
|
+
return this.input(object, parents);
|
|
131
125
|
});
|
|
132
126
|
|
|
133
127
|
/**
|
|
@@ -186,23 +180,23 @@ export default class Transform {
|
|
|
186
180
|
[...Array(size)]
|
|
187
181
|
.map(() => Math.floor(Math.random() * 10).toString(10))
|
|
188
182
|
.join("");
|
|
189
|
-
return
|
|
183
|
+
return placeholderVariablePrefix + genRanHex(10);
|
|
190
184
|
}
|
|
191
185
|
|
|
192
186
|
/**
|
|
193
187
|
* Returns an independent name generator with it's own counter.
|
|
194
|
-
* @param
|
|
188
|
+
* @param overrideMode - Override the user's `identifierGenerator` option
|
|
195
189
|
* @returns
|
|
196
190
|
*/
|
|
197
|
-
getGenerator(
|
|
198
|
-
var count =
|
|
191
|
+
getGenerator(overrideMode?: string) {
|
|
192
|
+
var count = 0;
|
|
199
193
|
var identifiers = new Set();
|
|
200
194
|
return {
|
|
201
195
|
generate: () => {
|
|
202
|
-
var retValue;
|
|
196
|
+
var retValue: string;
|
|
203
197
|
do {
|
|
204
198
|
count++;
|
|
205
|
-
retValue = this.generateIdentifier(-1, count);
|
|
199
|
+
retValue = this.generateIdentifier(-1, count, overrideMode);
|
|
206
200
|
} while (identifiers.has(retValue));
|
|
207
201
|
|
|
208
202
|
identifiers.add(retValue);
|
|
@@ -217,7 +211,11 @@ export default class Transform {
|
|
|
217
211
|
* @param length Default length is 6 to 10 characters.
|
|
218
212
|
* @returns **`string`**
|
|
219
213
|
*/
|
|
220
|
-
generateIdentifier(
|
|
214
|
+
generateIdentifier(
|
|
215
|
+
length: number = -1,
|
|
216
|
+
count = -1,
|
|
217
|
+
overrideMode?: string
|
|
218
|
+
): string {
|
|
221
219
|
if (length == -1) {
|
|
222
220
|
length = getRandomInteger(6, 8);
|
|
223
221
|
}
|
|
@@ -233,7 +231,7 @@ export default class Transform {
|
|
|
233
231
|
var identifier;
|
|
234
232
|
do {
|
|
235
233
|
identifier = ComputeProbabilityMap(
|
|
236
|
-
this.options.identifierGenerator,
|
|
234
|
+
overrideMode || this.options.identifierGenerator,
|
|
237
235
|
(mode = "randomized") => {
|
|
238
236
|
switch (mode) {
|
|
239
237
|
case "randomized":
|
package/src/traverse.ts
CHANGED
|
@@ -44,9 +44,9 @@ export function walk(
|
|
|
44
44
|
if (typeof object === "object" && object) {
|
|
45
45
|
var newParents: Node[] = [object as Node, ...parents];
|
|
46
46
|
|
|
47
|
-
if (!Array.isArray(object)) {
|
|
48
|
-
|
|
49
|
-
}
|
|
47
|
+
// if (!Array.isArray(object)) {
|
|
48
|
+
// validateChain(object, parents);
|
|
49
|
+
// }
|
|
50
50
|
|
|
51
51
|
// 1. Call `onEnter` function and remember any onExit callback returned
|
|
52
52
|
var onExit = onEnter(object as Node, parents);
|
|
@@ -59,7 +59,6 @@ export function walk(
|
|
|
59
59
|
return "EXIT";
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
|
-
copy.forEach((x) => {});
|
|
63
62
|
} else {
|
|
64
63
|
var keys = Object.keys(object);
|
|
65
64
|
for (var key of keys) {
|
|
@@ -99,3 +98,23 @@ export function walk(
|
|
|
99
98
|
export default function traverse(tree, onEnter: EnterCallback) {
|
|
100
99
|
walk(tree, [], onEnter);
|
|
101
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,7 +118,8 @@ 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
|
|
121
|
+
callback: (name: string, complete: number, totalTransforms: number) => void,
|
|
122
|
+
performance: Performance
|
|
122
123
|
) => Promise<{
|
|
123
124
|
obfuscated: string;
|
|
124
125
|
transformationTimes: { [transformName: string]: number };
|
package/src/util/gen.ts
CHANGED
|
@@ -171,7 +171,12 @@ export function BreakStatement(label?: string) {
|
|
|
171
171
|
};
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
-
export function Property(
|
|
174
|
+
export function Property(
|
|
175
|
+
key: Node,
|
|
176
|
+
value: Node,
|
|
177
|
+
computed = false,
|
|
178
|
+
kind: "init" | "set" | "get" = "init"
|
|
179
|
+
) {
|
|
175
180
|
if (!key) {
|
|
176
181
|
throw new Error("key is undefined");
|
|
177
182
|
}
|
|
@@ -183,7 +188,7 @@ export function Property(key: Node, value: Node, computed = false) {
|
|
|
183
188
|
key: key,
|
|
184
189
|
computed: computed,
|
|
185
190
|
value: value,
|
|
186
|
-
kind:
|
|
191
|
+
kind: kind,
|
|
187
192
|
method: false,
|
|
188
193
|
shorthand: false,
|
|
189
194
|
};
|
|
@@ -557,6 +562,22 @@ export function ClassDeclaration(
|
|
|
557
562
|
} as Node;
|
|
558
563
|
}
|
|
559
564
|
|
|
565
|
+
export function ClassExpression(
|
|
566
|
+
id: Node | null,
|
|
567
|
+
superClass: Node = null,
|
|
568
|
+
body: Node[] = []
|
|
569
|
+
) {
|
|
570
|
+
return {
|
|
571
|
+
type: "ClassExpression",
|
|
572
|
+
id: id,
|
|
573
|
+
superClass: superClass,
|
|
574
|
+
body: {
|
|
575
|
+
type: "ClassBody",
|
|
576
|
+
body: body,
|
|
577
|
+
},
|
|
578
|
+
} as Node;
|
|
579
|
+
}
|
|
580
|
+
|
|
560
581
|
export function ThrowStatement(argument: Node) {
|
|
561
582
|
return {
|
|
562
583
|
type: "ThrowStatement",
|
|
@@ -607,7 +628,11 @@ export function CatchClause(param: Node = null, body) {
|
|
|
607
628
|
};
|
|
608
629
|
}
|
|
609
630
|
|
|
610
|
-
export function TryStatement(
|
|
631
|
+
export function TryStatement(
|
|
632
|
+
body: Node[],
|
|
633
|
+
handler: Node,
|
|
634
|
+
finallyBody?: Node[]
|
|
635
|
+
) {
|
|
611
636
|
ok(handler);
|
|
612
637
|
ok(handler.type == "CatchClause");
|
|
613
638
|
return {
|
package/src/util/identifiers.ts
CHANGED
|
@@ -30,6 +30,23 @@ export function validateChain(object: Node, parents: Node[]) {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
function objectPatternCheck(object: Node, parents: Node[]) {
|
|
34
|
+
var objectPatternIndex = parents.findIndex((x) => x.type === "ObjectPattern");
|
|
35
|
+
if (objectPatternIndex == -1) {
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
var property = parents[objectPatternIndex].properties.find(
|
|
40
|
+
(property) => parents[objectPatternIndex - 2] === property
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
if (property.key === (parents[objectPatternIndex - 3] || object)) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
|
|
33
50
|
/**
|
|
34
51
|
* Returns detailed information about the given Identifier node.
|
|
35
52
|
* @param object
|
|
@@ -74,7 +91,22 @@ export function getIdentifierInfo(object: Node, parents: Node[]) {
|
|
|
74
91
|
var isVariableDeclaration =
|
|
75
92
|
varIndex != -1 &&
|
|
76
93
|
parents[varIndex].id == (parents[varIndex - 1] || object) &&
|
|
77
|
-
parents.find((x) => x.type == "VariableDeclaration")
|
|
94
|
+
parents.find((x) => x.type == "VariableDeclaration") &&
|
|
95
|
+
objectPatternCheck(object, parents);
|
|
96
|
+
|
|
97
|
+
// Assignment pattern check!
|
|
98
|
+
if (isVariableDeclaration) {
|
|
99
|
+
var slicedParents = parents.slice(0, varIndex - 1);
|
|
100
|
+
var i = 0;
|
|
101
|
+
for (var parent of slicedParents) {
|
|
102
|
+
var childNode = slicedParents[i - 1] || object;
|
|
103
|
+
if (parent.type === "AssignmentPattern" && parent.right === childNode) {
|
|
104
|
+
isVariableDeclaration = false;
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
i++;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
78
110
|
|
|
79
111
|
var forIndex = parents.findIndex((x) => x.type == "ForStatement");
|
|
80
112
|
var isForInitializer =
|
|
@@ -87,6 +119,12 @@ export function getIdentifierInfo(object: Node, parents: Node[]) {
|
|
|
87
119
|
functionIndex != -1 &&
|
|
88
120
|
parents[functionIndex].type == "FunctionDeclaration" &&
|
|
89
121
|
parents[functionIndex].id == object;
|
|
122
|
+
|
|
123
|
+
var isNamedFunctionExpression =
|
|
124
|
+
functionIndex != -1 &&
|
|
125
|
+
parents[functionIndex].type === "FunctionExpression" &&
|
|
126
|
+
parents[functionIndex].id === object;
|
|
127
|
+
|
|
90
128
|
var isAFunctionParameter = isFunctionParameter(object, parents);
|
|
91
129
|
|
|
92
130
|
var isClauseParameter = false;
|
|
@@ -112,7 +150,9 @@ export function getIdentifierInfo(object: Node, parents: Node[]) {
|
|
|
112
150
|
|
|
113
151
|
var isAssignmentLeft =
|
|
114
152
|
assignmentIndex !== -1 &&
|
|
115
|
-
parents[assignmentIndex].left ===
|
|
153
|
+
parents[assignmentIndex].left ===
|
|
154
|
+
(parents[assignmentIndex - 1] || object) &&
|
|
155
|
+
objectPatternCheck(object, parents);
|
|
116
156
|
var isAssignmentValue =
|
|
117
157
|
assignmentIndex !== -1 &&
|
|
118
158
|
parents[assignmentIndex].right === (parents[assignmentIndex - 1] || object);
|
|
@@ -272,6 +312,7 @@ export function getIdentifierInfo(object: Node, parents: Node[]) {
|
|
|
272
312
|
isDefined:
|
|
273
313
|
isVariableDeclaration ||
|
|
274
314
|
isFunctionDeclaration ||
|
|
315
|
+
isNamedFunctionExpression ||
|
|
275
316
|
isAFunctionParameter ||
|
|
276
317
|
isClassDeclaration ||
|
|
277
318
|
isClauseParameter ||
|
package/src/util/insert.ts
CHANGED
|
@@ -145,13 +145,13 @@ export function getAllDefiningContexts(o: Node, p: Node[]): Node[] {
|
|
|
145
145
|
// Get Function
|
|
146
146
|
var fn = getFunction(o, p);
|
|
147
147
|
|
|
148
|
-
contexts.push(fn.body);
|
|
148
|
+
// contexts.push(fn.body);
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
if (info.isClauseParameter) {
|
|
152
152
|
var catchClause = p.find((x) => x.type === "CatchClause");
|
|
153
153
|
if (catchClause) {
|
|
154
|
-
|
|
154
|
+
return [catchClause];
|
|
155
155
|
}
|
|
156
156
|
}
|
|
157
157
|
|
|
@@ -280,8 +280,19 @@ export function prepend(block: Node, ...nodes: Node[]) {
|
|
|
280
280
|
});
|
|
281
281
|
|
|
282
282
|
block.body.splice(moveBy, 0, ...nodes);
|
|
283
|
+
} else if (block.type === "SwitchCase") {
|
|
284
|
+
block.consequent.unshift(...nodes);
|
|
283
285
|
} else {
|
|
284
|
-
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
|
+
}
|
|
285
296
|
}
|
|
286
297
|
}
|
|
287
298
|
|
|
@@ -365,3 +376,27 @@ export function isForInitialize(
|
|
|
365
376
|
|
|
366
377
|
return false;
|
|
367
378
|
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Computes the `function.length` property given the parameter nodes.
|
|
382
|
+
*
|
|
383
|
+
* @param params
|
|
384
|
+
* @returns
|
|
385
|
+
*/
|
|
386
|
+
export function computeFunctionLength(params: Node[]): number {
|
|
387
|
+
var count = 0;
|
|
388
|
+
|
|
389
|
+
for (var parameterNode of params) {
|
|
390
|
+
if (
|
|
391
|
+
parameterNode.type === "Identifier" ||
|
|
392
|
+
parameterNode.type === "ObjectPattern" ||
|
|
393
|
+
parameterNode.type === "ArrayPattern"
|
|
394
|
+
) {
|
|
395
|
+
count++;
|
|
396
|
+
} else {
|
|
397
|
+
break;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
return count;
|
|
402
|
+
}
|
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",
|