js-confuser 1.5.6 → 1.5.7
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 +14 -0
- package/dist/transforms/lock/integrity.js +6 -2
- package/dist/transforms/lock/lock.js +40 -32
- package/dist/transforms/preparation/preparation.js +0 -7
- package/dist/transforms/rgf.js +32 -3
- package/package.json +1 -1
- package/src/transforms/lock/integrity.ts +13 -1
- package/src/transforms/lock/lock.ts +81 -44
- package/src/transforms/preparation/preparation.ts +2 -21
- package/src/transforms/rgf.ts +39 -3
- package/test/transforms/lock/countermeasures.test.ts +18 -0
- package/test/transforms/rgf.test.ts +37 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
# `1.5.7`
|
|
2
|
+
Countermeasures function fixes
|
|
3
|
+
|
|
4
|
+
This update focuses on fixing Countermeasures bugs
|
|
5
|
+
|
|
6
|
+
The `countermeasures` is custom callback function to invoke when a lock is triggered.
|
|
7
|
+
|
|
8
|
+
- Fixed [#66](https://github.com/MichaelXF/js-confuser/issues/66)
|
|
9
|
+
- - RGF to properly handle the countermeasures function
|
|
10
|
+
|
|
11
|
+
- Added additional code to prevent an infinite loop from occurring
|
|
12
|
+
|
|
13
|
+
- Slight improvements to RGF
|
|
14
|
+
|
|
1
15
|
# `1.5.6`
|
|
2
16
|
Website changed and RGF fixes
|
|
3
17
|
|
|
@@ -148,7 +148,7 @@ class Integrity extends _transform.default {
|
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
return () => {
|
|
151
|
-
object.__hiddenCountermeasures = this.lock.getCounterMeasuresCode();
|
|
151
|
+
object.__hiddenCountermeasures = this.lock.getCounterMeasuresCode(object, parents);
|
|
152
152
|
|
|
153
153
|
object.$eval = () => {
|
|
154
154
|
var functionName = this.generateIdentifier();
|
|
@@ -178,7 +178,11 @@ class Integrity extends _transform.default {
|
|
|
178
178
|
ifStatement.alternate = (0, _gen.BlockStatement)(object.__hiddenCountermeasures);
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
-
object.body = (0, _gen.BlockStatement)([functionDeclaration, (0, _gen.VariableDeclaration)((0, _gen.VariableDeclarator)(hashName, (0, _gen.CallExpression)((0, _insert.clone)(this.hashFn), [(0, _gen.CallExpression)((0, _insert.clone)(this.stringFn), [(0, _gen.Identifier)(functionName)]), (0, _gen.Literal)(this.seed)]))), ifStatement]);
|
|
181
|
+
object.body = (0, _gen.BlockStatement)([functionDeclaration, (0, _gen.VariableDeclaration)((0, _gen.VariableDeclarator)(hashName, (0, _gen.CallExpression)((0, _insert.clone)(this.hashFn), [(0, _gen.CallExpression)((0, _insert.clone)(this.stringFn), [(0, _gen.Identifier)(functionName)]), (0, _gen.Literal)(this.seed)]))), ifStatement]); // Make sure the countermeasures activation variable is present
|
|
182
|
+
|
|
183
|
+
if (this.lock.counterMeasuresActivated) {
|
|
184
|
+
object.body.body.unshift((0, _gen.VariableDeclaration)((0, _gen.VariableDeclarator)(this.lock.counterMeasuresActivated)));
|
|
185
|
+
}
|
|
182
186
|
|
|
183
187
|
if (object.type == "ArrowFunctionExpression") {
|
|
184
188
|
object.type = "FunctionExpression";
|
|
@@ -43,6 +43,10 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
|
|
|
43
43
|
* Applies browser & date locks.
|
|
44
44
|
*/
|
|
45
45
|
class Lock extends _transform.default {
|
|
46
|
+
/**
|
|
47
|
+
* This is a boolean variable injected into the source code determining wether the countermeasures function has been called.
|
|
48
|
+
* This is used to prevent infinite loops from happening
|
|
49
|
+
*/
|
|
46
50
|
constructor(o) {
|
|
47
51
|
super(o, _order.ObfuscateOrder.Lock); // Removed feature
|
|
48
52
|
// if (this.options.lock.startDate && this.options.lock.endDate) {
|
|
@@ -55,6 +59,8 @@ class Lock extends _transform.default {
|
|
|
55
59
|
|
|
56
60
|
_defineProperty(this, "iosDetectFn", void 0);
|
|
57
61
|
|
|
62
|
+
_defineProperty(this, "counterMeasuresActivated", void 0);
|
|
63
|
+
|
|
58
64
|
_defineProperty(this, "made", void 0);
|
|
59
65
|
|
|
60
66
|
if (this.options.lock.integrity) {
|
|
@@ -70,34 +76,29 @@ class Lock extends _transform.default {
|
|
|
70
76
|
|
|
71
77
|
apply(tree) {
|
|
72
78
|
if (typeof this.options.lock.countermeasures === "string" && (0, _compare.isValidIdentifier)(this.options.lock.countermeasures)) {
|
|
73
|
-
var defined = new Set();
|
|
74
79
|
(0, _traverse.default)(tree, (object, parents) => {
|
|
75
|
-
if (object.type == "Identifier") {
|
|
80
|
+
if (object.type == "Identifier" && object.name === this.options.lock.countermeasures) {
|
|
76
81
|
var info = (0, _identifiers.getIdentifierInfo)(object, parents);
|
|
77
82
|
|
|
78
83
|
if (info.spec.isDefined) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
throw new Error("Countermeasures function was already defined, it must have a unique name from the rest of your code");
|
|
84
|
-
} else {
|
|
85
|
-
var definingContext = (0, _insert.getVarContext)(parents[0], parents.slice(1));
|
|
86
|
-
|
|
87
|
-
if (definingContext != tree) {
|
|
88
|
-
throw new Error("Countermeasures function must be defined at the global level");
|
|
89
|
-
}
|
|
84
|
+
if (this.counterMeasuresNode) {
|
|
85
|
+
throw new Error("Countermeasures function was already defined, it must have a unique name from the rest of your code");
|
|
86
|
+
} else {
|
|
87
|
+
var definingContext = (0, _insert.getVarContext)(parents[0], parents.slice(1));
|
|
90
88
|
|
|
91
|
-
|
|
89
|
+
if (definingContext != tree) {
|
|
90
|
+
throw new Error("Countermeasures function must be defined at the global level");
|
|
91
|
+
}
|
|
92
92
|
|
|
93
|
-
|
|
94
|
-
chain = [parents[0], parents.slice(1)];
|
|
95
|
-
} else if (info.isVariableDeclaration) {
|
|
96
|
-
chain = [parents[1], parents.slice(2)];
|
|
97
|
-
}
|
|
93
|
+
var chain = [object, parents];
|
|
98
94
|
|
|
99
|
-
|
|
95
|
+
if (info.isFunctionDeclaration) {
|
|
96
|
+
chain = [parents[0], parents.slice(1)];
|
|
97
|
+
} else if (info.isVariableDeclaration) {
|
|
98
|
+
chain = [parents[1], parents.slice(2)];
|
|
100
99
|
}
|
|
100
|
+
|
|
101
|
+
this.counterMeasuresNode = chain;
|
|
101
102
|
}
|
|
102
103
|
}
|
|
103
104
|
}
|
|
@@ -111,7 +112,7 @@ class Lock extends _transform.default {
|
|
|
111
112
|
super.apply(tree);
|
|
112
113
|
}
|
|
113
114
|
|
|
114
|
-
getCounterMeasuresCode() {
|
|
115
|
+
getCounterMeasuresCode(object, parents) {
|
|
115
116
|
var opt = this.options.lock.countermeasures;
|
|
116
117
|
|
|
117
118
|
if (opt === false) {
|
|
@@ -120,8 +121,13 @@ class Lock extends _transform.default {
|
|
|
120
121
|
|
|
121
122
|
|
|
122
123
|
if (typeof opt === "string") {
|
|
123
|
-
|
|
124
|
-
|
|
124
|
+
if (!this.counterMeasuresActivated) {
|
|
125
|
+
this.counterMeasuresActivated = this.getPlaceholder();
|
|
126
|
+
(0, _insert.prepend)(parents[parents.length - 1] || object, (0, _gen.VariableDeclaration)((0, _gen.VariableDeclarator)(this.counterMeasuresActivated)));
|
|
127
|
+
} // Since Lock occurs before variable renaming, we are using the pre-obfuscated function name
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
return [(0, _gen.ExpressionStatement)((0, _gen.LogicalExpression)("||", (0, _gen.Identifier)(this.counterMeasuresActivated), (0, _gen.SequenceExpression)([(0, _gen.AssignmentExpression)("=", (0, _gen.Identifier)(this.counterMeasuresActivated), (0, _gen.Literal)(true)), (0, _gen.CallExpression)((0, _template.default)(opt).single().expression, [])])))];
|
|
125
131
|
}
|
|
126
132
|
|
|
127
133
|
var type = (0, _random.choice)(["crash", "exit"]);
|
|
@@ -239,7 +245,7 @@ class Lock extends _transform.default {
|
|
|
239
245
|
// A very simple mechanism inspired from https://github.com/javascript-obfuscator/javascript-obfuscator/blob/master/src/custom-code-helpers/self-defending/templates/SelfDefendingNoEvalTemplate.ts
|
|
240
246
|
// regExp checks for a newline, formatters add these
|
|
241
247
|
var callExpression = (0, _template.default)("\n (\n function(){\n // Breaks JSNice.org, beautifier.io\n var namedFunction = function(){\n const test = function(){\n const regExp=new RegExp('\\n');\n return regExp['test'](namedFunction)\n };\n return test()\n }\n\n return namedFunction();\n }\n )()\n ").single().expression;
|
|
242
|
-
nodes.push((0, _gen.IfStatement)(callExpression, this.getCounterMeasuresCode() || [], null));
|
|
248
|
+
nodes.push((0, _gen.IfStatement)(callExpression, this.getCounterMeasuresCode(object, parents) || [], null));
|
|
243
249
|
break;
|
|
244
250
|
|
|
245
251
|
case "nativeFunction":
|
|
@@ -270,23 +276,24 @@ class Lock extends _transform.default {
|
|
|
270
276
|
test = (0, _template.default)("".concat(fn, ".toString().split(\"{ [native code] }\").length <= 1")).single().expression;
|
|
271
277
|
}
|
|
272
278
|
|
|
273
|
-
nodes.push((0, _gen.IfStatement)(test, this.getCounterMeasuresCode() || [], null));
|
|
279
|
+
nodes.push((0, _gen.IfStatement)(test, this.getCounterMeasuresCode(object, parents) || [], null));
|
|
274
280
|
}
|
|
275
281
|
|
|
276
282
|
break;
|
|
277
283
|
|
|
278
284
|
case "startDate":
|
|
279
285
|
test = (0, _gen.BinaryExpression)("<", dateNow, (0, _gen.Literal)(this.getTime(this.options.lock.startDate)));
|
|
280
|
-
nodes.push((0, _gen.IfStatement)(test, this.getCounterMeasuresCode() || [], null));
|
|
286
|
+
nodes.push((0, _gen.IfStatement)(test, this.getCounterMeasuresCode(object, parents) || [], null));
|
|
281
287
|
break;
|
|
282
288
|
|
|
283
289
|
case "endDate":
|
|
284
290
|
test = (0, _gen.BinaryExpression)(">", dateNow, (0, _gen.Literal)(this.getTime(this.options.lock.endDate)));
|
|
285
|
-
nodes.push((0, _gen.IfStatement)(test, this.getCounterMeasuresCode() || [], null));
|
|
291
|
+
nodes.push((0, _gen.IfStatement)(test, this.getCounterMeasuresCode(object, parents) || [], null));
|
|
286
292
|
break;
|
|
287
293
|
|
|
288
294
|
case "context":
|
|
289
|
-
var prop = (0, _random.choice)(this.options.lock.context);
|
|
295
|
+
var prop = (0, _random.choice)(this.options.lock.context);
|
|
296
|
+
var code = this.getCounterMeasuresCode(object, parents) || []; // Todo: Alternative to `this`
|
|
290
297
|
|
|
291
298
|
if (!this.globalVar) {
|
|
292
299
|
offset = 1;
|
|
@@ -295,12 +302,13 @@ class Lock extends _transform.default {
|
|
|
295
302
|
}
|
|
296
303
|
|
|
297
304
|
test = (0, _gen.UnaryExpression)("!", (0, _gen.MemberExpression)((0, _gen.Identifier)(this.globalVar), (0, _gen.Literal)(prop), true));
|
|
298
|
-
nodes.push((0, _gen.IfStatement)(test,
|
|
305
|
+
nodes.push((0, _gen.IfStatement)(test, code, null));
|
|
299
306
|
break;
|
|
300
307
|
|
|
301
308
|
case "osLock":
|
|
302
309
|
var navigatorUserAgent = (0, _template.default)("window.navigator.userAgent.toLowerCase()").single().expression;
|
|
303
310
|
(0, _assert.ok)(this.options.lock.osLock);
|
|
311
|
+
var code = this.getCounterMeasuresCode(object, parents) || [];
|
|
304
312
|
this.options.lock.osLock.forEach(osName => {
|
|
305
313
|
var agentMatcher = {
|
|
306
314
|
windows: "Win",
|
|
@@ -338,7 +346,7 @@ class Lock extends _transform.default {
|
|
|
338
346
|
});
|
|
339
347
|
test = (0, _gen.UnaryExpression)("!", { ...test
|
|
340
348
|
});
|
|
341
|
-
nodes.push((0, _gen.IfStatement)(test,
|
|
349
|
+
nodes.push((0, _gen.IfStatement)(test, code, null));
|
|
342
350
|
break;
|
|
343
351
|
|
|
344
352
|
case "browserLock":
|
|
@@ -360,7 +368,7 @@ class Lock extends _transform.default {
|
|
|
360
368
|
});
|
|
361
369
|
test = (0, _gen.UnaryExpression)("!", { ...test
|
|
362
370
|
});
|
|
363
|
-
nodes.push((0, _gen.IfStatement)(test, this.getCounterMeasuresCode() || [], null));
|
|
371
|
+
nodes.push((0, _gen.IfStatement)(test, this.getCounterMeasuresCode(object, parents) || [], null));
|
|
364
372
|
break;
|
|
365
373
|
|
|
366
374
|
case "domainLock":
|
|
@@ -392,7 +400,7 @@ class Lock extends _transform.default {
|
|
|
392
400
|
test = (0, _gen.LogicalExpression)("||", (0, _gen.BinaryExpression)("==", (0, _gen.UnaryExpression)("typeof", (0, _gen.Identifier)("location")), (0, _gen.Literal)("undefined")), test);
|
|
393
401
|
}
|
|
394
402
|
|
|
395
|
-
nodes.push((0, _gen.IfStatement)(test, this.getCounterMeasuresCode() || [], null));
|
|
403
|
+
nodes.push((0, _gen.IfStatement)(test, this.getCounterMeasuresCode(object, parents) || [], null));
|
|
396
404
|
}
|
|
397
405
|
|
|
398
406
|
break;
|
|
@@ -17,8 +17,6 @@ var _identifiers = require("../../util/identifiers");
|
|
|
17
17
|
|
|
18
18
|
var _label = _interopRequireDefault(require("../label"));
|
|
19
19
|
|
|
20
|
-
var _antiDestructuring = _interopRequireDefault(require("../es5/antiDestructuring"));
|
|
21
|
-
|
|
22
20
|
var _compare = require("../../util/compare");
|
|
23
21
|
|
|
24
22
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
@@ -179,11 +177,6 @@ class Preparation extends _transform.default {
|
|
|
179
177
|
this.before.push(new _label.default(o));
|
|
180
178
|
this.before.push(new ExplicitIdentifiers(o));
|
|
181
179
|
this.before.push(new ExplicitDeclarations(o));
|
|
182
|
-
|
|
183
|
-
if (this.options.es5) {
|
|
184
|
-
this.before.push(new _antiDestructuring.default(o));
|
|
185
|
-
} // this.before.push(new NameConflicts(o));
|
|
186
|
-
|
|
187
180
|
}
|
|
188
181
|
|
|
189
182
|
match() {
|
package/dist/transforms/rgf.js
CHANGED
|
@@ -75,6 +75,8 @@ class RGF extends _transform.default {
|
|
|
75
75
|
var definingNodes = new Map();
|
|
76
76
|
(0, _traverse.walk)(contextObject, contextParents, (object, parents) => {
|
|
77
77
|
if (object !== contextObject && (0, _insert.isFunction)(object) && !object.$requiresEval && !object.async && !object.generator && (0, _insert.getVarContext)(parents[0], parents.slice(1)) === contextObject) {
|
|
78
|
+
var _this$options$lock;
|
|
79
|
+
|
|
78
80
|
// Discard getter/setter methods
|
|
79
81
|
if (parents[0].type === "Property" && parents[0].value === object) {
|
|
80
82
|
if (parents[0].method || parents[0].kind === "get" || parents[0].kind === "set") {
|
|
@@ -85,12 +87,36 @@ class RGF extends _transform.default {
|
|
|
85
87
|
|
|
86
88
|
if (parents[0].type === "MethodDefinition" && parents[0].value === object) {
|
|
87
89
|
return;
|
|
90
|
+
} // Avoid applying to the countermeasures function
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
if (typeof ((_this$options$lock = this.options.lock) === null || _this$options$lock === void 0 ? void 0 : _this$options$lock.countermeasures) === "string") {
|
|
94
|
+
// function countermeasures(){...}
|
|
95
|
+
if (object.type === "FunctionDeclaration" && object.id.type === "Identifier" && object.id.name === this.options.lock.countermeasures) {
|
|
96
|
+
return;
|
|
97
|
+
} // var countermeasures = function(){...}
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
if (parents[0].type === "VariableDeclarator" && parents[0].init === object && parents[0].id.type === "Identifier" && parents[0].id.name === this.options.lock.countermeasures) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
88
103
|
}
|
|
89
104
|
|
|
90
105
|
var defined = new Set(),
|
|
91
106
|
referenced = new Set();
|
|
92
107
|
var isBound = false;
|
|
93
|
-
|
|
108
|
+
/**
|
|
109
|
+
* The fnTraverses serves two important purposes
|
|
110
|
+
*
|
|
111
|
+
* - Identify all the variables referenced and defined here
|
|
112
|
+
* - Identify is the 'this' keyword is used anywhere
|
|
113
|
+
*
|
|
114
|
+
* @param o
|
|
115
|
+
* @param p
|
|
116
|
+
* @returns
|
|
117
|
+
*/
|
|
118
|
+
|
|
119
|
+
const fnTraverser = (o, p) => {
|
|
94
120
|
if (o.type == "Identifier" && !_constants.reservedIdentifiers.has(o.name) && !this.options.globalVariables.has(o.name)) {
|
|
95
121
|
var info = (0, _identifiers.getIdentifierInfo)(o, p);
|
|
96
122
|
|
|
@@ -98,7 +124,7 @@ class RGF extends _transform.default {
|
|
|
98
124
|
return;
|
|
99
125
|
}
|
|
100
126
|
|
|
101
|
-
if (info.spec.isDefined) {
|
|
127
|
+
if (info.spec.isDefined && (0, _insert.getDefiningContext)(o, p) === object) {
|
|
102
128
|
defined.add(o.name);
|
|
103
129
|
} else {
|
|
104
130
|
referenced.add(o.name);
|
|
@@ -108,7 +134,10 @@ class RGF extends _transform.default {
|
|
|
108
134
|
if (o.type == "ThisExpression" || o.type == "Super") {
|
|
109
135
|
isBound = true;
|
|
110
136
|
}
|
|
111
|
-
}
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
(0, _traverse.walk)(object.params, [object, ...parents], fnTraverser);
|
|
140
|
+
(0, _traverse.walk)(object.body, [object, ...parents], fnTraverser);
|
|
112
141
|
|
|
113
142
|
if (!isBound) {
|
|
114
143
|
var _object$id;
|
package/package.json
CHANGED
|
@@ -195,7 +195,10 @@ export default class Integrity extends Transform {
|
|
|
195
195
|
}
|
|
196
196
|
|
|
197
197
|
return () => {
|
|
198
|
-
object.__hiddenCountermeasures = this.lock.getCounterMeasuresCode(
|
|
198
|
+
object.__hiddenCountermeasures = this.lock.getCounterMeasuresCode(
|
|
199
|
+
object,
|
|
200
|
+
parents
|
|
201
|
+
);
|
|
199
202
|
|
|
200
203
|
object.$eval = () => {
|
|
201
204
|
var functionName = this.generateIdentifier();
|
|
@@ -258,6 +261,15 @@ export default class Integrity extends Transform {
|
|
|
258
261
|
ifStatement,
|
|
259
262
|
]);
|
|
260
263
|
|
|
264
|
+
// Make sure the countermeasures activation variable is present
|
|
265
|
+
if (this.lock.counterMeasuresActivated) {
|
|
266
|
+
object.body.body.unshift(
|
|
267
|
+
VariableDeclaration(
|
|
268
|
+
VariableDeclarator(this.lock.counterMeasuresActivated)
|
|
269
|
+
)
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
|
|
261
273
|
if (object.type == "ArrowFunctionExpression") {
|
|
262
274
|
object.type = "FunctionExpression";
|
|
263
275
|
object.expression = false;
|
|
@@ -11,17 +11,12 @@ import {
|
|
|
11
11
|
Literal,
|
|
12
12
|
UnaryExpression,
|
|
13
13
|
NewExpression,
|
|
14
|
-
FunctionDeclaration,
|
|
15
|
-
ReturnStatement,
|
|
16
14
|
VariableDeclaration,
|
|
17
|
-
ObjectExpression,
|
|
18
|
-
Property,
|
|
19
|
-
ArrayExpression,
|
|
20
|
-
FunctionExpression,
|
|
21
15
|
ThisExpression,
|
|
22
16
|
VariableDeclarator,
|
|
23
17
|
Location,
|
|
24
18
|
LogicalExpression,
|
|
19
|
+
SequenceExpression,
|
|
25
20
|
} from "../../util/gen";
|
|
26
21
|
import traverse, { getBlock, isBlock } from "../../traverse";
|
|
27
22
|
import { choice, getRandomInteger } from "../../util/random";
|
|
@@ -47,6 +42,12 @@ export default class Lock extends Transform {
|
|
|
47
42
|
counterMeasuresNode: Location;
|
|
48
43
|
iosDetectFn: string;
|
|
49
44
|
|
|
45
|
+
/**
|
|
46
|
+
* This is a boolean variable injected into the source code determining wether the countermeasures function has been called.
|
|
47
|
+
* This is used to prevent infinite loops from happening
|
|
48
|
+
*/
|
|
49
|
+
counterMeasuresActivated: string;
|
|
50
|
+
|
|
50
51
|
made: number;
|
|
51
52
|
|
|
52
53
|
constructor(o) {
|
|
@@ -73,36 +74,32 @@ export default class Lock extends Transform {
|
|
|
73
74
|
typeof this.options.lock.countermeasures === "string" &&
|
|
74
75
|
isValidIdentifier(this.options.lock.countermeasures)
|
|
75
76
|
) {
|
|
76
|
-
var defined = new Set<string>();
|
|
77
77
|
traverse(tree, (object, parents) => {
|
|
78
|
-
if (
|
|
78
|
+
if (
|
|
79
|
+
object.type == "Identifier" &&
|
|
80
|
+
object.name === this.options.lock.countermeasures
|
|
81
|
+
) {
|
|
79
82
|
var info = getIdentifierInfo(object, parents);
|
|
80
83
|
if (info.spec.isDefined) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
+
if (this.counterMeasuresNode) {
|
|
85
|
+
throw new Error(
|
|
86
|
+
"Countermeasures function was already defined, it must have a unique name from the rest of your code"
|
|
87
|
+
);
|
|
88
|
+
} else {
|
|
89
|
+
var definingContext = getVarContext(parents[0], parents.slice(1));
|
|
90
|
+
if (definingContext != tree) {
|
|
84
91
|
throw new Error(
|
|
85
|
-
"Countermeasures function
|
|
86
|
-
);
|
|
87
|
-
} else {
|
|
88
|
-
var definingContext = getVarContext(
|
|
89
|
-
parents[0],
|
|
90
|
-
parents.slice(1)
|
|
92
|
+
"Countermeasures function must be defined at the global level"
|
|
91
93
|
);
|
|
92
|
-
if (definingContext != tree) {
|
|
93
|
-
throw new Error(
|
|
94
|
-
"Countermeasures function must be defined at the global level"
|
|
95
|
-
);
|
|
96
|
-
}
|
|
97
|
-
var chain: Location = [object, parents];
|
|
98
|
-
if (info.isFunctionDeclaration) {
|
|
99
|
-
chain = [parents[0], parents.slice(1)];
|
|
100
|
-
} else if (info.isVariableDeclaration) {
|
|
101
|
-
chain = [parents[1], parents.slice(2)];
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
this.counterMeasuresNode = chain;
|
|
105
94
|
}
|
|
95
|
+
var chain: Location = [object, parents];
|
|
96
|
+
if (info.isFunctionDeclaration) {
|
|
97
|
+
chain = [parents[0], parents.slice(1)];
|
|
98
|
+
} else if (info.isVariableDeclaration) {
|
|
99
|
+
chain = [parents[1], parents.slice(2)];
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
this.counterMeasuresNode = chain;
|
|
106
103
|
}
|
|
107
104
|
}
|
|
108
105
|
}
|
|
@@ -120,7 +117,7 @@ export default class Lock extends Transform {
|
|
|
120
117
|
super.apply(tree);
|
|
121
118
|
}
|
|
122
119
|
|
|
123
|
-
getCounterMeasuresCode(): Node[] {
|
|
120
|
+
getCounterMeasuresCode(object: Node, parents: Node[]): Node[] {
|
|
124
121
|
var opt = this.options.lock.countermeasures;
|
|
125
122
|
|
|
126
123
|
if (opt === false) {
|
|
@@ -129,10 +126,30 @@ export default class Lock extends Transform {
|
|
|
129
126
|
|
|
130
127
|
// Call function
|
|
131
128
|
if (typeof opt === "string") {
|
|
129
|
+
if (!this.counterMeasuresActivated) {
|
|
130
|
+
this.counterMeasuresActivated = this.getPlaceholder();
|
|
131
|
+
|
|
132
|
+
prepend(
|
|
133
|
+
parents[parents.length - 1] || object,
|
|
134
|
+
VariableDeclaration(VariableDeclarator(this.counterMeasuresActivated))
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
132
138
|
// Since Lock occurs before variable renaming, we are using the pre-obfuscated function name
|
|
133
139
|
return [
|
|
134
140
|
ExpressionStatement(
|
|
135
|
-
|
|
141
|
+
LogicalExpression(
|
|
142
|
+
"||",
|
|
143
|
+
Identifier(this.counterMeasuresActivated),
|
|
144
|
+
SequenceExpression([
|
|
145
|
+
AssignmentExpression(
|
|
146
|
+
"=",
|
|
147
|
+
Identifier(this.counterMeasuresActivated),
|
|
148
|
+
Literal(true)
|
|
149
|
+
),
|
|
150
|
+
CallExpression(Template(opt).single().expression, []),
|
|
151
|
+
])
|
|
152
|
+
)
|
|
136
153
|
),
|
|
137
154
|
];
|
|
138
155
|
}
|
|
@@ -288,7 +305,7 @@ export default class Lock extends Transform {
|
|
|
288
305
|
nodes.push(
|
|
289
306
|
IfStatement(
|
|
290
307
|
callExpression,
|
|
291
|
-
this.getCounterMeasuresCode() || [],
|
|
308
|
+
this.getCounterMeasuresCode(object, parents) || [],
|
|
292
309
|
null
|
|
293
310
|
)
|
|
294
311
|
);
|
|
@@ -324,7 +341,11 @@ export default class Lock extends Transform {
|
|
|
324
341
|
}
|
|
325
342
|
|
|
326
343
|
nodes.push(
|
|
327
|
-
IfStatement(
|
|
344
|
+
IfStatement(
|
|
345
|
+
test,
|
|
346
|
+
this.getCounterMeasuresCode(object, parents) || [],
|
|
347
|
+
null
|
|
348
|
+
)
|
|
328
349
|
);
|
|
329
350
|
}
|
|
330
351
|
|
|
@@ -338,7 +359,11 @@ export default class Lock extends Transform {
|
|
|
338
359
|
);
|
|
339
360
|
|
|
340
361
|
nodes.push(
|
|
341
|
-
IfStatement(
|
|
362
|
+
IfStatement(
|
|
363
|
+
test,
|
|
364
|
+
this.getCounterMeasuresCode(object, parents) || [],
|
|
365
|
+
null
|
|
366
|
+
)
|
|
342
367
|
);
|
|
343
368
|
|
|
344
369
|
break;
|
|
@@ -351,7 +376,11 @@ export default class Lock extends Transform {
|
|
|
351
376
|
);
|
|
352
377
|
|
|
353
378
|
nodes.push(
|
|
354
|
-
IfStatement(
|
|
379
|
+
IfStatement(
|
|
380
|
+
test,
|
|
381
|
+
this.getCounterMeasuresCode(object, parents) || [],
|
|
382
|
+
null
|
|
383
|
+
)
|
|
355
384
|
);
|
|
356
385
|
|
|
357
386
|
break;
|
|
@@ -359,6 +388,8 @@ export default class Lock extends Transform {
|
|
|
359
388
|
case "context":
|
|
360
389
|
var prop = choice(this.options.lock.context);
|
|
361
390
|
|
|
391
|
+
var code = this.getCounterMeasuresCode(object, parents) || [];
|
|
392
|
+
|
|
362
393
|
// Todo: Alternative to `this`
|
|
363
394
|
if (!this.globalVar) {
|
|
364
395
|
offset = 1;
|
|
@@ -384,9 +415,7 @@ export default class Lock extends Transform {
|
|
|
384
415
|
"!",
|
|
385
416
|
MemberExpression(Identifier(this.globalVar), Literal(prop), true)
|
|
386
417
|
);
|
|
387
|
-
nodes.push(
|
|
388
|
-
IfStatement(test, this.getCounterMeasuresCode() || [], null)
|
|
389
|
-
);
|
|
418
|
+
nodes.push(IfStatement(test, code, null));
|
|
390
419
|
|
|
391
420
|
break;
|
|
392
421
|
|
|
@@ -397,6 +426,8 @@ export default class Lock extends Transform {
|
|
|
397
426
|
|
|
398
427
|
ok(this.options.lock.osLock);
|
|
399
428
|
|
|
429
|
+
var code = this.getCounterMeasuresCode(object, parents) || [];
|
|
430
|
+
|
|
400
431
|
this.options.lock.osLock.forEach((osName) => {
|
|
401
432
|
var agentMatcher = {
|
|
402
433
|
windows: "Win",
|
|
@@ -449,9 +480,7 @@ export default class Lock extends Transform {
|
|
|
449
480
|
});
|
|
450
481
|
|
|
451
482
|
test = UnaryExpression("!", { ...test });
|
|
452
|
-
nodes.push(
|
|
453
|
-
IfStatement(test, this.getCounterMeasuresCode() || [], null)
|
|
454
|
-
);
|
|
483
|
+
nodes.push(IfStatement(test, code, null));
|
|
455
484
|
break;
|
|
456
485
|
|
|
457
486
|
case "browserLock":
|
|
@@ -488,7 +517,11 @@ export default class Lock extends Transform {
|
|
|
488
517
|
|
|
489
518
|
test = UnaryExpression("!", { ...test });
|
|
490
519
|
nodes.push(
|
|
491
|
-
IfStatement(
|
|
520
|
+
IfStatement(
|
|
521
|
+
test,
|
|
522
|
+
this.getCounterMeasuresCode(object, parents) || [],
|
|
523
|
+
null
|
|
524
|
+
)
|
|
492
525
|
);
|
|
493
526
|
break;
|
|
494
527
|
|
|
@@ -540,7 +573,11 @@ export default class Lock extends Transform {
|
|
|
540
573
|
);
|
|
541
574
|
}
|
|
542
575
|
nodes.push(
|
|
543
|
-
IfStatement(
|
|
576
|
+
IfStatement(
|
|
577
|
+
test,
|
|
578
|
+
this.getCounterMeasuresCode(object, parents) || [],
|
|
579
|
+
null
|
|
580
|
+
)
|
|
544
581
|
);
|
|
545
582
|
}
|
|
546
583
|
|
|
@@ -3,24 +3,11 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import Transform from "../transform";
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
BlockStatement,
|
|
8
|
-
Identifier,
|
|
9
|
-
LabeledStatement,
|
|
10
|
-
Literal,
|
|
11
|
-
Location,
|
|
12
|
-
Node,
|
|
13
|
-
ReturnStatement,
|
|
14
|
-
} from "../../util/gen";
|
|
6
|
+
import { BlockStatement, Literal, ReturnStatement } from "../../util/gen";
|
|
15
7
|
import { ObfuscateOrder } from "../../order";
|
|
16
|
-
import {
|
|
17
|
-
import { ok } from "assert";
|
|
8
|
+
import { clone, getFunction } from "../../util/insert";
|
|
18
9
|
import { getIdentifierInfo } from "../../util/identifiers";
|
|
19
|
-
import { walk } from "../../traverse";
|
|
20
10
|
import Label from "../label";
|
|
21
|
-
import NameConflicts from "./nameConflicts";
|
|
22
|
-
import AntiDestructuring from "../es5/antiDestructuring";
|
|
23
|
-
import { OPERATOR_PRECEDENCE } from "../../precedence";
|
|
24
11
|
import { isLoop } from "../../util/compare";
|
|
25
12
|
|
|
26
13
|
/**
|
|
@@ -181,12 +168,6 @@ export default class Preparation extends Transform {
|
|
|
181
168
|
this.before.push(new Label(o));
|
|
182
169
|
this.before.push(new ExplicitIdentifiers(o));
|
|
183
170
|
this.before.push(new ExplicitDeclarations(o));
|
|
184
|
-
|
|
185
|
-
if (this.options.es5) {
|
|
186
|
-
this.before.push(new AntiDestructuring(o));
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// this.before.push(new NameConflicts(o));
|
|
190
171
|
}
|
|
191
172
|
|
|
192
173
|
match() {
|
package/src/transforms/rgf.ts
CHANGED
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
isVarContext,
|
|
31
31
|
isFunction,
|
|
32
32
|
prepend,
|
|
33
|
+
getDefiningContext,
|
|
33
34
|
} from "../util/insert";
|
|
34
35
|
import { getRandomString } from "../util/random";
|
|
35
36
|
import Transform from "./transform";
|
|
@@ -106,12 +107,44 @@ export default class RGF extends Transform {
|
|
|
106
107
|
return;
|
|
107
108
|
}
|
|
108
109
|
|
|
110
|
+
// Avoid applying to the countermeasures function
|
|
111
|
+
if (typeof this.options.lock?.countermeasures === "string") {
|
|
112
|
+
// function countermeasures(){...}
|
|
113
|
+
if (
|
|
114
|
+
object.type === "FunctionDeclaration" &&
|
|
115
|
+
object.id.type === "Identifier" &&
|
|
116
|
+
object.id.name === this.options.lock.countermeasures
|
|
117
|
+
) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// var countermeasures = function(){...}
|
|
122
|
+
if (
|
|
123
|
+
parents[0].type === "VariableDeclarator" &&
|
|
124
|
+
parents[0].init === object &&
|
|
125
|
+
parents[0].id.type === "Identifier" &&
|
|
126
|
+
parents[0].id.name === this.options.lock.countermeasures
|
|
127
|
+
) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
109
132
|
var defined = new Set<string>(),
|
|
110
133
|
referenced = new Set<string>();
|
|
111
134
|
|
|
112
135
|
var isBound = false;
|
|
113
136
|
|
|
114
|
-
|
|
137
|
+
/**
|
|
138
|
+
* The fnTraverses serves two important purposes
|
|
139
|
+
*
|
|
140
|
+
* - Identify all the variables referenced and defined here
|
|
141
|
+
* - Identify is the 'this' keyword is used anywhere
|
|
142
|
+
*
|
|
143
|
+
* @param o
|
|
144
|
+
* @param p
|
|
145
|
+
* @returns
|
|
146
|
+
*/
|
|
147
|
+
const fnTraverser = (o, p) => {
|
|
115
148
|
if (
|
|
116
149
|
o.type == "Identifier" &&
|
|
117
150
|
!reservedIdentifiers.has(o.name) &&
|
|
@@ -121,7 +154,7 @@ export default class RGF extends Transform {
|
|
|
121
154
|
if (!info.spec.isReferenced) {
|
|
122
155
|
return;
|
|
123
156
|
}
|
|
124
|
-
if (info.spec.isDefined) {
|
|
157
|
+
if (info.spec.isDefined && getDefiningContext(o, p) === object) {
|
|
125
158
|
defined.add(o.name);
|
|
126
159
|
} else {
|
|
127
160
|
referenced.add(o.name);
|
|
@@ -131,7 +164,10 @@ export default class RGF extends Transform {
|
|
|
131
164
|
if (o.type == "ThisExpression" || o.type == "Super") {
|
|
132
165
|
isBound = true;
|
|
133
166
|
}
|
|
134
|
-
}
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
walk(object.params, [object, ...parents], fnTraverser);
|
|
170
|
+
walk(object.body, [object, ...parents], fnTraverser);
|
|
135
171
|
|
|
136
172
|
if (!isBound) {
|
|
137
173
|
defined.forEach((identifier) => {
|
|
@@ -80,3 +80,21 @@ test("Variant #4: Should work when countermeasures is variable declaration", asy
|
|
|
80
80
|
}
|
|
81
81
|
);
|
|
82
82
|
});
|
|
83
|
+
|
|
84
|
+
// https://github.com/MichaelXF/js-confuser/issues/66
|
|
85
|
+
test("Variant #5: Should work with RGF enabled", async () => {
|
|
86
|
+
await JsConfuser.obfuscate(
|
|
87
|
+
`
|
|
88
|
+
function myCountermeasuresFunction(){
|
|
89
|
+
|
|
90
|
+
}
|
|
91
|
+
`,
|
|
92
|
+
{
|
|
93
|
+
target: "node",
|
|
94
|
+
lock: {
|
|
95
|
+
countermeasures: "myCountermeasuresFunction",
|
|
96
|
+
},
|
|
97
|
+
rgf: true,
|
|
98
|
+
}
|
|
99
|
+
);
|
|
100
|
+
});
|
|
@@ -251,6 +251,43 @@ input(console.log, result)
|
|
|
251
251
|
eval(output);
|
|
252
252
|
expect(TEST_VALUE).toStrictEqual("undefined");
|
|
253
253
|
});
|
|
254
|
+
|
|
255
|
+
it("should not apply to functions that reference their parent scope in the parameters", async () => {
|
|
256
|
+
var output = await JsConfuser.obfuscate(
|
|
257
|
+
`
|
|
258
|
+
var outsideVar = 0;
|
|
259
|
+
function myFunction(insideVar = outsideVar){
|
|
260
|
+
}
|
|
261
|
+
`,
|
|
262
|
+
{
|
|
263
|
+
target: "node",
|
|
264
|
+
rgf: true,
|
|
265
|
+
}
|
|
266
|
+
);
|
|
267
|
+
|
|
268
|
+
expect(output).not.toContain("new Function");
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it("should not apply to functions that reference their parent scope in previously defined names", async () => {
|
|
272
|
+
var output = await JsConfuser.obfuscate(
|
|
273
|
+
`
|
|
274
|
+
var outsideVar = 0;
|
|
275
|
+
function myFunction(){
|
|
276
|
+
(function (){
|
|
277
|
+
var outsideVar;
|
|
278
|
+
})();
|
|
279
|
+
|
|
280
|
+
console.log(outsideVar);
|
|
281
|
+
}
|
|
282
|
+
`,
|
|
283
|
+
{
|
|
284
|
+
target: "node",
|
|
285
|
+
rgf: true,
|
|
286
|
+
}
|
|
287
|
+
);
|
|
288
|
+
|
|
289
|
+
expect(output).not.toContain("new Function");
|
|
290
|
+
});
|
|
254
291
|
});
|
|
255
292
|
|
|
256
293
|
describe("RGF with the 'all' mode", () => {
|