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
@@ -6,6 +6,7 @@ import { walk } from "../traverse";
6
6
  import {
7
7
  AssignmentExpression,
8
8
  BinaryExpression,
9
+ CallExpression,
9
10
  ExpressionStatement,
10
11
  Identifier,
11
12
  IfStatement,
@@ -18,6 +19,7 @@ import {
18
19
  } from "../util/gen";
19
20
  import { getIdentifierInfo } from "../util/identifiers";
20
21
  import {
22
+ computeFunctionLength,
21
23
  getBlockBody,
22
24
  getDefiningContext,
23
25
  getReferencingContexts,
@@ -28,10 +30,14 @@ import {
28
30
  } from "../util/insert";
29
31
  import { chance, choice, getRandomInteger } from "../util/random";
30
32
  import Transform from "./transform";
33
+ import { noRenameVariablePrefix } from "../constants";
34
+ import { FunctionLengthTemplate } from "../templates/functionLength";
31
35
 
32
36
  export default class Stack extends Transform {
33
37
  mangledExpressionsMade: number;
34
38
 
39
+ functionLengthName: string;
40
+
35
41
  constructor(o) {
36
42
  super(o, ObfuscateOrder.Stack);
37
43
 
@@ -111,8 +117,14 @@ export default class Stack extends Transform {
111
117
  });
112
118
 
113
119
  var startingSize = subscripts.size;
120
+ var isIllegal = false;
114
121
 
115
122
  walk(object.body, [object, ...parents], (o, p) => {
123
+ if (o.type === "Identifier" && o.name === "arguments") {
124
+ isIllegal = true;
125
+ return "EXIT";
126
+ }
127
+
116
128
  if (o.type == "Identifier") {
117
129
  var info = getIdentifierInfo(o, p);
118
130
  if (!info.spec.isReferenced || info.spec.isExported) {
@@ -128,6 +140,10 @@ export default class Stack extends Transform {
128
140
  illegal.add(o.name);
129
141
  }
130
142
 
143
+ if (o.name.startsWith(noRenameVariablePrefix)) {
144
+ illegal.add(o.name);
145
+ }
146
+
131
147
  if (
132
148
  info.isClauseParameter ||
133
149
  info.isFunctionParameter ||
@@ -200,6 +216,8 @@ export default class Stack extends Transform {
200
216
  }
201
217
  });
202
218
 
219
+ if (isIllegal) return;
220
+
203
221
  illegal.forEach((name) => {
204
222
  defined.delete(name);
205
223
  referenced.delete(name);
@@ -467,6 +485,9 @@ export default class Stack extends Transform {
467
485
  object.body.body.splice(parseInt(index) + i, 0, rotateNodes[index]);
468
486
  });
469
487
 
488
+ // Preserve function.length property
489
+ var originalFunctionLength = computeFunctionLength(object.params);
490
+
470
491
  // Set the params for this function to be the stack array
471
492
  object.params = [RestElement(Identifier(stackName))];
472
493
 
@@ -475,6 +496,47 @@ export default class Stack extends Transform {
475
496
  object.body,
476
497
  Template(`${stackName}["length"] = ${startingSize}`).single()
477
498
  );
499
+
500
+ if (originalFunctionLength !== 0) {
501
+ if (!this.functionLengthName) {
502
+ this.functionLengthName = this.getPlaceholder();
503
+ prepend(
504
+ parents[parents.length - 1] || object,
505
+ FunctionLengthTemplate.single({ name: this.functionLengthName })
506
+ );
507
+ }
508
+
509
+ if (object.type === "FunctionDeclaration") {
510
+ var body = parents[0];
511
+ if (Array.isArray(body)) {
512
+ var index = body.indexOf(object);
513
+
514
+ body.splice(
515
+ index,
516
+ 0,
517
+ ExpressionStatement(
518
+ CallExpression(Identifier(this.functionLengthName), [
519
+ Identifier(object.id.name),
520
+ Literal(originalFunctionLength),
521
+ ])
522
+ )
523
+ );
524
+ }
525
+ } else {
526
+ ok(
527
+ object.type === "FunctionExpression" ||
528
+ object.type === "ArrowFunctionExpression"
529
+ );
530
+
531
+ this.replace(
532
+ object,
533
+ CallExpression(Identifier(this.functionLengthName), [
534
+ { ...object },
535
+ Literal(originalFunctionLength),
536
+ ])
537
+ );
538
+ }
539
+ }
478
540
  };
479
541
  }
480
542
  }
@@ -9,7 +9,11 @@ import { ok } from "assert";
9
9
  import Obfuscator from "../obfuscator";
10
10
  import { ObfuscateOptions } from "../options";
11
11
  import { ComputeProbabilityMap } from "../probability";
12
- import { reservedIdentifiers, reservedKeywords } from "../constants";
12
+ import {
13
+ placeholderVariablePrefix,
14
+ reservedIdentifiers,
15
+ reservedKeywords,
16
+ } from "../constants";
13
17
  import { ObfuscateOrder } from "../order";
14
18
 
15
19
  /**
@@ -176,7 +180,7 @@ export default class Transform {
176
180
  [...Array(size)]
177
181
  .map(() => Math.floor(Math.random() * 10).toString(10))
178
182
  .join("");
179
- return "__p_" + genRanHex(10);
183
+ return placeholderVariablePrefix + genRanHex(10);
180
184
  }
181
185
 
182
186
  /**
package/src/util/gen.ts CHANGED
@@ -171,7 +171,12 @@ export function BreakStatement(label?: string) {
171
171
  };
172
172
  }
173
173
 
174
- export function Property(key: Node, value: Node, computed = false) {
174
+ export function Property(
175
+ key: Node,
176
+ value: Node,
177
+ computed = false,
178
+ kind: "init" | "set" | "get" = "init"
179
+ ) {
175
180
  if (!key) {
176
181
  throw new Error("key is undefined");
177
182
  }
@@ -183,7 +188,7 @@ export function Property(key: Node, value: Node, computed = false) {
183
188
  key: key,
184
189
  computed: computed,
185
190
  value: value,
186
- kind: "init",
191
+ kind: kind,
187
192
  method: false,
188
193
  shorthand: false,
189
194
  };
@@ -30,6 +30,23 @@ export function validateChain(object: Node, parents: Node[]) {
30
30
  }
31
31
  }
32
32
 
33
+ function objectPatternCheck(object: Node, parents: Node[]) {
34
+ var objectPatternIndex = parents.findIndex((x) => x.type === "ObjectPattern");
35
+ if (objectPatternIndex == -1) {
36
+ return true;
37
+ }
38
+
39
+ var property = parents[objectPatternIndex].properties.find(
40
+ (property) => parents[objectPatternIndex - 2] === property
41
+ );
42
+
43
+ if (property.key === (parents[objectPatternIndex - 3] || object)) {
44
+ return false;
45
+ }
46
+
47
+ return true;
48
+ }
49
+
33
50
  /**
34
51
  * Returns detailed information about the given Identifier node.
35
52
  * @param object
@@ -74,7 +91,22 @@ export function getIdentifierInfo(object: Node, parents: Node[]) {
74
91
  var isVariableDeclaration =
75
92
  varIndex != -1 &&
76
93
  parents[varIndex].id == (parents[varIndex - 1] || object) &&
77
- parents.find((x) => x.type == "VariableDeclaration");
94
+ parents.find((x) => x.type == "VariableDeclaration") &&
95
+ objectPatternCheck(object, parents);
96
+
97
+ // Assignment pattern check!
98
+ if (isVariableDeclaration) {
99
+ var slicedParents = parents.slice(0, varIndex - 1);
100
+ var i = 0;
101
+ for (var parent of slicedParents) {
102
+ var childNode = slicedParents[i - 1] || object;
103
+ if (parent.type === "AssignmentPattern" && parent.right === childNode) {
104
+ isVariableDeclaration = false;
105
+ break;
106
+ }
107
+ i++;
108
+ }
109
+ }
78
110
 
79
111
  var forIndex = parents.findIndex((x) => x.type == "ForStatement");
80
112
  var isForInitializer =
@@ -87,6 +119,12 @@ export function getIdentifierInfo(object: Node, parents: Node[]) {
87
119
  functionIndex != -1 &&
88
120
  parents[functionIndex].type == "FunctionDeclaration" &&
89
121
  parents[functionIndex].id == object;
122
+
123
+ var isNamedFunctionExpression =
124
+ functionIndex != -1 &&
125
+ parents[functionIndex].type === "FunctionExpression" &&
126
+ parents[functionIndex].id === object;
127
+
90
128
  var isAFunctionParameter = isFunctionParameter(object, parents);
91
129
 
92
130
  var isClauseParameter = false;
@@ -112,7 +150,9 @@ export function getIdentifierInfo(object: Node, parents: Node[]) {
112
150
 
113
151
  var isAssignmentLeft =
114
152
  assignmentIndex !== -1 &&
115
- parents[assignmentIndex].left === (parents[assignmentIndex - 1] || object);
153
+ parents[assignmentIndex].left ===
154
+ (parents[assignmentIndex - 1] || object) &&
155
+ objectPatternCheck(object, parents);
116
156
  var isAssignmentValue =
117
157
  assignmentIndex !== -1 &&
118
158
  parents[assignmentIndex].right === (parents[assignmentIndex - 1] || object);
@@ -272,6 +312,7 @@ export function getIdentifierInfo(object: Node, parents: Node[]) {
272
312
  isDefined:
273
313
  isVariableDeclaration ||
274
314
  isFunctionDeclaration ||
315
+ isNamedFunctionExpression ||
275
316
  isAFunctionParameter ||
276
317
  isClassDeclaration ||
277
318
  isClauseParameter ||
@@ -145,13 +145,13 @@ export function getAllDefiningContexts(o: Node, p: Node[]): Node[] {
145
145
  // Get Function
146
146
  var fn = getFunction(o, p);
147
147
 
148
- contexts.push(fn.body);
148
+ // contexts.push(fn.body);
149
149
  }
150
150
 
151
151
  if (info.isClauseParameter) {
152
152
  var catchClause = p.find((x) => x.type === "CatchClause");
153
153
  if (catchClause) {
154
- contexts.push(catchClause.body);
154
+ return [catchClause];
155
155
  }
156
156
  }
157
157
 
@@ -376,3 +376,27 @@ export function isForInitialize(
376
376
 
377
377
  return false;
378
378
  }
379
+
380
+ /**
381
+ * Computes the `function.length` property given the parameter nodes.
382
+ *
383
+ * @param params
384
+ * @returns
385
+ */
386
+ export function computeFunctionLength(params: Node[]): number {
387
+ var count = 0;
388
+
389
+ for (var parameterNode of params) {
390
+ if (
391
+ parameterNode.type === "Identifier" ||
392
+ parameterNode.type === "ObjectPattern" ||
393
+ parameterNode.type === "ArrayPattern"
394
+ ) {
395
+ count++;
396
+ } else {
397
+ break;
398
+ }
399
+ }
400
+
401
+ return count;
402
+ }
@@ -203,6 +203,30 @@ function labeledBreaksAndContinues() {
203
203
  var variant15 = labeledBreaksAndContinues();
204
204
  expect(variant15).toStrictEqual(15);
205
205
 
206
+ // Variant #16: Function.length property
207
+ var variant16 = function (
208
+ n1,
209
+ n2,
210
+ n3,
211
+ n4,
212
+ n5,
213
+ n6,
214
+ n7,
215
+ n8,
216
+ n9,
217
+ n10,
218
+ n11,
219
+ n12,
220
+ n13,
221
+ n14,
222
+ n15,
223
+ n16
224
+ ) {
225
+ var _ = true;
226
+ };
227
+
228
+ expect(variant16.length).toStrictEqual(16);
229
+
206
230
  // Set 'ranAllTest' to TRUE
207
231
  ranAllTest = true;
208
232