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.
Files changed (59) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +215 -170
  3. package/dist/constants.js +6 -2
  4. package/dist/obfuscator.js +0 -6
  5. package/dist/options.js +4 -4
  6. package/dist/presets.js +6 -7
  7. package/dist/templates/crash.js +2 -2
  8. package/dist/templates/functionLength.js +16 -0
  9. package/dist/transforms/dispatcher.js +4 -1
  10. package/dist/transforms/extraction/duplicateLiteralsRemoval.js +89 -58
  11. package/dist/transforms/flatten.js +224 -147
  12. package/dist/transforms/identifier/movedDeclarations.js +38 -85
  13. package/dist/transforms/identifier/renameVariables.js +94 -41
  14. package/dist/transforms/lock/lock.js +0 -37
  15. package/dist/transforms/minify.js +2 -2
  16. package/dist/transforms/rgf.js +139 -246
  17. package/dist/transforms/stack.js +42 -1
  18. package/dist/transforms/transform.js +1 -1
  19. package/dist/util/gen.js +2 -1
  20. package/dist/util/identifiers.js +37 -3
  21. package/dist/util/insert.js +24 -3
  22. package/docs/ControlFlowFlattening.md +595 -0
  23. package/{Countermeasures.md → docs/Countermeasures.md} +1 -15
  24. package/{Integrity.md → docs/Integrity.md} +2 -2
  25. package/docs/RGF.md +419 -0
  26. package/package.json +1 -1
  27. package/src/constants.ts +3 -0
  28. package/src/obfuscator.ts +0 -4
  29. package/src/options.ts +9 -86
  30. package/src/presets.ts +6 -7
  31. package/src/templates/crash.ts +10 -10
  32. package/src/templates/functionLength.ts +14 -0
  33. package/src/transforms/dispatcher.ts +5 -1
  34. package/src/transforms/extraction/duplicateLiteralsRemoval.ts +130 -129
  35. package/src/transforms/flatten.ts +357 -290
  36. package/src/transforms/identifier/movedDeclarations.ts +50 -96
  37. package/src/transforms/identifier/renameVariables.ts +120 -56
  38. package/src/transforms/lock/lock.ts +1 -42
  39. package/src/transforms/minify.ts +11 -2
  40. package/src/transforms/rgf.ts +214 -404
  41. package/src/transforms/stack.ts +62 -0
  42. package/src/transforms/transform.ts +6 -2
  43. package/src/util/gen.ts +7 -2
  44. package/src/util/identifiers.ts +43 -2
  45. package/src/util/insert.ts +26 -2
  46. package/test/code/ES6.src.js +24 -0
  47. package/test/transforms/flatten.test.ts +352 -88
  48. package/test/transforms/identifier/movedDeclarations.test.ts +37 -9
  49. package/test/transforms/identifier/renameVariables.test.ts +37 -0
  50. package/test/transforms/lock/lock.test.ts +1 -48
  51. package/test/transforms/minify.test.ts +19 -0
  52. package/test/transforms/rgf.test.ts +262 -353
  53. package/test/transforms/stack.test.ts +52 -0
  54. package/test/util/identifiers.test.ts +113 -1
  55. package/test/util/insert.test.ts +57 -3
  56. package/src/transforms/eval.ts +0 -89
  57. package/src/transforms/identifier/nameRecycling.ts +0 -280
  58. package/test/transforms/eval.test.ts +0 -131
  59. package/test/transforms/identifier/nameRecycling.test.ts +0 -205
@@ -40,6 +40,7 @@ class RenameVariables extends _transform.default {
40
40
  // Names already used
41
41
  // Map of Context->Object of changes
42
42
  // Ref to VariableAnalysis data
43
+ // Option to re-use previously generated names
43
44
  constructor(o) {
44
45
  super(o, _order.ObfuscateOrder.RenameVariables);
45
46
 
@@ -49,6 +50,8 @@ class RenameVariables extends _transform.default {
49
50
 
50
51
  _defineProperty(this, "variableAnalysis", void 0);
51
52
 
53
+ _defineProperty(this, "reusePreviousNames", true);
54
+
52
55
  this.changed = new Map(); // 1.
53
56
 
54
57
  this.variableAnalysis = new _variableAnalysis.default(o);
@@ -57,10 +60,10 @@ class RenameVariables extends _transform.default {
57
60
  }
58
61
 
59
62
  match(object, parents) {
60
- return (0, _insert.isContext)(object);
63
+ return (0, _insert.isContext)(object) || object.type === "Identifier";
61
64
  }
62
65
 
63
- transform(object, parents) {
66
+ transformContext(object, parents) {
64
67
  // 2. Notice this is on 'onEnter' (top-down)
65
68
  var isGlobal = object.type == "Program";
66
69
  var type = isGlobal ? "root" : (0, _insert.isVarContext)(object) ? "var" : (0, _insert.isLexContext)(object) ? "lex" : undefined;
@@ -77,7 +80,7 @@ class RenameVariables extends _transform.default {
77
80
 
78
81
  var possible = new Set(); // 3. Try to re-use names when possible
79
82
 
80
- if (this.generated.length && !isGlobal) {
83
+ if (this.reusePreviousNames && this.generated.length && !isGlobal) {
81
84
  var allReferences = new Set();
82
85
  var nope = new Set(defined);
83
86
  (0, _traverse.walk)(object, [], (o, p) => {
@@ -115,8 +118,8 @@ class RenameVariables extends _transform.default {
115
118
 
116
119
 
117
120
  for (var name of defined) {
118
- if (!name.startsWith("__NO_JS_CONFUSER_RENAME__") && ( // Variables prefixed with '__NO_JS_CONFUSER_RENAME__' are never renamed
119
- isGlobal && !name.startsWith("__p_") // Variables prefixed with '__p_' are created by the obfuscator, always renamed
121
+ if (!name.startsWith(_constants.noRenameVariablePrefix) && ( // Variables prefixed with '__NO_JS_CONFUSER_RENAME__' are never renamed
122
+ isGlobal && !name.startsWith(_constants.placeholderVariablePrefix) // Variables prefixed with '__p_' are created by the obfuscator, always renamed
120
123
  ? (0, _probability.ComputeProbabilityMap)(this.options.renameGlobals, x => x, name) : true) && (0, _probability.ComputeProbabilityMap)( // Check the user's option for renaming variables
121
124
  this.options.renameVariables, x => x, name, isGlobal)) {
122
125
  // Create a new name from (1) or (2) methods
@@ -142,58 +145,108 @@ class RenameVariables extends _transform.default {
142
145
  // This variable name was deemed not to be renamed.
143
146
  newNames[name] = name;
144
147
  }
148
+ } // console.log(object.type, newNames);
149
+
150
+
151
+ this.changed.set(object, newNames);
152
+ }
153
+
154
+ transformIdentifier(object, parents) {
155
+ const identifierName = object.name;
156
+
157
+ if (_constants.reservedIdentifiers.has(identifierName) || this.options.globalVariables.has(identifierName)) {
158
+ return;
145
159
  }
146
160
 
147
- this.changed.set(object, newNames); // 5. Update Identifier node's 'name' property
161
+ if (object.$renamed) {
162
+ return;
163
+ }
148
164
 
149
- (0, _traverse.walk)(object, parents, (o, p) => {
150
- if (o.type == "Identifier") {
151
- if (_constants.reservedIdentifiers.has(o.name) || this.options.globalVariables.has(o.name)) {
152
- return;
153
- }
165
+ var info = (0, _identifiers.getIdentifierInfo)(object, parents);
154
166
 
155
- if (o.$renamed) {
156
- return;
157
- }
167
+ if (info.spec.isExported) {
168
+ return;
169
+ }
158
170
 
159
- var info = (0, _identifiers.getIdentifierInfo)(o, p);
171
+ if (!info.spec.isReferenced) {
172
+ return;
173
+ }
160
174
 
161
- if (info.spec.isExported) {
162
- return;
163
- }
175
+ var contexts = [object, ...parents].filter(x => (0, _insert.isContext)(x));
176
+ var newName = null; // Function default parameter check!
164
177
 
165
- if (!info.spec.isReferenced) {
166
- return;
167
- }
178
+ var functionIndices = [];
168
179
 
169
- var contexts = [o, ...p].filter(x => (0, _insert.isContext)(x));
170
- var newName = null;
180
+ for (var i in parents) {
181
+ if ((0, _insert.isFunction)(parents[i])) {
182
+ functionIndices.push(i);
183
+ }
184
+ }
171
185
 
172
- for (var check of contexts) {
173
- if (this.variableAnalysis.defined.has(check) && this.variableAnalysis.defined.get(check).has(o.name)) {
174
- if (this.changed.has(check) && this.changed.get(check)[o.name]) {
175
- newName = this.changed.get(check)[o.name];
176
- break;
177
- }
186
+ for (var functionIndex of functionIndices) {
187
+ if (parents[functionIndex].id === object) {
188
+ // This context is not referenced, so remove it
189
+ contexts = contexts.filter(context => context != parents[functionIndex]);
190
+ continue;
191
+ }
192
+
193
+ if (parents[functionIndex].params === parents[functionIndex - 1]) {
194
+ var isReferencedHere = true;
195
+ var slicedParents = parents.slice(0, functionIndex);
196
+ var forIndex = 0;
197
+
198
+ for (var parent of slicedParents) {
199
+ var childNode = slicedParents[forIndex - 1] || object;
200
+
201
+ if (parent.type === "AssignmentPattern" && parent.right === childNode) {
202
+ isReferencedHere = false;
203
+ break;
178
204
  }
205
+
206
+ forIndex++;
179
207
  }
180
208
 
181
- if (newName && typeof newName === "string") {
182
- // Strange behavior where the `local` and `imported` objects are the same
183
- if (info.isImportSpecifier) {
184
- var importSpecifierIndex = p.findIndex(x => x.type === "ImportSpecifier");
209
+ if (!isReferencedHere) {
210
+ // This context is not referenced, so remove it
211
+ contexts = contexts.filter(context => context != parents[functionIndex]);
212
+ }
213
+ }
214
+ }
185
215
 
186
- if (importSpecifierIndex != -1 && p[importSpecifierIndex].imported === (p[importSpecifierIndex - 1] || o) && p[importSpecifierIndex].imported && p[importSpecifierIndex].imported.type === "Identifier") {
187
- p[importSpecifierIndex].imported = (0, _insert.clone)(p[importSpecifierIndex - 1] || o);
188
- }
189
- } // console.log(o.name, "->", newName);
216
+ for (var check of contexts) {
217
+ if (this.variableAnalysis.defined.has(check) && this.variableAnalysis.defined.get(check).has(identifierName)) {
218
+ if (this.changed.has(check) && this.changed.get(check)[identifierName]) {
219
+ newName = this.changed.get(check)[identifierName];
220
+ break;
221
+ }
222
+ }
223
+ }
190
224
 
225
+ if (newName && typeof newName === "string") {
226
+ // Strange behavior where the `local` and `imported` objects are the same
227
+ if (info.isImportSpecifier) {
228
+ var importSpecifierIndex = parents.findIndex(x => x.type === "ImportSpecifier");
191
229
 
192
- o.name = newName;
193
- o.$renamed = true;
230
+ if (importSpecifierIndex != -1 && parents[importSpecifierIndex].imported === (parents[importSpecifierIndex - 1] || object) && parents[importSpecifierIndex].imported && parents[importSpecifierIndex].imported.type === "Identifier") {
231
+ parents[importSpecifierIndex].imported = (0, _insert.clone)(parents[importSpecifierIndex - 1] || object);
194
232
  }
195
- }
196
- });
233
+ } // console.log(o.name, "->", newName);
234
+ // 5. Update Identifier node's 'name' property
235
+
236
+
237
+ object.name = newName;
238
+ object.$renamed = true;
239
+ }
240
+ }
241
+
242
+ transform(object, parents) {
243
+ var matchType = object.type === "Identifier" ? "Identifier" : "Context";
244
+
245
+ if (matchType === "Identifier") {
246
+ this.transformIdentifier(object, parents);
247
+ } else {
248
+ this.transformContext(object, parents);
249
+ }
197
250
  }
198
251
 
199
252
  }
@@ -194,10 +194,6 @@ class Lock extends _transform.default {
194
194
  choices.push("domainLock");
195
195
  }
196
196
 
197
- if (this.options.lock.nativeFunctions) {
198
- choices.push("nativeFunction");
199
- }
200
-
201
197
  if (this.options.lock.context && this.options.lock.context.length) {
202
198
  choices.push("context");
203
199
  }
@@ -248,39 +244,6 @@ class Lock extends _transform.default {
248
244
  nodes.push((0, _gen.IfStatement)(callExpression, this.getCounterMeasuresCode(object, parents) || [], null));
249
245
  break;
250
246
 
251
- case "nativeFunction":
252
- var set = this.options.lock.nativeFunctions;
253
-
254
- if (set === true) {
255
- if (this.options.target == "node") {
256
- set = new Set(["Function", "String"]);
257
- } else {
258
- set = new Set(["Function", "String", "fetch"]);
259
- }
260
- }
261
-
262
- if (Array.isArray(set)) {
263
- set = new Set(set);
264
- }
265
-
266
- if (!set) {
267
- set = new Set();
268
- }
269
-
270
- var fn = (0, _random.choice)(Array.from(set));
271
-
272
- if (fn) {
273
- test = (0, _template.default)("(".concat(fn, "+\"\").indexOf(\"[native code]\") == -1")).single().expression;
274
-
275
- if (Math.random() > 0.5) {
276
- test = (0, _template.default)("".concat(fn, ".toString().split(\"{ [native code] }\").length <= 1")).single().expression;
277
- }
278
-
279
- nodes.push((0, _gen.IfStatement)(test, this.getCounterMeasuresCode(object, parents) || [], null));
280
- }
281
-
282
- break;
283
-
284
247
  case "startDate":
285
248
  test = (0, _gen.BinaryExpression)("<", dateNow, (0, _gen.Literal)(this.getTime(this.options.lock.startDate)));
286
249
  nodes.push((0, _gen.IfStatement)(test, this.getCounterMeasuresCode(object, parents) || [], null));
@@ -214,11 +214,11 @@ class Minify extends _transform.default {
214
214
  if (canTransform) {
215
215
  if (!this.arrowFunctionName) {
216
216
  this.arrowFunctionName = this.getPlaceholder();
217
- (0, _insert.append)(parents[parents.length - 1] || object, (0, _template.default)("\n function ".concat(this.arrowFunctionName, "(arrowFn){\n return function(){ return arrowFn(...arguments) }\n }\n ")).single());
217
+ (0, _insert.append)(parents[parents.length - 1] || object, (0, _template.default)("\n function ".concat(this.arrowFunctionName, "(arrowFn, functionLength){\n var functionObject = function(){ return arrowFn(...arguments) };\n\n Object[\"defineProperty\"](functionObject, \"length\", {\n \"value\": functionLength,\n \"configurable\": true\n });\n\n return functionObject;\n }\n ")).single());
218
218
  }
219
219
 
220
220
  const wrap = object => {
221
- return (0, _gen.CallExpression)((0, _gen.Identifier)(this.arrowFunctionName), [(0, _insert.clone)(object)]);
221
+ return (0, _gen.CallExpression)((0, _gen.Identifier)(this.arrowFunctionName), [(0, _insert.clone)(object), (0, _gen.Literal)((0, _insert.computeFunctionLength)(object.params))]);
222
222
  };
223
223
 
224
224
  if (object.type == "FunctionExpression") {