js-confuser 1.7.0 → 1.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +57 -0
- package/README.md +12 -29
- package/dist/compiler.js +2 -8
- package/dist/constants.js +17 -10
- package/dist/index.js +7 -30
- package/dist/obfuscator.js +15 -62
- package/dist/options.js +21 -38
- package/dist/order.js +4 -7
- package/dist/parser.js +5 -13
- package/dist/precedence.js +6 -8
- package/dist/presets.js +4 -6
- package/dist/probability.js +13 -24
- package/dist/templates/bufferToString.js +100 -5
- package/dist/templates/crash.js +51 -9
- package/dist/templates/es5.js +125 -6
- package/dist/templates/functionLength.js +24 -6
- package/dist/templates/globals.js +9 -0
- package/dist/templates/template.js +71 -30
- package/dist/transforms/antiTooling.js +26 -22
- package/dist/transforms/calculator.js +18 -54
- package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +236 -333
- package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +46 -25
- package/dist/transforms/deadCode.js +528 -27
- package/dist/transforms/dispatcher.js +110 -108
- package/dist/transforms/es5/antiClass.js +70 -44
- package/dist/transforms/es5/antiDestructuring.js +14 -38
- package/dist/transforms/es5/antiES6Object.js +39 -48
- package/dist/transforms/es5/antiSpreadOperator.js +5 -14
- package/dist/transforms/es5/antiTemplate.js +10 -19
- package/dist/transforms/es5/es5.js +7 -40
- package/dist/transforms/extraction/classExtraction.js +83 -0
- package/dist/transforms/extraction/duplicateLiteralsRemoval.js +45 -79
- package/dist/transforms/extraction/objectExtraction.js +27 -54
- package/dist/transforms/finalizer.js +6 -20
- package/dist/transforms/flatten.js +51 -99
- package/dist/transforms/identifier/globalAnalysis.js +8 -26
- package/dist/transforms/identifier/globalConcealing.js +35 -54
- package/dist/transforms/identifier/movedDeclarations.js +66 -38
- package/dist/transforms/identifier/renameVariables.js +29 -68
- package/dist/transforms/identifier/variableAnalysis.js +21 -48
- package/dist/transforms/lock/antiDebug.js +20 -25
- package/dist/transforms/lock/integrity.js +48 -47
- package/dist/transforms/lock/lock.js +62 -113
- package/dist/transforms/minify.js +77 -108
- package/dist/transforms/opaquePredicates.js +11 -48
- package/dist/transforms/preparation.js +17 -50
- package/dist/transforms/renameLabels.js +5 -22
- package/dist/transforms/rgf.js +98 -66
- package/dist/transforms/shuffle.js +41 -46
- package/dist/transforms/stack.js +35 -98
- package/dist/transforms/string/encoding.js +73 -27
- package/dist/transforms/string/stringCompression.js +44 -68
- package/dist/transforms/string/stringConcealing.js +125 -134
- package/dist/transforms/string/stringEncoding.js +6 -26
- package/dist/transforms/string/stringSplitting.js +5 -30
- package/dist/transforms/transform.js +50 -100
- package/dist/traverse.js +11 -18
- package/dist/util/compare.js +27 -29
- package/dist/util/gen.js +32 -86
- package/dist/util/guard.js +0 -1
- package/dist/util/identifiers.js +11 -74
- package/dist/util/insert.js +27 -77
- package/dist/util/math.js +0 -3
- package/dist/util/object.js +3 -7
- package/dist/util/random.js +5 -36
- package/dist/util/scope.js +6 -3
- package/docs/ControlFlowFlattening.md +1 -1
- package/docs/ES5.md +197 -0
- package/package.json +3 -3
- package/src/constants.ts +12 -0
- package/src/options.ts +13 -0
- package/src/order.ts +2 -2
- package/src/templates/bufferToString.ts +49 -11
- package/src/templates/functionLength.ts +21 -3
- package/src/templates/globals.ts +3 -0
- package/src/templates/template.ts +85 -25
- package/src/transforms/antiTooling.ts +33 -11
- package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +2 -2
- package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +46 -10
- package/src/transforms/deadCode.ts +0 -16
- package/src/transforms/dispatcher.ts +101 -69
- package/src/transforms/es5/antiClass.ts +10 -1
- package/src/transforms/extraction/classExtraction.ts +168 -0
- package/src/transforms/extraction/duplicateLiteralsRemoval.ts +13 -10
- package/src/transforms/extraction/objectExtraction.ts +7 -14
- package/src/transforms/flatten.ts +20 -5
- package/src/transforms/identifier/globalConcealing.ts +29 -65
- package/src/transforms/identifier/movedDeclarations.ts +90 -24
- package/src/transforms/minify.ts +27 -12
- package/src/transforms/rgf.ts +103 -5
- package/src/transforms/stack.ts +12 -3
- package/src/transforms/string/encoding.ts +85 -51
- package/src/transforms/string/stringCompression.ts +5 -8
- package/src/transforms/string/stringConcealing.ts +139 -113
- package/src/transforms/string/stringEncoding.ts +1 -2
- package/src/transforms/string/stringSplitting.ts +1 -2
- package/src/transforms/transform.ts +30 -1
- package/src/util/compare.ts +39 -5
- package/src/util/gen.ts +10 -3
- package/src/util/identifiers.ts +6 -3
- package/src/util/insert.ts +17 -0
- package/src/util/scope.ts +14 -2
- package/test/code/Cash.test.ts +10 -4
- package/test/code/StrictMode.src.js +65 -0
- package/test/code/StrictMode.test.js +37 -0
- package/test/compare.test.ts +62 -2
- package/test/options.test.ts +111 -55
- package/test/transforms/controlFlowFlattening/expressionObfuscation.test.ts +37 -18
- package/test/transforms/dispatcher.test.ts +82 -0
- package/test/transforms/extraction/classExtraction.test.ts +86 -0
- package/test/transforms/extraction/duplicateLiteralsRemoval.test.ts +29 -8
- package/test/transforms/extraction/objectExtraction.test.ts +37 -15
- package/test/transforms/identifier/globalConcealing.test.ts +42 -2
- package/test/transforms/identifier/movedDeclarations.test.ts +61 -0
- package/test/transforms/lock/integrity.test.ts +24 -0
- package/test/transforms/minify.test.ts +37 -0
- package/test/transforms/rgf.test.ts +50 -0
- package/test/util/identifiers.test.ts +21 -0
- package/dist/transforms/controlFlowFlattening/choiceFlowObfuscation.js +0 -62
- package/dist/transforms/controlFlowFlattening/controlFlowObfuscation.js +0 -159
- package/dist/transforms/controlFlowFlattening/switchCaseObfuscation.js +0 -106
- package/dist/transforms/eval.js +0 -84
- package/dist/transforms/hexadecimalNumbers.js +0 -63
- package/dist/transforms/hideInitializingCode.js +0 -270
- package/dist/transforms/identifier/nameRecycling.js +0 -218
- package/dist/transforms/label.js +0 -67
- package/dist/transforms/preparation/nameConflicts.js +0 -116
- package/dist/transforms/preparation/preparation.js +0 -188
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { ok } from "assert";
|
|
2
2
|
import { ObfuscateOrder } from "../../order";
|
|
3
3
|
import Template from "../../templates/template";
|
|
4
|
-
import {
|
|
5
|
-
import { isDirective } from "../../util/compare";
|
|
4
|
+
import { getBlock } from "../../traverse";
|
|
5
|
+
import { isDirective, isModuleSource } from "../../util/compare";
|
|
6
6
|
import {
|
|
7
7
|
ArrayExpression,
|
|
8
8
|
CallExpression,
|
|
9
|
-
FunctionExpression,
|
|
10
9
|
Identifier,
|
|
11
10
|
Literal,
|
|
12
11
|
MemberExpression,
|
|
@@ -22,54 +21,36 @@ import {
|
|
|
22
21
|
choice,
|
|
23
22
|
getRandomInteger,
|
|
24
23
|
getRandomString,
|
|
24
|
+
shuffle,
|
|
25
25
|
} from "../../util/random";
|
|
26
26
|
import Transform from "../transform";
|
|
27
|
-
import
|
|
27
|
+
import {
|
|
28
|
+
EncodingImplementation,
|
|
29
|
+
EncodingImplementations,
|
|
30
|
+
createEncodingImplementation,
|
|
31
|
+
hasAllEncodings,
|
|
32
|
+
} from "./encoding";
|
|
28
33
|
import { ComputeProbabilityMap } from "../../probability";
|
|
29
34
|
import { BufferToStringTemplate } from "../../templates/bufferToString";
|
|
35
|
+
import { criticalFunctionTag, predictableFunctionTag } from "../../constants";
|
|
30
36
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if (parents[0].type == "ImportDeclaration" && parents[0].source == object) {
|
|
37
|
-
return true;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (parents[0].type == "ImportExpression" && parents[0].source == object) {
|
|
41
|
-
return true;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (
|
|
45
|
-
parents[1] &&
|
|
46
|
-
parents[1].type == "CallExpression" &&
|
|
47
|
-
parents[1].arguments[0] === object &&
|
|
48
|
-
parents[1].callee.type == "Identifier"
|
|
49
|
-
) {
|
|
50
|
-
if (
|
|
51
|
-
parents[1].callee.name == "require" ||
|
|
52
|
-
parents[1].callee.name == "import"
|
|
53
|
-
) {
|
|
54
|
-
return true;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return false;
|
|
37
|
+
interface FunctionObject {
|
|
38
|
+
block: Node;
|
|
39
|
+
fnName: string;
|
|
40
|
+
encodingImplementation: EncodingImplementation;
|
|
59
41
|
}
|
|
60
42
|
|
|
61
43
|
export default class StringConcealing extends Transform {
|
|
62
44
|
arrayExpression: Node;
|
|
63
45
|
set: Set<string>;
|
|
64
|
-
index: { [str: string]: [number, string] };
|
|
46
|
+
index: { [str: string]: [number, string, Node] }; // index, fnName, block
|
|
65
47
|
|
|
66
48
|
arrayName = this.getPlaceholder();
|
|
67
49
|
ignore = new Set<string>();
|
|
68
50
|
variablesMade = 1;
|
|
69
|
-
encoding: { [type: string]: string } = Object.create(null);
|
|
70
51
|
gen: ReturnType<Transform["getGenerator"]>;
|
|
71
52
|
|
|
72
|
-
|
|
53
|
+
functionObjects: FunctionObject[] = [];
|
|
73
54
|
|
|
74
55
|
constructor(o) {
|
|
75
56
|
super(o, ObfuscateOrder.StringConcealing);
|
|
@@ -77,84 +58,110 @@ export default class StringConcealing extends Transform {
|
|
|
77
58
|
this.set = new Set();
|
|
78
59
|
this.index = Object.create(null);
|
|
79
60
|
this.arrayExpression = ArrayExpression([]);
|
|
80
|
-
this.hasAllEncodings = false;
|
|
81
61
|
this.gen = this.getGenerator();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
apply(tree) {
|
|
65
|
+
super.apply(tree);
|
|
82
66
|
|
|
83
67
|
// Pad array with useless strings
|
|
84
68
|
var dead = getRandomInteger(5, 15);
|
|
85
69
|
for (var i = 0; i < dead; i++) {
|
|
86
70
|
var str = getRandomString(getRandomInteger(5, 40));
|
|
87
|
-
var fn = this.transform(Literal(str), []);
|
|
71
|
+
var fn = this.transform(Literal(str), [tree]);
|
|
88
72
|
if (fn) {
|
|
89
73
|
fn();
|
|
90
74
|
}
|
|
91
75
|
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
apply(tree) {
|
|
95
|
-
super.apply(tree);
|
|
96
76
|
|
|
97
77
|
var cacheName = this.getPlaceholder();
|
|
98
|
-
var bufferToStringName = this.getPlaceholder();
|
|
78
|
+
var bufferToStringName = this.getPlaceholder() + predictableFunctionTag;
|
|
99
79
|
|
|
100
80
|
// This helper functions convert UInt8 Array to UTf-string
|
|
101
81
|
prepend(
|
|
102
82
|
tree,
|
|
103
|
-
...BufferToStringTemplate.compile({
|
|
83
|
+
...BufferToStringTemplate.compile({
|
|
84
|
+
name: bufferToStringName,
|
|
85
|
+
getGlobalFnName: this.getPlaceholder() + predictableFunctionTag,
|
|
86
|
+
})
|
|
104
87
|
);
|
|
105
88
|
|
|
106
|
-
|
|
107
|
-
var {
|
|
108
|
-
|
|
109
|
-
|
|
89
|
+
for (var functionObject of this.functionObjects) {
|
|
90
|
+
var {
|
|
91
|
+
block,
|
|
92
|
+
fnName: getterFnName,
|
|
93
|
+
encodingImplementation,
|
|
94
|
+
} = functionObject;
|
|
95
|
+
|
|
96
|
+
var decodeFn =
|
|
97
|
+
this.getPlaceholder() + predictableFunctionTag + criticalFunctionTag;
|
|
110
98
|
|
|
111
99
|
append(
|
|
112
|
-
|
|
113
|
-
template.single({
|
|
100
|
+
block,
|
|
101
|
+
encodingImplementation.template.single({
|
|
102
|
+
__fnName__: decodeFn,
|
|
103
|
+
__bufferToString__: bufferToStringName,
|
|
104
|
+
})
|
|
114
105
|
);
|
|
106
|
+
// All these are fake and never ran
|
|
107
|
+
var ifStatements = Template(`if ( z == x ) {
|
|
108
|
+
return y[${cacheName}[z]] = ${getterFnName}(x, y);
|
|
109
|
+
}
|
|
110
|
+
if ( y ) {
|
|
111
|
+
[b, y] = [a(b), x || z]
|
|
112
|
+
return ${getterFnName}(x, b, z)
|
|
113
|
+
}
|
|
114
|
+
if ( z && a !== ${decodeFn} ) {
|
|
115
|
+
${getterFnName} = ${decodeFn}
|
|
116
|
+
return ${getterFnName}(x, -1, z, a, b)
|
|
117
|
+
}
|
|
118
|
+
if ( a === ${getterFnName} ) {
|
|
119
|
+
${decodeFn} = y
|
|
120
|
+
return ${decodeFn}(z)
|
|
121
|
+
}
|
|
122
|
+
if( a === undefined ) {
|
|
123
|
+
${getterFnName} = b
|
|
124
|
+
}
|
|
125
|
+
if( z == a ) {
|
|
126
|
+
return y ? x[b[y]] : ${cacheName}[x] || (z=(b[x] || a), ${cacheName}[x] = z(${this.arrayName}[x]))
|
|
127
|
+
}
|
|
128
|
+
`).compile();
|
|
115
129
|
|
|
116
|
-
|
|
117
|
-
|
|
130
|
+
// Not all fake if-statements are needed
|
|
131
|
+
ifStatements = ifStatements.filter(() => chance(50));
|
|
132
|
+
|
|
133
|
+
// This one is always used
|
|
134
|
+
ifStatements.push(
|
|
118
135
|
Template(`
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
} else if ( y ) {
|
|
124
|
-
[b, y] = [a(b), x || z]
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
return y ? x[b[y]] : ${cacheName}[x] || (z=(b[x], a), ${cacheName}[x] = z(${this.arrayName}[x]))
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
`).single()
|
|
136
|
+
if ( x !== y ) {
|
|
137
|
+
return b[x] || (b[x] = a(${this.arrayName}[x]))
|
|
138
|
+
}
|
|
139
|
+
`).single()
|
|
131
140
|
);
|
|
132
|
-
});
|
|
133
141
|
|
|
134
|
-
|
|
142
|
+
shuffle(ifStatements);
|
|
143
|
+
|
|
144
|
+
var varDeclaration = Template(`
|
|
145
|
+
var ${getterFnName} = (x, y, z, a, b)=>{
|
|
146
|
+
if(typeof a === "undefined") {
|
|
147
|
+
a = ${decodeFn}
|
|
148
|
+
}
|
|
149
|
+
if(typeof b === "undefined") {
|
|
150
|
+
b = ${cacheName}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
`).single();
|
|
154
|
+
|
|
155
|
+
varDeclaration.declarations[0].init.body.body.push(...ifStatements);
|
|
156
|
+
|
|
157
|
+
prepend(block, varDeclaration);
|
|
158
|
+
}
|
|
135
159
|
|
|
136
160
|
prepend(
|
|
137
161
|
tree,
|
|
138
162
|
VariableDeclaration([
|
|
139
163
|
VariableDeclarator(cacheName, ArrayExpression([])),
|
|
140
|
-
VariableDeclarator(
|
|
141
|
-
VariableDeclarator(
|
|
142
|
-
this.arrayName,
|
|
143
|
-
CallExpression(
|
|
144
|
-
FunctionExpression(
|
|
145
|
-
[],
|
|
146
|
-
[
|
|
147
|
-
VariableDeclaration(
|
|
148
|
-
VariableDeclarator("a", this.arrayExpression)
|
|
149
|
-
),
|
|
150
|
-
Template(
|
|
151
|
-
`return (${flowIntegrity} ? a["pop"]() : ${flowIntegrity}++, a)`
|
|
152
|
-
).single(),
|
|
153
|
-
]
|
|
154
|
-
),
|
|
155
|
-
[]
|
|
156
|
-
)
|
|
157
|
-
),
|
|
164
|
+
VariableDeclarator(this.arrayName, this.arrayExpression),
|
|
158
165
|
])
|
|
159
166
|
);
|
|
160
167
|
}
|
|
@@ -192,48 +199,67 @@ export default class StringConcealing extends Transform {
|
|
|
192
199
|
return;
|
|
193
200
|
}
|
|
194
201
|
|
|
195
|
-
|
|
196
|
-
if (this.set.size > 1000 && !chance(this.set.size / 100)) return;
|
|
202
|
+
var currentBlock = getBlock(object, parents);
|
|
197
203
|
|
|
198
|
-
|
|
204
|
+
// Find created functions
|
|
205
|
+
var functionObjects: FunctionObject[] = parents
|
|
206
|
+
.filter((node) => node.$stringConcealingFunctionObject)
|
|
207
|
+
.map((item) => item.$stringConcealingFunctionObject);
|
|
199
208
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
209
|
+
// Choose random functionObject to use
|
|
210
|
+
var functionObject = choice(functionObjects);
|
|
211
|
+
|
|
212
|
+
if (
|
|
213
|
+
!functionObject ||
|
|
214
|
+
(!hasAllEncodings() &&
|
|
215
|
+
chance(25 / this.functionObjects.length) &&
|
|
216
|
+
!currentBlock.$stringConcealingFunctionObject)
|
|
217
|
+
) {
|
|
218
|
+
// No functions, create one
|
|
205
219
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
220
|
+
var newFunctionObject: FunctionObject = {
|
|
221
|
+
block: currentBlock,
|
|
222
|
+
encodingImplementation: createEncodingImplementation(),
|
|
223
|
+
fnName: this.getPlaceholder() + predictableFunctionTag,
|
|
224
|
+
};
|
|
211
225
|
|
|
212
|
-
|
|
213
|
-
|
|
226
|
+
this.functionObjects.push(newFunctionObject);
|
|
227
|
+
currentBlock.$stringConcealingFunctionObject = newFunctionObject;
|
|
228
|
+
functionObject = newFunctionObject;
|
|
214
229
|
}
|
|
215
230
|
|
|
216
|
-
var fnName =
|
|
217
|
-
var encoder = Encoding[type];
|
|
231
|
+
var { fnName, encodingImplementation } = functionObject;
|
|
218
232
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
this.
|
|
224
|
-
|
|
233
|
+
var index = -1;
|
|
234
|
+
|
|
235
|
+
// String already decoded?
|
|
236
|
+
if (this.set.has(object.value)) {
|
|
237
|
+
var row = this.index[object.value];
|
|
238
|
+
if (parents.includes(row[2])) {
|
|
239
|
+
[index, fnName] = row;
|
|
240
|
+
ok(typeof index === "number");
|
|
241
|
+
}
|
|
225
242
|
}
|
|
226
243
|
|
|
227
|
-
|
|
228
|
-
|
|
244
|
+
if (index == -1) {
|
|
245
|
+
// The decode function must return correct result
|
|
246
|
+
var encoded = encodingImplementation.encode(object.value);
|
|
247
|
+
if (encodingImplementation.decode(encoded) !== object.value) {
|
|
248
|
+
this.ignore.add(object.value);
|
|
249
|
+
this.warn(
|
|
250
|
+
encodingImplementation.identity,
|
|
251
|
+
object.value.slice(0, 100)
|
|
252
|
+
);
|
|
253
|
+
delete EncodingImplementations[encodingImplementation.identity];
|
|
254
|
+
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
|
|
229
258
|
this.arrayExpression.elements.push(Literal(encoded));
|
|
230
259
|
index = this.arrayExpression.elements.length - 1;
|
|
231
|
-
this.index[object.value] = [index, fnName];
|
|
260
|
+
this.index[object.value] = [index, fnName, currentBlock];
|
|
232
261
|
|
|
233
262
|
this.set.add(object.value);
|
|
234
|
-
} else {
|
|
235
|
-
[index, fnName] = this.index[object.value];
|
|
236
|
-
ok(typeof index === "number");
|
|
237
263
|
}
|
|
238
264
|
|
|
239
265
|
ok(index != -1, "index == -1");
|
|
@@ -269,7 +295,7 @@ export default class StringConcealing extends Transform {
|
|
|
269
295
|
|
|
270
296
|
var constantReferenceType = choice(["variable", "array", "object"]);
|
|
271
297
|
|
|
272
|
-
var place =
|
|
298
|
+
var place = currentBlock;
|
|
273
299
|
if (!place) {
|
|
274
300
|
this.error(new Error("No lexical block to insert code"));
|
|
275
301
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import Transform from "../transform";
|
|
2
2
|
import { choice } from "../../util/random";
|
|
3
|
-
import { isDirective } from "../../util/compare";
|
|
4
|
-
import { isModuleSource } from "./stringConcealing";
|
|
3
|
+
import { isDirective, isModuleSource } from "../../util/compare";
|
|
5
4
|
import { ComputeProbabilityMap } from "../../probability";
|
|
6
5
|
import { Identifier } from "../../util/gen";
|
|
7
6
|
|
|
@@ -3,8 +3,7 @@ import { Node, Literal, BinaryExpression } from "../../util/gen";
|
|
|
3
3
|
import { clone } from "../../util/insert";
|
|
4
4
|
import { getRandomInteger, shuffle, splitIntoChunks } from "../../util/random";
|
|
5
5
|
import { ObfuscateOrder } from "../../order";
|
|
6
|
-
import { isModuleSource } from "
|
|
7
|
-
import { isDirective } from "../../util/compare";
|
|
6
|
+
import { isDirective, isModuleSource } from "../../util/compare";
|
|
8
7
|
import { ok } from "assert";
|
|
9
8
|
import { ComputeProbabilityMap } from "../../probability";
|
|
10
9
|
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import traverse, { ExitCallback } from "../traverse";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
AddComment,
|
|
4
|
+
Node,
|
|
5
|
+
VariableDeclaration,
|
|
6
|
+
VariableDeclarator,
|
|
7
|
+
} from "../util/gen";
|
|
3
8
|
import {
|
|
4
9
|
alphabeticalGenerator,
|
|
5
10
|
choice,
|
|
@@ -15,6 +20,8 @@ import {
|
|
|
15
20
|
reservedKeywords,
|
|
16
21
|
} from "../constants";
|
|
17
22
|
import { ObfuscateOrder } from "../order";
|
|
23
|
+
import { ITemplate } from "../templates/template";
|
|
24
|
+
import { prepend } from "../util/insert";
|
|
18
25
|
|
|
19
26
|
/**
|
|
20
27
|
* Base-class for all transformations.
|
|
@@ -78,6 +85,8 @@ export default class Transform {
|
|
|
78
85
|
*/
|
|
79
86
|
after: Transform[];
|
|
80
87
|
|
|
88
|
+
initVariables = new Map<string, string>();
|
|
89
|
+
|
|
81
90
|
constructor(obfuscator, priority: number = -1) {
|
|
82
91
|
ok(obfuscator instanceof Obfuscator, "obfuscator should be an Obfuscator");
|
|
83
92
|
|
|
@@ -336,6 +345,26 @@ export default class Transform {
|
|
|
336
345
|
return identifier;
|
|
337
346
|
}
|
|
338
347
|
|
|
348
|
+
createInitVariable = (value: ITemplate, parents: Node[]) => {
|
|
349
|
+
var key = value.templates[0];
|
|
350
|
+
if (this.initVariables.has(key)) {
|
|
351
|
+
return this.initVariables.get(key);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
var root = parents[parents.length - 1];
|
|
355
|
+
ok(root.type === "Program");
|
|
356
|
+
|
|
357
|
+
var name = this.getPlaceholder();
|
|
358
|
+
this.initVariables.set(key, name);
|
|
359
|
+
|
|
360
|
+
prepend(
|
|
361
|
+
root,
|
|
362
|
+
VariableDeclaration(VariableDeclarator(name, value.single().expression))
|
|
363
|
+
);
|
|
364
|
+
|
|
365
|
+
return name;
|
|
366
|
+
};
|
|
367
|
+
|
|
339
368
|
/**
|
|
340
369
|
* Smartly appends a comment to a Node.
|
|
341
370
|
* - Includes the transformation's name.
|
package/src/util/compare.ts
CHANGED
|
@@ -74,19 +74,52 @@ export function isDirective(object: Node, parents: Node[]) {
|
|
|
74
74
|
return parents[dIndex].expression == (parents[dIndex - 1] || object);
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
export function isModuleSource(object: Node, parents: Node[]) {
|
|
78
|
+
if (!parents[0]) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (parents[0].type == "ImportDeclaration" && parents[0].source == object) {
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (parents[0].type == "ImportExpression" && parents[0].source == object) {
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (
|
|
91
|
+
parents[1] &&
|
|
92
|
+
parents[1].type == "CallExpression" &&
|
|
93
|
+
parents[1].arguments[0] === object &&
|
|
94
|
+
parents[1].callee.type == "Identifier"
|
|
95
|
+
) {
|
|
96
|
+
if (
|
|
97
|
+
parents[1].callee.name == "require" ||
|
|
98
|
+
parents[1].callee.name == "import"
|
|
99
|
+
) {
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function isMoveable(object: Node, parents: Node[]) {
|
|
108
|
+
return !isDirective(object, parents) && !isModuleSource(object, parents);
|
|
109
|
+
}
|
|
110
|
+
|
|
77
111
|
export function isIndependent(object: Node, parents: Node[]) {
|
|
78
112
|
if (object.type == "Literal") {
|
|
79
113
|
return true;
|
|
80
114
|
}
|
|
81
115
|
|
|
82
|
-
var parent = parents[0];
|
|
83
|
-
|
|
84
116
|
if (object.type == "Identifier") {
|
|
85
|
-
|
|
86
|
-
if (set.has(object.name)) {
|
|
117
|
+
if (primitiveIdentifiers.has(object.name)) {
|
|
87
118
|
return true;
|
|
88
119
|
}
|
|
89
|
-
|
|
120
|
+
|
|
121
|
+
var parent = parents[0];
|
|
122
|
+
if (parent && parent.type == "Property") {
|
|
90
123
|
if (!parent.computed && parent.key == object) {
|
|
91
124
|
return true;
|
|
92
125
|
}
|
|
@@ -105,6 +138,7 @@ export function isIndependent(object: Node, parents: Node[]) {
|
|
|
105
138
|
if (object != $object) {
|
|
106
139
|
if (!Array.isArray($object) && !isIndependent($object, $parents)) {
|
|
107
140
|
allowIt = false;
|
|
141
|
+
return "EXIT";
|
|
108
142
|
}
|
|
109
143
|
}
|
|
110
144
|
});
|
package/src/util/gen.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ok } from "assert";
|
|
2
|
+
import { predictableFunctionTag } from "../constants";
|
|
2
3
|
import { isValidIdentifier } from "./compare";
|
|
3
4
|
|
|
4
5
|
export type Type =
|
|
@@ -306,6 +307,7 @@ export function FunctionExpression(params: Node[], body: any[]) {
|
|
|
306
307
|
generator: false,
|
|
307
308
|
expression: false,
|
|
308
309
|
async: false,
|
|
310
|
+
[predictableFunctionTag]: true,
|
|
309
311
|
};
|
|
310
312
|
}
|
|
311
313
|
|
|
@@ -340,6 +342,7 @@ export function FunctionDeclaration(
|
|
|
340
342
|
generator: false,
|
|
341
343
|
expression: false,
|
|
342
344
|
async: false,
|
|
345
|
+
[predictableFunctionTag]: true,
|
|
343
346
|
};
|
|
344
347
|
}
|
|
345
348
|
|
|
@@ -529,16 +532,20 @@ export function AddComment(node: Node, text: string) {
|
|
|
529
532
|
return node;
|
|
530
533
|
}
|
|
531
534
|
|
|
535
|
+
export function Super() {
|
|
536
|
+
return { type: "Super" };
|
|
537
|
+
}
|
|
538
|
+
|
|
532
539
|
export function MethodDefinition(
|
|
533
|
-
|
|
540
|
+
key: Node,
|
|
534
541
|
functionExpression: Node,
|
|
535
542
|
kind: "method" | "constructor" | "get" | "set",
|
|
536
|
-
isStatic =
|
|
543
|
+
isStatic = false,
|
|
537
544
|
computed = false
|
|
538
545
|
) {
|
|
539
546
|
return {
|
|
540
547
|
type: "MethodDefinition",
|
|
541
|
-
key:
|
|
548
|
+
key: key,
|
|
542
549
|
computed: computed,
|
|
543
550
|
value: functionExpression,
|
|
544
551
|
kind: kind,
|
package/src/util/identifiers.ts
CHANGED
|
@@ -94,9 +94,14 @@ export function getIdentifierInfo(object: Node, parents: Node[]) {
|
|
|
94
94
|
parents.find((x) => x.type == "VariableDeclaration") &&
|
|
95
95
|
objectPatternCheck(object, parents);
|
|
96
96
|
|
|
97
|
+
var functionIndex = parents.findIndex((x) => isFunction(x));
|
|
98
|
+
|
|
97
99
|
// Assignment pattern check!
|
|
98
100
|
if (isVariableDeclaration) {
|
|
99
|
-
var slicedParents = parents.slice(
|
|
101
|
+
var slicedParents = parents.slice(
|
|
102
|
+
0,
|
|
103
|
+
functionIndex != -1 ? Math.min(varIndex, functionIndex) : varIndex
|
|
104
|
+
);
|
|
100
105
|
var i = 0;
|
|
101
106
|
for (var parent of slicedParents) {
|
|
102
107
|
var childNode = slicedParents[i - 1] || object;
|
|
@@ -113,8 +118,6 @@ export function getIdentifierInfo(object: Node, parents: Node[]) {
|
|
|
113
118
|
forIndex != -1 &&
|
|
114
119
|
parents[forIndex].init == (parents[forIndex - 1] || object);
|
|
115
120
|
|
|
116
|
-
var functionIndex = parents.findIndex((x) => isFunction(x));
|
|
117
|
-
|
|
118
121
|
var isFunctionDeclaration =
|
|
119
122
|
functionIndex != -1 &&
|
|
120
123
|
parents[functionIndex].type == "FunctionDeclaration" &&
|
package/src/util/insert.ts
CHANGED
|
@@ -3,6 +3,12 @@ import { getBlock, isBlock } from "../traverse";
|
|
|
3
3
|
import { Node } from "./gen";
|
|
4
4
|
import { getIdentifierInfo, validateChain } from "./identifiers";
|
|
5
5
|
|
|
6
|
+
export function isClass(object: Node): boolean {
|
|
7
|
+
return (
|
|
8
|
+
object.type === "ClassDeclaration" || object.type === "ClassExpression"
|
|
9
|
+
);
|
|
10
|
+
}
|
|
11
|
+
|
|
6
12
|
/**
|
|
7
13
|
* - `FunctionDeclaration`
|
|
8
14
|
* - `FunctionExpression`
|
|
@@ -18,6 +24,17 @@ export function isFunction(object: Node): boolean {
|
|
|
18
24
|
].includes(object && object.type);
|
|
19
25
|
}
|
|
20
26
|
|
|
27
|
+
export function isStrictModeFunction(object: Node): boolean {
|
|
28
|
+
ok(isFunction(object));
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
object.body.type === "BlockStatement" &&
|
|
32
|
+
object.body.body[0] &&
|
|
33
|
+
object.body.body[0].type === "ExpressionStatement" &&
|
|
34
|
+
object.body.body[0].directive === "use strict"
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
21
38
|
/**
|
|
22
39
|
* The function context where the object is.
|
|
23
40
|
*
|
package/src/util/scope.ts
CHANGED
|
@@ -1,9 +1,21 @@
|
|
|
1
|
+
import { ok } from "assert";
|
|
1
2
|
import { isBlock } from "../traverse";
|
|
3
|
+
import { Node } from "./gen";
|
|
2
4
|
|
|
3
|
-
export function isLexicalScope(object) {
|
|
5
|
+
export function isLexicalScope(object: Node) {
|
|
4
6
|
return isBlock(object) || object.type == "SwitchCase";
|
|
5
7
|
}
|
|
6
8
|
|
|
7
|
-
export function getLexicalScope(object, parents) {
|
|
9
|
+
export function getLexicalScope(object: Node, parents: Node[]): Node {
|
|
8
10
|
return [object, ...parents].find((node) => isLexicalScope(node));
|
|
9
11
|
}
|
|
12
|
+
|
|
13
|
+
export function getLexicalScopeBody(object: Node): Node[] {
|
|
14
|
+
ok(isLexicalScope(object));
|
|
15
|
+
|
|
16
|
+
return isBlock(object)
|
|
17
|
+
? object.body
|
|
18
|
+
: object.type === "SwitchCase"
|
|
19
|
+
? object.consequent
|
|
20
|
+
: ok("Unhandled case");
|
|
21
|
+
}
|
package/test/code/Cash.test.ts
CHANGED
|
@@ -32,12 +32,18 @@ test("Variant #1: Cash.js on High Preset (Strict Mode)", async () => {
|
|
|
32
32
|
$: false,
|
|
33
33
|
} as any;
|
|
34
34
|
window.window = window;
|
|
35
|
+
global.window = window;
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
try {
|
|
38
|
+
eval(output);
|
|
39
|
+
} catch (e) {
|
|
40
|
+
console.error(e);
|
|
41
|
+
writeFileSync("dev.output.js", output, {
|
|
42
|
+
encoding: "utf-8",
|
|
43
|
+
});
|
|
39
44
|
|
|
40
|
-
|
|
45
|
+
expect(true).toStrictEqual(false);
|
|
46
|
+
}
|
|
41
47
|
|
|
42
48
|
expect(window).toHaveProperty("cash");
|
|
43
49
|
});
|