js-confuser 1.4.1 → 1.5.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/CHANGELOG.md +27 -0
- package/README.md +7 -0
- package/dev.js +4 -5
- package/dist/compiler.js +3 -2
- package/dist/constants.js +1 -1
- package/dist/index.js +5 -5
- package/dist/obfuscator.js +14 -3
- package/dist/options.js +2 -2
- package/dist/order.js +1 -0
- package/dist/parser.js +2 -2
- package/dist/precedence.js +1 -1
- package/dist/presets.js +3 -0
- package/dist/probability.js +7 -1
- package/dist/transforms/calculator.js +15 -3
- package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +93 -19
- package/dist/transforms/deadCode.js +1 -1
- package/dist/transforms/dispatcher.js +3 -1
- package/dist/transforms/eval.js +1 -1
- package/dist/transforms/flatten.js +2 -2
- package/dist/transforms/hexadecimalNumbers.js +38 -0
- package/dist/transforms/hideInitializingCode.js +8 -3
- package/dist/transforms/identifier/globalConcealing.js +3 -1
- package/dist/transforms/identifier/nameRecycling.js +2 -1
- package/dist/transforms/lock/integrity.js +2 -1
- package/dist/transforms/lock/lock.js +2 -2
- package/dist/transforms/minify.js +8 -3
- package/dist/transforms/rgf.js +11 -8
- package/dist/transforms/stack.js +2 -1
- package/dist/transforms/string/stringConcealing.js +3 -3
- package/dist/transforms/transform.js +32 -8
- package/dist/traverse.js +4 -2
- package/dist/types.js +5 -1
- package/dist/util/compare.js +4 -4
- package/dist/util/gen.js +66 -47
- package/dist/util/identifiers.js +4 -4
- package/dist/util/insert.js +25 -16
- package/dist/util/object.js +3 -1
- package/dist/util/random.js +5 -5
- package/dist/util/scope.js +1 -1
- package/package.json +11 -11
- package/samples/high.js +1 -198
- package/samples/low.js +1 -26
- package/samples/medium.js +1 -40
- package/src/compiler.ts +5 -1
- package/src/obfuscator.ts +2 -0
- package/src/options.ts +8 -0
- package/src/order.ts +2 -0
- package/src/presets.ts +3 -0
- package/src/transforms/calculator.ts +36 -5
- package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +119 -2
- package/src/transforms/deadCode.ts +102 -0
- package/src/transforms/eval.ts +2 -1
- package/src/transforms/hexadecimalNumbers.ts +31 -0
- package/src/transforms/minify.ts +9 -3
- package/src/transforms/transform.ts +10 -2
- package/test/transforms/eval.test.ts +28 -0
- package/test/transforms/hexadecimalNumbers.test.ts +62 -0
- package/test/transforms/minify.test.ts +38 -0
|
@@ -10,19 +10,27 @@ import {
|
|
|
10
10
|
LogicalExpression,
|
|
11
11
|
SwitchCase,
|
|
12
12
|
SwitchStatement,
|
|
13
|
+
SequenceExpression,
|
|
14
|
+
AssignmentExpression,
|
|
15
|
+
VariableDeclaration,
|
|
16
|
+
VariableDeclarator,
|
|
17
|
+
ExpressionStatement,
|
|
13
18
|
} from "../util/gen";
|
|
14
19
|
import { prepend } from "../util/insert";
|
|
15
20
|
import { getBlock } from "../traverse";
|
|
16
|
-
import { getRandomInteger } from "../util/random";
|
|
21
|
+
import { choice, getRandomInteger } from "../util/random";
|
|
17
22
|
import { ObfuscateOrder } from "../order";
|
|
18
23
|
import { ok } from "assert";
|
|
19
24
|
import { OPERATOR_PRECEDENCE } from "../precedence";
|
|
25
|
+
import Template from "../templates/template";
|
|
20
26
|
|
|
21
27
|
export default class Calculator extends Transform {
|
|
22
28
|
gen: any;
|
|
23
29
|
ops: { [operator: string]: number };
|
|
24
30
|
statesUsed: Set<string>;
|
|
25
31
|
calculatorFn: string;
|
|
32
|
+
calculatorOpVar: string;
|
|
33
|
+
calculatorSetOpFn: string;
|
|
26
34
|
|
|
27
35
|
constructor(o) {
|
|
28
36
|
super(o, ObfuscateOrder.Calculator);
|
|
@@ -30,6 +38,8 @@ export default class Calculator extends Transform {
|
|
|
30
38
|
this.ops = Object.create(null);
|
|
31
39
|
this.statesUsed = new Set();
|
|
32
40
|
this.calculatorFn = this.getPlaceholder();
|
|
41
|
+
this.calculatorOpVar = this.getPlaceholder();
|
|
42
|
+
this.calculatorSetOpFn = this.getPlaceholder();
|
|
33
43
|
|
|
34
44
|
this.gen = this.getGenerator();
|
|
35
45
|
}
|
|
@@ -41,7 +51,6 @@ export default class Calculator extends Transform {
|
|
|
41
51
|
return;
|
|
42
52
|
}
|
|
43
53
|
|
|
44
|
-
var opArg = this.getPlaceholder();
|
|
45
54
|
var leftArg = this.getPlaceholder();
|
|
46
55
|
var rightArg = this.getPlaceholder();
|
|
47
56
|
var switchCases = [];
|
|
@@ -65,8 +74,21 @@ export default class Calculator extends Transform {
|
|
|
65
74
|
|
|
66
75
|
var func = FunctionDeclaration(
|
|
67
76
|
this.calculatorFn,
|
|
68
|
-
[
|
|
69
|
-
[SwitchStatement(Identifier(
|
|
77
|
+
[leftArg, rightArg].map((x) => Identifier(x)),
|
|
78
|
+
[SwitchStatement(Identifier(this.calculatorOpVar), switchCases)]
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
prepend(
|
|
82
|
+
tree,
|
|
83
|
+
VariableDeclaration(VariableDeclarator(this.calculatorOpVar))
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
prepend(
|
|
87
|
+
tree,
|
|
88
|
+
Template(`function {name}(a){
|
|
89
|
+
a = {b} + ({b}=a, 0);
|
|
90
|
+
return a;
|
|
91
|
+
}`).single({ name: this.calculatorSetOpFn, b: this.calculatorOpVar })
|
|
70
92
|
);
|
|
71
93
|
|
|
72
94
|
prepend(tree, func);
|
|
@@ -123,9 +145,18 @@ export default class Calculator extends Transform {
|
|
|
123
145
|
this.replace(
|
|
124
146
|
object,
|
|
125
147
|
CallExpression(Identifier(this.calculatorFn), [
|
|
126
|
-
Literal(this.ops[operator]),
|
|
127
148
|
object.left,
|
|
128
149
|
object.right,
|
|
150
|
+
choice([
|
|
151
|
+
AssignmentExpression(
|
|
152
|
+
"=",
|
|
153
|
+
Identifier(this.calculatorOpVar),
|
|
154
|
+
Literal(this.ops[operator])
|
|
155
|
+
),
|
|
156
|
+
CallExpression(Identifier(this.calculatorSetOpFn), [
|
|
157
|
+
Literal(this.ops[operator]),
|
|
158
|
+
]),
|
|
159
|
+
]),
|
|
129
160
|
])
|
|
130
161
|
);
|
|
131
162
|
};
|
|
@@ -18,7 +18,10 @@ import {
|
|
|
18
18
|
IfStatement,
|
|
19
19
|
LabeledStatement,
|
|
20
20
|
Literal,
|
|
21
|
+
MemberExpression,
|
|
21
22
|
Node,
|
|
23
|
+
ObjectExpression,
|
|
24
|
+
Property,
|
|
22
25
|
ReturnStatement,
|
|
23
26
|
SequenceExpression,
|
|
24
27
|
SwitchCase,
|
|
@@ -234,7 +237,16 @@ export default class ControlFlowFlattening extends Transform {
|
|
|
234
237
|
|
|
235
238
|
var resultVar = this.getPlaceholder();
|
|
236
239
|
var argVar = this.getPlaceholder();
|
|
240
|
+
var testVar = this.getPlaceholder();
|
|
241
|
+
var stringBankVar = this.getPlaceholder();
|
|
242
|
+
var stringBank: { [strValue: string]: string } = Object.create(null);
|
|
243
|
+
var stringBankByLabels: { [label: string]: Set<string> } =
|
|
244
|
+
Object.create(null);
|
|
245
|
+
let stringBankGen = this.getGenerator();
|
|
246
|
+
|
|
247
|
+
var needsTestVar = false;
|
|
237
248
|
var needsResultAndArgVar = false;
|
|
249
|
+
var needsStringBankVar = false;
|
|
238
250
|
var fnToLabel: { [fnName: string]: string } = Object.create(null);
|
|
239
251
|
|
|
240
252
|
fnNames.forEach((fnName) => {
|
|
@@ -269,6 +281,38 @@ export default class ControlFlowFlattening extends Transform {
|
|
|
269
281
|
body: [...currentBody],
|
|
270
282
|
});
|
|
271
283
|
|
|
284
|
+
walk(currentBody, [], (o, p) => {
|
|
285
|
+
if (
|
|
286
|
+
o.type == "Literal" &&
|
|
287
|
+
typeof o.value == "string" &&
|
|
288
|
+
!o.regex &&
|
|
289
|
+
Math.random() / (Object.keys(stringBank).length / 2 + 1) > 0.5
|
|
290
|
+
) {
|
|
291
|
+
needsStringBankVar = true;
|
|
292
|
+
if (!stringBankByLabels[currentLabel]) {
|
|
293
|
+
stringBankByLabels[currentLabel] = new Set();
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
stringBankByLabels[currentLabel].add(o.value);
|
|
297
|
+
|
|
298
|
+
if (typeof stringBank[o.value] === "undefined") {
|
|
299
|
+
stringBank[o.value] = stringBankGen.generate();
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
return () => {
|
|
303
|
+
this.replaceIdentifierOrLiteral(
|
|
304
|
+
o,
|
|
305
|
+
MemberExpression(
|
|
306
|
+
Identifier(stringBankVar),
|
|
307
|
+
Literal(stringBank[o.value]),
|
|
308
|
+
true
|
|
309
|
+
),
|
|
310
|
+
p
|
|
311
|
+
);
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
|
|
272
316
|
currentLabel = newLabel;
|
|
273
317
|
currentBody = [];
|
|
274
318
|
};
|
|
@@ -478,7 +522,21 @@ export default class ControlFlowFlattening extends Transform {
|
|
|
478
522
|
finishCurrentChunk(isPostTest ? bodyPath : testPath, testPath);
|
|
479
523
|
|
|
480
524
|
currentBody.push(
|
|
481
|
-
|
|
525
|
+
ExpressionStatement(
|
|
526
|
+
AssignmentExpression(
|
|
527
|
+
"=",
|
|
528
|
+
Identifier(testVar),
|
|
529
|
+
control.test || Literal(true)
|
|
530
|
+
)
|
|
531
|
+
)
|
|
532
|
+
);
|
|
533
|
+
|
|
534
|
+
needsTestVar = true;
|
|
535
|
+
|
|
536
|
+
finishCurrentChunk();
|
|
537
|
+
|
|
538
|
+
currentBody.push(
|
|
539
|
+
IfStatement(Identifier(testVar), [
|
|
482
540
|
{
|
|
483
541
|
type: "GotoStatement",
|
|
484
542
|
label: bodyPath,
|
|
@@ -522,6 +580,16 @@ export default class ControlFlowFlattening extends Transform {
|
|
|
522
580
|
) {
|
|
523
581
|
finishCurrentChunk();
|
|
524
582
|
|
|
583
|
+
currentBody.push(
|
|
584
|
+
ExpressionStatement(
|
|
585
|
+
AssignmentExpression("=", Identifier(testVar), stmt.test)
|
|
586
|
+
)
|
|
587
|
+
);
|
|
588
|
+
|
|
589
|
+
needsTestVar = true;
|
|
590
|
+
|
|
591
|
+
finishCurrentChunk();
|
|
592
|
+
|
|
525
593
|
var hasAlternate = !!stmt.alternate;
|
|
526
594
|
ok(!(hasAlternate && stmt.alternate.type !== "BlockStatement"));
|
|
527
595
|
|
|
@@ -530,7 +598,7 @@ export default class ControlFlowFlattening extends Transform {
|
|
|
530
598
|
var afterPath = this.getPlaceholder();
|
|
531
599
|
|
|
532
600
|
currentBody.push(
|
|
533
|
-
IfStatement(
|
|
601
|
+
IfStatement(Identifier(testVar), [
|
|
534
602
|
{
|
|
535
603
|
type: "GotoStatement",
|
|
536
604
|
label: yesPath,
|
|
@@ -845,6 +913,7 @@ export default class ControlFlowFlattening extends Transform {
|
|
|
845
913
|
|
|
846
914
|
var breaksInsertion = [];
|
|
847
915
|
var staticStateValues = [...labelToStates[chunk.label]];
|
|
916
|
+
var potentialBranches = new Set<string>();
|
|
848
917
|
|
|
849
918
|
chunk.body.forEach((stmt, stmtIndex) => {
|
|
850
919
|
var addBreak = false;
|
|
@@ -894,6 +963,8 @@ export default class ControlFlowFlattening extends Transform {
|
|
|
894
963
|
);
|
|
895
964
|
}
|
|
896
965
|
|
|
966
|
+
potentialBranches.add(o.label);
|
|
967
|
+
|
|
897
968
|
var mutatingStateValues = [...labelToStates[chunk.label]];
|
|
898
969
|
var nextStateValues = labelToStates[o.label];
|
|
899
970
|
ok(nextStateValues, o.label);
|
|
@@ -930,6 +1001,29 @@ export default class ControlFlowFlattening extends Transform {
|
|
|
930
1001
|
chunk.body.splice(index + 1, 0, BreakStatement(switchLabel));
|
|
931
1002
|
});
|
|
932
1003
|
|
|
1004
|
+
for (var branch of Array.from(potentialBranches)) {
|
|
1005
|
+
var strings = stringBankByLabels[branch];
|
|
1006
|
+
if (strings) {
|
|
1007
|
+
chunk.body.unshift(
|
|
1008
|
+
ExpressionStatement(
|
|
1009
|
+
SequenceExpression(
|
|
1010
|
+
Array.from(strings).map((strValue) => {
|
|
1011
|
+
return AssignmentExpression(
|
|
1012
|
+
"=",
|
|
1013
|
+
MemberExpression(
|
|
1014
|
+
Identifier(stringBankVar),
|
|
1015
|
+
Literal(stringBank[strValue]),
|
|
1016
|
+
true
|
|
1017
|
+
),
|
|
1018
|
+
Literal(strValue)
|
|
1019
|
+
);
|
|
1020
|
+
})
|
|
1021
|
+
)
|
|
1022
|
+
)
|
|
1023
|
+
);
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
|
|
933
1027
|
// var c = Identifier("undefined");
|
|
934
1028
|
// this.addComment(c, stateValues.join(", "));
|
|
935
1029
|
// transitionStatements.push(c);
|
|
@@ -975,11 +1069,34 @@ export default class ControlFlowFlattening extends Transform {
|
|
|
975
1069
|
|
|
976
1070
|
var declarations = [];
|
|
977
1071
|
|
|
1072
|
+
if (needsTestVar) {
|
|
1073
|
+
declarations.push(VariableDeclarator(testVar));
|
|
1074
|
+
}
|
|
1075
|
+
|
|
978
1076
|
if (needsResultAndArgVar) {
|
|
979
1077
|
declarations.push(VariableDeclarator(resultVar));
|
|
980
1078
|
declarations.push(VariableDeclarator(argVar));
|
|
981
1079
|
}
|
|
982
1080
|
|
|
1081
|
+
if (needsStringBankVar) {
|
|
1082
|
+
declarations.push(
|
|
1083
|
+
VariableDeclarator(
|
|
1084
|
+
stringBankVar,
|
|
1085
|
+
ObjectExpression(
|
|
1086
|
+
stringBankByLabels[startLabel]
|
|
1087
|
+
? Array.from(stringBankByLabels[startLabel]).map((strValue) =>
|
|
1088
|
+
Property(
|
|
1089
|
+
Literal(stringBank[strValue]),
|
|
1090
|
+
Literal(strValue),
|
|
1091
|
+
false
|
|
1092
|
+
)
|
|
1093
|
+
)
|
|
1094
|
+
: []
|
|
1095
|
+
)
|
|
1096
|
+
)
|
|
1097
|
+
);
|
|
1098
|
+
}
|
|
1099
|
+
|
|
983
1100
|
declarations.push(
|
|
984
1101
|
...stateVars.map((stateVar, i) => {
|
|
985
1102
|
return VariableDeclarator(stateVar, Literal(initStateValues[i]));
|
|
@@ -124,6 +124,108 @@ function setCookie(cname, cvalue, exdays) {
|
|
|
124
124
|
|
|
125
125
|
__.match(s + g);
|
|
126
126
|
`),
|
|
127
|
+
Template(`
|
|
128
|
+
function vec_pack(vec) {
|
|
129
|
+
return vec[1] * 67108864 + (vec[0] < 0 ? 33554432 | vec[0] : vec[0]);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function vec_unpack(number) {
|
|
133
|
+
switch (((number & 33554432) !== 0) * 1 + (number < 0) * 2) {
|
|
134
|
+
case 0:
|
|
135
|
+
return [number % 33554432, Math.trunc(number / 67108864)];
|
|
136
|
+
case 1:
|
|
137
|
+
return [
|
|
138
|
+
(number % 33554432) - 33554432,
|
|
139
|
+
Math.trunc(number / 67108864) + 1,
|
|
140
|
+
];
|
|
141
|
+
case 2:
|
|
142
|
+
return [
|
|
143
|
+
(((number + 33554432) % 33554432) + 33554432) % 33554432,
|
|
144
|
+
Math.round(number / 67108864),
|
|
145
|
+
];
|
|
146
|
+
case 3:
|
|
147
|
+
return [number % 33554432, Math.trunc(number / 67108864)];
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
let a = vec_pack([2, 4]);
|
|
152
|
+
let b = vec_pack([1, 2]);
|
|
153
|
+
|
|
154
|
+
let c = a + b; // Vector addition
|
|
155
|
+
let d = c - b; // Vector subtraction
|
|
156
|
+
let e = d * 2; // Scalar multiplication
|
|
157
|
+
let f = e / 2; // Scalar division
|
|
158
|
+
|
|
159
|
+
console.log(vec_unpack(c)); // [3, 6]
|
|
160
|
+
console.log(vec_unpack(d)); // [2, 4]
|
|
161
|
+
console.log(vec_unpack(e)); // [4, 8]
|
|
162
|
+
console.log(vec_unpack(f)); // [2, 4]
|
|
163
|
+
`),
|
|
164
|
+
Template(`
|
|
165
|
+
function buildCharacterMap(str) {
|
|
166
|
+
const characterMap = {};
|
|
167
|
+
|
|
168
|
+
for (let char of str.replace(/[^\w]/g, "").toLowerCase())
|
|
169
|
+
characterMap[char] = characterMap[char] + 1 || 1;
|
|
170
|
+
|
|
171
|
+
return characterMap;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function isAnagrams(stringA, stringB) {
|
|
175
|
+
const stringAMap = buildCharMap(stringA);
|
|
176
|
+
const stringBMap = buildCharMap(stringB);
|
|
177
|
+
|
|
178
|
+
for (let char in stringAMap) {
|
|
179
|
+
if (stringAMap[char] !== stringBMap[char]) {
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (Object.keys(stringAMap).length !== Object.keys(stringBMap).length) {
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* @param {TreeNode} root
|
|
193
|
+
* @return {boolean}
|
|
194
|
+
*/
|
|
195
|
+
function isBalanced(root) {
|
|
196
|
+
const height = getHeightBalanced(root);
|
|
197
|
+
return height !== Infinity;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function getHeightBalanced(node) {
|
|
201
|
+
if (!node) {
|
|
202
|
+
return -1;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const leftTreeHeight = getHeightBalanced(node.left);
|
|
206
|
+
const rightTreeHeight = getHeightBalanced(node.right);
|
|
207
|
+
|
|
208
|
+
const heightDiff = Math.abs(leftTreeHeight - rightTreeHeight);
|
|
209
|
+
|
|
210
|
+
if (
|
|
211
|
+
leftTreeHeight === Infinity ||
|
|
212
|
+
rightTreeHeight === Infinity ||
|
|
213
|
+
heightDiff > 1
|
|
214
|
+
) {
|
|
215
|
+
return Infinity;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const currentHeight = Math.max(leftTreeHeight, rightTreeHeight) + 1;
|
|
219
|
+
return currentHeight;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
window["__GLOBAL__HELPERS__"] = {
|
|
223
|
+
buildCharacterMap,
|
|
224
|
+
isAnagrams,
|
|
225
|
+
isBalanced,
|
|
226
|
+
getHeightBalanced,
|
|
227
|
+
};
|
|
228
|
+
`),
|
|
127
229
|
];
|
|
128
230
|
|
|
129
231
|
/**
|
package/src/transforms/eval.ts
CHANGED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import Transform from "./transform";
|
|
2
|
+
import { ObfuscateOrder } from "../order";
|
|
3
|
+
import { ExitCallback } from "../traverse";
|
|
4
|
+
import { Identifier, Node } from "../util/gen";
|
|
5
|
+
|
|
6
|
+
export default class HexadecimalNumbers extends Transform {
|
|
7
|
+
constructor(o) {
|
|
8
|
+
super(o, ObfuscateOrder.HexadecimalNumbers);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
match(object: Node, parents: Node[]): boolean {
|
|
12
|
+
return (
|
|
13
|
+
object.type === "Literal" &&
|
|
14
|
+
typeof object.value === "number" &&
|
|
15
|
+
Math.floor(object.value) === object.value
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
transform(object: Node, parents: Node[]): void | ExitCallback {
|
|
20
|
+
return () => {
|
|
21
|
+
// Technically, a Literal will never be negative because it's supposed to be inside a UnaryExpression with a "-" operator.
|
|
22
|
+
// This code handles it regardless
|
|
23
|
+
var isNegative = object.value < 0;
|
|
24
|
+
var hex = Math.abs(object.value).toString(16);
|
|
25
|
+
|
|
26
|
+
var newStr = (isNegative ? "-" : "") + "0x" + hex;
|
|
27
|
+
|
|
28
|
+
this.replace(object, Identifier(newStr));
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
}
|
package/src/transforms/minify.ts
CHANGED
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
clone,
|
|
22
22
|
isForInitialize,
|
|
23
23
|
isLexContext,
|
|
24
|
+
getFunction,
|
|
24
25
|
} from "../util/insert";
|
|
25
26
|
import { isValidIdentifier, isEquivalent } from "../util/compare";
|
|
26
27
|
import { walk, isBlock } from "../traverse";
|
|
@@ -126,9 +127,14 @@ export default class Minify extends Transform {
|
|
|
126
127
|
// Unnecessary return
|
|
127
128
|
if (body.length && body[body.length - 1]) {
|
|
128
129
|
var last = body[body.length - 1];
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
130
|
+
if (last.type == "ReturnStatement") {
|
|
131
|
+
var isUndefined = last.argument == null;
|
|
132
|
+
|
|
133
|
+
if (isUndefined) {
|
|
134
|
+
if (getFunction(object, parents).body == object) {
|
|
135
|
+
body.pop();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
132
138
|
}
|
|
133
139
|
}
|
|
134
140
|
|
|
@@ -196,10 +196,18 @@ export default class Transform {
|
|
|
196
196
|
*/
|
|
197
197
|
getGenerator(offset = 0) {
|
|
198
198
|
var count = offset;
|
|
199
|
+
var identifiers = new Set();
|
|
199
200
|
return {
|
|
200
201
|
generate: () => {
|
|
201
|
-
|
|
202
|
-
|
|
202
|
+
var retValue;
|
|
203
|
+
do {
|
|
204
|
+
count++;
|
|
205
|
+
retValue = this.generateIdentifier(-1, count);
|
|
206
|
+
} while (identifiers.has(retValue));
|
|
207
|
+
|
|
208
|
+
identifiers.add(retValue);
|
|
209
|
+
|
|
210
|
+
return retValue;
|
|
203
211
|
},
|
|
204
212
|
};
|
|
205
213
|
}
|
|
@@ -48,3 +48,31 @@ it("should move function declarations to the top of the block", async () => {
|
|
|
48
48
|
|
|
49
49
|
expect(value).toStrictEqual(100);
|
|
50
50
|
});
|
|
51
|
+
|
|
52
|
+
it("should work with Integrity also enabled", async () => {
|
|
53
|
+
var code = `
|
|
54
|
+
input("Hello World")
|
|
55
|
+
`;
|
|
56
|
+
|
|
57
|
+
var output = await JsConfuser(code, {
|
|
58
|
+
target: "node",
|
|
59
|
+
compact: false,
|
|
60
|
+
eval: true,
|
|
61
|
+
lock: {
|
|
62
|
+
integrity: true,
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
expect(output).toContain("eval(");
|
|
67
|
+
|
|
68
|
+
var value = "never_called",
|
|
69
|
+
input = (valueIn) => (value = valueIn);
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
eval(output);
|
|
73
|
+
} catch (e) {
|
|
74
|
+
expect(e).toStrictEqual(undefined);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
expect(value).toStrictEqual("Hello World");
|
|
78
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import JsConfuser from "../../src/index";
|
|
2
|
+
|
|
3
|
+
test("Variant #1: Positive integer to hexadecimal", async () => {
|
|
4
|
+
var output = await JsConfuser.obfuscate(`TEST_VAR = 10;`, {
|
|
5
|
+
target: "node",
|
|
6
|
+
hexadecimalNumbers: true,
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
expect(output).toContain("0xa");
|
|
10
|
+
expect(output).not.toContain("10");
|
|
11
|
+
|
|
12
|
+
var TEST_VAR;
|
|
13
|
+
|
|
14
|
+
eval(output);
|
|
15
|
+
|
|
16
|
+
expect(TEST_VAR).toStrictEqual(10);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test("Variant #2: Negative integer to hexadecimal", async () => {
|
|
20
|
+
var output = await JsConfuser.obfuscate(`TEST_VAR = -10;`, {
|
|
21
|
+
target: "node",
|
|
22
|
+
hexadecimalNumbers: true,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
expect(output).toContain("-0xa");
|
|
26
|
+
expect(output).not.toContain("-10");
|
|
27
|
+
|
|
28
|
+
var TEST_VAR;
|
|
29
|
+
|
|
30
|
+
eval(output);
|
|
31
|
+
|
|
32
|
+
expect(TEST_VAR).toStrictEqual(-10);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test("Variant #3: Don't change floats", async () => {
|
|
36
|
+
var output = await JsConfuser.obfuscate(`var TEST_VAR = [15.5, -75.9];`, {
|
|
37
|
+
target: "node",
|
|
38
|
+
hexadecimalNumbers: true,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
expect(output).toContain("15.5");
|
|
42
|
+
expect(output).toContain("-75.9");
|
|
43
|
+
expect(output).not.toContain("0x");
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("Variant #4: Work even on large numbers", async () => {
|
|
47
|
+
var output = await JsConfuser.obfuscate(
|
|
48
|
+
`TEST_VAR = 10000000000000000000000000000;`,
|
|
49
|
+
{
|
|
50
|
+
target: "node",
|
|
51
|
+
hexadecimalNumbers: true,
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
expect(output).toContain("0x204fce5e3e25020000000000");
|
|
56
|
+
|
|
57
|
+
var TEST_VAR;
|
|
58
|
+
|
|
59
|
+
eval(output);
|
|
60
|
+
|
|
61
|
+
expect(TEST_VAR).toStrictEqual(10000000000000000000000000000);
|
|
62
|
+
});
|
|
@@ -261,3 +261,41 @@ test("Variant #14: Shorten 'var x = undefined' to 'var x'", async () => {
|
|
|
261
261
|
expect(output).toContain("var x");
|
|
262
262
|
expect(output).not.toContain("var x=");
|
|
263
263
|
});
|
|
264
|
+
|
|
265
|
+
test("Variant #15: Removing implied 'return'", async () => {
|
|
266
|
+
// Valid
|
|
267
|
+
var output = await JsConfuser(
|
|
268
|
+
`
|
|
269
|
+
function MyFunction(){
|
|
270
|
+
var output = "Hello World";
|
|
271
|
+
console.log(output);
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
MyFunction();
|
|
276
|
+
`,
|
|
277
|
+
{ target: "node", minify: true }
|
|
278
|
+
);
|
|
279
|
+
|
|
280
|
+
expect(output).not.toContain("return");
|
|
281
|
+
|
|
282
|
+
// Invalid
|
|
283
|
+
// https://github.com/MichaelXF/js-confuser/issues/34
|
|
284
|
+
var output2 = await JsConfuser(
|
|
285
|
+
`
|
|
286
|
+
function greet(){
|
|
287
|
+
if(true){
|
|
288
|
+
console.log("return");
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
var output = "should not show!"; console.log(output);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
greet();
|
|
296
|
+
`,
|
|
297
|
+
{ target: "browser", minify: true }
|
|
298
|
+
);
|
|
299
|
+
|
|
300
|
+
expect(output2).toContain("return");
|
|
301
|
+
});
|