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 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
- defined.add(object.name);
80
-
81
- if (object.name === this.options.lock.countermeasures) {
82
- if (this.counterMeasuresNode) {
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
- var chain = [object, parents];
89
+ if (definingContext != tree) {
90
+ throw new Error("Countermeasures function must be defined at the global level");
91
+ }
92
92
 
93
- if (info.isFunctionDeclaration) {
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
- this.counterMeasuresNode = chain;
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
- // Since Lock occurs before variable renaming, we are using the pre-obfuscated function name
124
- return [(0, _gen.ExpressionStatement)((0, _gen.CallExpression)((0, _template.default)(opt).single().expression, []))];
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); // Todo: Alternative to `this`
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, this.getCounterMeasuresCode() || [], null));
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, this.getCounterMeasuresCode() || [], null));
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() {
@@ -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
- (0, _traverse.walk)(object.body, [object, ...parents], (o, p) => {
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "js-confuser",
3
- "version": "1.5.6",
3
+ "version": "1.5.7",
4
4
  "description": "JavaScript Obfuscation Tool.",
5
5
  "main": "dist/index.js",
6
6
  "types": "index.d.ts",
@@ -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 (object.type == "Identifier") {
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
- defined.add(object.name);
82
- if (object.name === this.options.lock.countermeasures) {
83
- if (this.counterMeasuresNode) {
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 was already defined, it must have a unique name from the rest of your code"
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
- CallExpression(Template(opt).single().expression, [])
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(test, this.getCounterMeasuresCode() || [], null)
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(test, this.getCounterMeasuresCode() || [], null)
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(test, this.getCounterMeasuresCode() || [], null)
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(test, this.getCounterMeasuresCode() || [], null)
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(test, this.getCounterMeasuresCode() || [], null)
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 { getIndexDirect, clone, getFunction } from "../../util/insert";
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() {
@@ -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
- walk(object.body, [object, ...parents], (o, p) => {
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", () => {