js-confuser 1.6.0 → 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/CHANGELOG.md +23 -0
- package/README.md +215 -170
- package/dist/constants.js +6 -2
- package/dist/obfuscator.js +0 -6
- package/dist/options.js +4 -4
- package/dist/presets.js +6 -7
- package/dist/templates/crash.js +2 -2
- package/dist/templates/functionLength.js +16 -0
- package/dist/transforms/dispatcher.js +4 -1
- package/dist/transforms/extraction/duplicateLiteralsRemoval.js +89 -58
- package/dist/transforms/flatten.js +224 -147
- package/dist/transforms/identifier/movedDeclarations.js +38 -85
- package/dist/transforms/identifier/renameVariables.js +94 -41
- package/dist/transforms/lock/lock.js +0 -37
- package/dist/transforms/minify.js +2 -2
- package/dist/transforms/rgf.js +139 -246
- package/dist/transforms/stack.js +42 -1
- package/dist/transforms/transform.js +1 -1
- package/dist/util/gen.js +2 -1
- package/dist/util/identifiers.js +37 -3
- package/dist/util/insert.js +24 -3
- 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 +1 -1
- package/src/constants.ts +3 -0
- package/src/obfuscator.ts +0 -4
- package/src/options.ts +9 -86
- package/src/presets.ts +6 -7
- package/src/templates/crash.ts +10 -10
- package/src/templates/functionLength.ts +14 -0
- package/src/transforms/dispatcher.ts +5 -1
- package/src/transforms/extraction/duplicateLiteralsRemoval.ts +130 -129
- package/src/transforms/flatten.ts +357 -290
- package/src/transforms/identifier/movedDeclarations.ts +50 -96
- package/src/transforms/identifier/renameVariables.ts +120 -56
- package/src/transforms/lock/lock.ts +1 -42
- package/src/transforms/minify.ts +11 -2
- package/src/transforms/rgf.ts +214 -404
- package/src/transforms/stack.ts +62 -0
- package/src/transforms/transform.ts +6 -2
- package/src/util/gen.ts +7 -2
- package/src/util/identifiers.ts +43 -2
- package/src/util/insert.ts +26 -2
- package/test/code/ES6.src.js +24 -0
- package/test/transforms/flatten.test.ts +352 -88
- package/test/transforms/identifier/movedDeclarations.test.ts +37 -9
- package/test/transforms/identifier/renameVariables.test.ts +37 -0
- package/test/transforms/lock/lock.test.ts +1 -48
- package/test/transforms/minify.test.ts +19 -0
- package/test/transforms/rgf.test.ts +262 -353
- package/test/transforms/stack.test.ts +52 -0
- package/test/util/identifiers.test.ts +113 -1
- package/test/util/insert.test.ts +57 -3
- package/src/transforms/eval.ts +0 -89
- package/src/transforms/identifier/nameRecycling.ts +0 -280
- package/test/transforms/eval.test.ts +0 -131
- package/test/transforms/identifier/nameRecycling.test.ts +0 -205
package/src/transforms/stack.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { walk } from "../traverse";
|
|
|
6
6
|
import {
|
|
7
7
|
AssignmentExpression,
|
|
8
8
|
BinaryExpression,
|
|
9
|
+
CallExpression,
|
|
9
10
|
ExpressionStatement,
|
|
10
11
|
Identifier,
|
|
11
12
|
IfStatement,
|
|
@@ -18,6 +19,7 @@ import {
|
|
|
18
19
|
} from "../util/gen";
|
|
19
20
|
import { getIdentifierInfo } from "../util/identifiers";
|
|
20
21
|
import {
|
|
22
|
+
computeFunctionLength,
|
|
21
23
|
getBlockBody,
|
|
22
24
|
getDefiningContext,
|
|
23
25
|
getReferencingContexts,
|
|
@@ -28,10 +30,14 @@ import {
|
|
|
28
30
|
} from "../util/insert";
|
|
29
31
|
import { chance, choice, getRandomInteger } from "../util/random";
|
|
30
32
|
import Transform from "./transform";
|
|
33
|
+
import { noRenameVariablePrefix } from "../constants";
|
|
34
|
+
import { FunctionLengthTemplate } from "../templates/functionLength";
|
|
31
35
|
|
|
32
36
|
export default class Stack extends Transform {
|
|
33
37
|
mangledExpressionsMade: number;
|
|
34
38
|
|
|
39
|
+
functionLengthName: string;
|
|
40
|
+
|
|
35
41
|
constructor(o) {
|
|
36
42
|
super(o, ObfuscateOrder.Stack);
|
|
37
43
|
|
|
@@ -111,8 +117,14 @@ export default class Stack extends Transform {
|
|
|
111
117
|
});
|
|
112
118
|
|
|
113
119
|
var startingSize = subscripts.size;
|
|
120
|
+
var isIllegal = false;
|
|
114
121
|
|
|
115
122
|
walk(object.body, [object, ...parents], (o, p) => {
|
|
123
|
+
if (o.type === "Identifier" && o.name === "arguments") {
|
|
124
|
+
isIllegal = true;
|
|
125
|
+
return "EXIT";
|
|
126
|
+
}
|
|
127
|
+
|
|
116
128
|
if (o.type == "Identifier") {
|
|
117
129
|
var info = getIdentifierInfo(o, p);
|
|
118
130
|
if (!info.spec.isReferenced || info.spec.isExported) {
|
|
@@ -128,6 +140,10 @@ export default class Stack extends Transform {
|
|
|
128
140
|
illegal.add(o.name);
|
|
129
141
|
}
|
|
130
142
|
|
|
143
|
+
if (o.name.startsWith(noRenameVariablePrefix)) {
|
|
144
|
+
illegal.add(o.name);
|
|
145
|
+
}
|
|
146
|
+
|
|
131
147
|
if (
|
|
132
148
|
info.isClauseParameter ||
|
|
133
149
|
info.isFunctionParameter ||
|
|
@@ -200,6 +216,8 @@ export default class Stack extends Transform {
|
|
|
200
216
|
}
|
|
201
217
|
});
|
|
202
218
|
|
|
219
|
+
if (isIllegal) return;
|
|
220
|
+
|
|
203
221
|
illegal.forEach((name) => {
|
|
204
222
|
defined.delete(name);
|
|
205
223
|
referenced.delete(name);
|
|
@@ -467,6 +485,9 @@ export default class Stack extends Transform {
|
|
|
467
485
|
object.body.body.splice(parseInt(index) + i, 0, rotateNodes[index]);
|
|
468
486
|
});
|
|
469
487
|
|
|
488
|
+
// Preserve function.length property
|
|
489
|
+
var originalFunctionLength = computeFunctionLength(object.params);
|
|
490
|
+
|
|
470
491
|
// Set the params for this function to be the stack array
|
|
471
492
|
object.params = [RestElement(Identifier(stackName))];
|
|
472
493
|
|
|
@@ -475,6 +496,47 @@ export default class Stack extends Transform {
|
|
|
475
496
|
object.body,
|
|
476
497
|
Template(`${stackName}["length"] = ${startingSize}`).single()
|
|
477
498
|
);
|
|
499
|
+
|
|
500
|
+
if (originalFunctionLength !== 0) {
|
|
501
|
+
if (!this.functionLengthName) {
|
|
502
|
+
this.functionLengthName = this.getPlaceholder();
|
|
503
|
+
prepend(
|
|
504
|
+
parents[parents.length - 1] || object,
|
|
505
|
+
FunctionLengthTemplate.single({ name: this.functionLengthName })
|
|
506
|
+
);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
if (object.type === "FunctionDeclaration") {
|
|
510
|
+
var body = parents[0];
|
|
511
|
+
if (Array.isArray(body)) {
|
|
512
|
+
var index = body.indexOf(object);
|
|
513
|
+
|
|
514
|
+
body.splice(
|
|
515
|
+
index,
|
|
516
|
+
0,
|
|
517
|
+
ExpressionStatement(
|
|
518
|
+
CallExpression(Identifier(this.functionLengthName), [
|
|
519
|
+
Identifier(object.id.name),
|
|
520
|
+
Literal(originalFunctionLength),
|
|
521
|
+
])
|
|
522
|
+
)
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
} else {
|
|
526
|
+
ok(
|
|
527
|
+
object.type === "FunctionExpression" ||
|
|
528
|
+
object.type === "ArrowFunctionExpression"
|
|
529
|
+
);
|
|
530
|
+
|
|
531
|
+
this.replace(
|
|
532
|
+
object,
|
|
533
|
+
CallExpression(Identifier(this.functionLengthName), [
|
|
534
|
+
{ ...object },
|
|
535
|
+
Literal(originalFunctionLength),
|
|
536
|
+
])
|
|
537
|
+
);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
478
540
|
};
|
|
479
541
|
}
|
|
480
542
|
}
|
|
@@ -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
|
/**
|
|
@@ -176,7 +180,7 @@ export default class Transform {
|
|
|
176
180
|
[...Array(size)]
|
|
177
181
|
.map(() => Math.floor(Math.random() * 10).toString(10))
|
|
178
182
|
.join("");
|
|
179
|
-
return
|
|
183
|
+
return placeholderVariablePrefix + genRanHex(10);
|
|
180
184
|
}
|
|
181
185
|
|
|
182
186
|
/**
|
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
|
};
|
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
|
|
|
@@ -376,3 +376,27 @@ export function isForInitialize(
|
|
|
376
376
|
|
|
377
377
|
return false;
|
|
378
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/test/code/ES6.src.js
CHANGED
|
@@ -203,6 +203,30 @@ function labeledBreaksAndContinues() {
|
|
|
203
203
|
var variant15 = labeledBreaksAndContinues();
|
|
204
204
|
expect(variant15).toStrictEqual(15);
|
|
205
205
|
|
|
206
|
+
// Variant #16: Function.length property
|
|
207
|
+
var variant16 = function (
|
|
208
|
+
n1,
|
|
209
|
+
n2,
|
|
210
|
+
n3,
|
|
211
|
+
n4,
|
|
212
|
+
n5,
|
|
213
|
+
n6,
|
|
214
|
+
n7,
|
|
215
|
+
n8,
|
|
216
|
+
n9,
|
|
217
|
+
n10,
|
|
218
|
+
n11,
|
|
219
|
+
n12,
|
|
220
|
+
n13,
|
|
221
|
+
n14,
|
|
222
|
+
n15,
|
|
223
|
+
n16
|
|
224
|
+
) {
|
|
225
|
+
var _ = true;
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
expect(variant16.length).toStrictEqual(16);
|
|
229
|
+
|
|
206
230
|
// Set 'ranAllTest' to TRUE
|
|
207
231
|
ranAllTest = true;
|
|
208
232
|
|