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.
Files changed (128) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/README.md +12 -29
  3. package/dist/compiler.js +2 -8
  4. package/dist/constants.js +17 -10
  5. package/dist/index.js +7 -30
  6. package/dist/obfuscator.js +15 -62
  7. package/dist/options.js +21 -38
  8. package/dist/order.js +4 -7
  9. package/dist/parser.js +5 -13
  10. package/dist/precedence.js +6 -8
  11. package/dist/presets.js +4 -6
  12. package/dist/probability.js +13 -24
  13. package/dist/templates/bufferToString.js +100 -5
  14. package/dist/templates/crash.js +51 -9
  15. package/dist/templates/es5.js +125 -6
  16. package/dist/templates/functionLength.js +24 -6
  17. package/dist/templates/globals.js +9 -0
  18. package/dist/templates/template.js +71 -30
  19. package/dist/transforms/antiTooling.js +26 -22
  20. package/dist/transforms/calculator.js +18 -54
  21. package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +236 -333
  22. package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +46 -25
  23. package/dist/transforms/deadCode.js +528 -27
  24. package/dist/transforms/dispatcher.js +110 -108
  25. package/dist/transforms/es5/antiClass.js +70 -44
  26. package/dist/transforms/es5/antiDestructuring.js +14 -38
  27. package/dist/transforms/es5/antiES6Object.js +39 -48
  28. package/dist/transforms/es5/antiSpreadOperator.js +5 -14
  29. package/dist/transforms/es5/antiTemplate.js +10 -19
  30. package/dist/transforms/es5/es5.js +7 -40
  31. package/dist/transforms/extraction/classExtraction.js +83 -0
  32. package/dist/transforms/extraction/duplicateLiteralsRemoval.js +45 -79
  33. package/dist/transforms/extraction/objectExtraction.js +27 -54
  34. package/dist/transforms/finalizer.js +6 -20
  35. package/dist/transforms/flatten.js +51 -99
  36. package/dist/transforms/identifier/globalAnalysis.js +8 -26
  37. package/dist/transforms/identifier/globalConcealing.js +35 -54
  38. package/dist/transforms/identifier/movedDeclarations.js +66 -38
  39. package/dist/transforms/identifier/renameVariables.js +29 -68
  40. package/dist/transforms/identifier/variableAnalysis.js +21 -48
  41. package/dist/transforms/lock/antiDebug.js +20 -25
  42. package/dist/transforms/lock/integrity.js +48 -47
  43. package/dist/transforms/lock/lock.js +62 -113
  44. package/dist/transforms/minify.js +77 -108
  45. package/dist/transforms/opaquePredicates.js +11 -48
  46. package/dist/transforms/preparation.js +17 -50
  47. package/dist/transforms/renameLabels.js +5 -22
  48. package/dist/transforms/rgf.js +98 -66
  49. package/dist/transforms/shuffle.js +41 -46
  50. package/dist/transforms/stack.js +35 -98
  51. package/dist/transforms/string/encoding.js +73 -27
  52. package/dist/transforms/string/stringCompression.js +44 -68
  53. package/dist/transforms/string/stringConcealing.js +125 -134
  54. package/dist/transforms/string/stringEncoding.js +6 -26
  55. package/dist/transforms/string/stringSplitting.js +5 -30
  56. package/dist/transforms/transform.js +50 -100
  57. package/dist/traverse.js +11 -18
  58. package/dist/util/compare.js +27 -29
  59. package/dist/util/gen.js +32 -86
  60. package/dist/util/guard.js +0 -1
  61. package/dist/util/identifiers.js +11 -74
  62. package/dist/util/insert.js +27 -77
  63. package/dist/util/math.js +0 -3
  64. package/dist/util/object.js +3 -7
  65. package/dist/util/random.js +5 -36
  66. package/dist/util/scope.js +6 -3
  67. package/docs/ControlFlowFlattening.md +1 -1
  68. package/docs/ES5.md +197 -0
  69. package/package.json +3 -3
  70. package/src/constants.ts +12 -0
  71. package/src/options.ts +13 -0
  72. package/src/order.ts +2 -2
  73. package/src/templates/bufferToString.ts +49 -11
  74. package/src/templates/functionLength.ts +21 -3
  75. package/src/templates/globals.ts +3 -0
  76. package/src/templates/template.ts +85 -25
  77. package/src/transforms/antiTooling.ts +33 -11
  78. package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +2 -2
  79. package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +46 -10
  80. package/src/transforms/deadCode.ts +0 -16
  81. package/src/transforms/dispatcher.ts +101 -69
  82. package/src/transforms/es5/antiClass.ts +10 -1
  83. package/src/transforms/extraction/classExtraction.ts +168 -0
  84. package/src/transforms/extraction/duplicateLiteralsRemoval.ts +13 -10
  85. package/src/transforms/extraction/objectExtraction.ts +7 -14
  86. package/src/transforms/flatten.ts +20 -5
  87. package/src/transforms/identifier/globalConcealing.ts +29 -65
  88. package/src/transforms/identifier/movedDeclarations.ts +90 -24
  89. package/src/transforms/minify.ts +27 -12
  90. package/src/transforms/rgf.ts +103 -5
  91. package/src/transforms/stack.ts +12 -3
  92. package/src/transforms/string/encoding.ts +85 -51
  93. package/src/transforms/string/stringCompression.ts +5 -8
  94. package/src/transforms/string/stringConcealing.ts +139 -113
  95. package/src/transforms/string/stringEncoding.ts +1 -2
  96. package/src/transforms/string/stringSplitting.ts +1 -2
  97. package/src/transforms/transform.ts +30 -1
  98. package/src/util/compare.ts +39 -5
  99. package/src/util/gen.ts +10 -3
  100. package/src/util/identifiers.ts +6 -3
  101. package/src/util/insert.ts +17 -0
  102. package/src/util/scope.ts +14 -2
  103. package/test/code/Cash.test.ts +10 -4
  104. package/test/code/StrictMode.src.js +65 -0
  105. package/test/code/StrictMode.test.js +37 -0
  106. package/test/compare.test.ts +62 -2
  107. package/test/options.test.ts +111 -55
  108. package/test/transforms/controlFlowFlattening/expressionObfuscation.test.ts +37 -18
  109. package/test/transforms/dispatcher.test.ts +82 -0
  110. package/test/transforms/extraction/classExtraction.test.ts +86 -0
  111. package/test/transforms/extraction/duplicateLiteralsRemoval.test.ts +29 -8
  112. package/test/transforms/extraction/objectExtraction.test.ts +37 -15
  113. package/test/transforms/identifier/globalConcealing.test.ts +42 -2
  114. package/test/transforms/identifier/movedDeclarations.test.ts +61 -0
  115. package/test/transforms/lock/integrity.test.ts +24 -0
  116. package/test/transforms/minify.test.ts +37 -0
  117. package/test/transforms/rgf.test.ts +50 -0
  118. package/test/util/identifiers.test.ts +21 -0
  119. package/dist/transforms/controlFlowFlattening/choiceFlowObfuscation.js +0 -62
  120. package/dist/transforms/controlFlowFlattening/controlFlowObfuscation.js +0 -159
  121. package/dist/transforms/controlFlowFlattening/switchCaseObfuscation.js +0 -106
  122. package/dist/transforms/eval.js +0 -84
  123. package/dist/transforms/hexadecimalNumbers.js +0 -63
  124. package/dist/transforms/hideInitializingCode.js +0 -270
  125. package/dist/transforms/identifier/nameRecycling.js +0 -218
  126. package/dist/transforms/label.js +0 -67
  127. package/dist/transforms/preparation/nameConflicts.js +0 -116
  128. package/dist/transforms/preparation/preparation.js +0 -188
package/docs/ES5.md ADDED
@@ -0,0 +1,197 @@
1
+ ## `ES5`
2
+
3
+ The ES5 option converts most ES6+ features into ES5 compatible code.
4
+
5
+ Option name: `es5`
6
+
7
+ Option values: `true/false`
8
+
9
+ Note: Does not cover all cases such as Promises or Generator functions. Use [Babel](https://babel.dev/).
10
+
11
+ The ES5 option is intended to undo any ES6 feature the obfuscator adds to your code. If you input ES5 code, and enable the `es5` option, you can be guaranteed to have ES5 compatible output.
12
+
13
+ ## Example
14
+
15
+ ```js
16
+ // Input
17
+ function print(...messages){
18
+ console.log(...messages); // The spread operator (...)
19
+ // was introduced in ES6!
20
+ }
21
+
22
+ print("Hello", "World"); // "Hello World"
23
+
24
+ // Output
25
+ var __p_2580918143;
26
+ function print() {
27
+ var __p_7607361496;
28
+ var messages, __p_2591841272 = (__p_7607361496 = Array.prototype.slice.call(arguments), messages = __p_7607361496.slice(0));
29
+ (__p_2580918143 = console).log.apply(__p_2580918143, [].concat(Array.prototype.slice.call(messages)));
30
+ }
31
+ print('Hello', 'World'); // "Hello World"
32
+ ```
33
+
34
+ ## Polyfill Array Methods
35
+
36
+ When the ES5 option is enabled, array method polyfills will be injected to the top of your script.
37
+
38
+ ```js
39
+ if (!Array.prototype.forEach) {
40
+ Array.prototype.forEach = function forEach(callback, thisArg) {
41
+ if (typeof callback !== 'function') {
42
+ throw new TypeError(callback + ' is not a function');
43
+ }
44
+ var array = this;
45
+ thisArg = thisArg || this;
46
+ for (var i = 0, l = array.length; i !== l; ++i) {
47
+ callback.call(thisArg, array[i], i, array);
48
+ }
49
+ };
50
+ }
51
+ ```
52
+
53
+ ## Destructuring
54
+
55
+ The ES5 option supports transpiling the destructuring patterns.
56
+
57
+ ```js
58
+ // Input
59
+ var {userName, email} = { userName: "John", email: "email@exampe.com" };
60
+
61
+ // Output
62
+ var __p_7467473759;
63
+ var userName, email, __p_4755992742 = (__p_7467473759 = {
64
+ userName: 'John',
65
+ email: 'email@exampe.com'
66
+ }, userName = __p_7467473759.userName, email = __p_7467473759.email);
67
+ ```
68
+
69
+ ## Spread Operator
70
+
71
+ The ES5 option supports transpiling the spread operator.
72
+
73
+ ```js
74
+ // Input
75
+ array.push(...objects);
76
+
77
+ // Output
78
+ var __p_6344935930;
79
+ (__p_6344935930 = array).push.apply(__p_6344935930, [].concat(Array.prototype.slice.call(objects)));
80
+ ```
81
+
82
+ ## Template String
83
+
84
+ The ES5 option supports transpiling template strings.
85
+
86
+ ```js
87
+ // Input
88
+ var myString = `Hello ${userName}`;
89
+
90
+ // Output
91
+ var myString = 'Hello ' + (userName + '');
92
+ ```
93
+
94
+ ## Object getters/setters
95
+
96
+ The ES5 option supports transpiling getter and setter methods.
97
+
98
+ ```js
99
+ // Input
100
+ var _name;
101
+ var myObject = {
102
+ get name(){
103
+ return _name;
104
+ },
105
+ set name(newName){
106
+ _name = newName;
107
+ }
108
+ };
109
+
110
+ // Output
111
+ function __p_6886881506(base, computedProps, getters, setters) {
112
+ for (var i = 0; i < computedProps.length; i++) {
113
+ base[computedProps[i][0]] = computedProps[i][1];
114
+ }
115
+ var keys = Object.create(null);
116
+ Object.keys(getters).forEach(function (key) {
117
+ return keys[key] = 1;
118
+ });
119
+ Object.keys(setters).forEach(function (key) {
120
+ return keys[key] = 1;
121
+ });
122
+ Object.keys(keys).forEach(function (key) {
123
+ Object.defineProperty(base, key, {
124
+ set: setters[key],
125
+ get: getters[key],
126
+ configurable: true
127
+ });
128
+ });
129
+ return base;
130
+ }
131
+ var _name;
132
+ var myObject = __p_6886881506({}, [], {
133
+ 'name': function () {
134
+ return _name;
135
+ }
136
+ }, {
137
+ 'name': function (newName) {
138
+ _name = newName;
139
+ }
140
+ });
141
+ ```
142
+
143
+ ## Arrow Functions
144
+
145
+ The ES5 option converts arrow functions into regular functions.
146
+
147
+ ```js
148
+ // Input
149
+ var print = message => console.log(message);
150
+
151
+ // Output
152
+ var print = function (message) {
153
+ return console.log(message);
154
+ };
155
+ ```
156
+
157
+ ## Const/Let
158
+
159
+ The ES5 option converts `const` and `let` to a regular `var` keyword.
160
+
161
+ ```js
162
+ // Input
163
+ let myVar1 = true;
164
+ const myVar2 = "String";
165
+
166
+ // Output
167
+ var myVar1 = true;
168
+ var myVar2 = 'String';
169
+ ```
170
+
171
+ ## Classes
172
+
173
+ The ES5 option partially supports transpiling classes.
174
+
175
+ ## Reserved Identifiers
176
+
177
+ The ES5 option will change any illegal uses of reserved identifiers.
178
+
179
+ ```js
180
+ // Input
181
+ var myObject = {true: 1};
182
+ myObject.for = true;
183
+
184
+ // Output
185
+ var myObject = {"true": 1};
186
+ myObject["for"] = true;
187
+ ```
188
+
189
+ ## Features not supported
190
+
191
+ - Promises
192
+ - Async / Await
193
+ - Generator functions
194
+ - Nullish coalescing
195
+ - Optional chaining
196
+
197
+ Use [Babel](https://babel.dev/) to transpile these features. JS-Confuser will only support features the obfuscator may potentially add to your code.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "js-confuser",
3
- "version": "1.7.0",
3
+ "version": "1.7.2",
4
4
  "description": "JavaScript Obfuscation Tool.",
5
5
  "main": "dist/index.js",
6
6
  "types": "index.d.ts",
@@ -22,8 +22,8 @@
22
22
  "author": "MichaelXF",
23
23
  "license": "MIT",
24
24
  "dependencies": {
25
- "acorn": "^8.8.2",
26
- "escodegen": "^2.0.0"
25
+ "acorn": "^8.12.1",
26
+ "escodegen": "^2.1.0"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@babel/cli": "^7.17.6",
package/src/constants.ts CHANGED
@@ -82,3 +82,15 @@ export const reservedIdentifiers = new Set([
82
82
 
83
83
  export const noRenameVariablePrefix = "__NO_JS_CONFUSER_RENAME__";
84
84
  export const placeholderVariablePrefix = "__p_";
85
+
86
+ /**
87
+ * Tells the obfuscator this function is predictable:
88
+ * - Never called with extraneous parameters
89
+ */
90
+ export const predictableFunctionTag = "__JS_PREDICT__";
91
+
92
+ /**
93
+ * Tells the obfuscator this function is critical for the Obfuscated code.
94
+ * - Example: string decryption function
95
+ */
96
+ export const criticalFunctionTag = "__JS_CRITICAL__";
package/src/options.ts CHANGED
@@ -585,6 +585,15 @@ export interface ObfuscateOptions {
585
585
  * [See all settings here](https://github.com/MichaelXF/js-confuser/blob/master/README.md#options)
586
586
  */
587
587
  debugComments?: boolean;
588
+
589
+ /**
590
+ * ### `preserveFunctionLength`
591
+ *
592
+ * Modified functions will retain the correct `function.length` property. Enabled by default. (`true/false`)
593
+ *
594
+ * [See all settings here](https://github.com/MichaelXF/js-confuser/blob/master/README.md#options)
595
+ */
596
+ preserveFunctionLength?: boolean;
588
597
  }
589
598
 
590
599
  const validProperties = new Set([
@@ -619,6 +628,7 @@ const validProperties = new Set([
619
628
  "verbose",
620
629
  "globalVariables",
621
630
  "debugComments",
631
+ "preserveFunctionLength",
622
632
  ]);
623
633
 
624
634
  const validOses = new Set(["windows", "linux", "osx", "ios", "android"]);
@@ -764,6 +774,9 @@ export async function correctOptions(
764
774
  if (!options.hasOwnProperty("renameGlobals")) {
765
775
  options.renameGlobals = true; // RenameGlobals is on by default
766
776
  }
777
+ if (!options.hasOwnProperty("preserveFunctionLength")) {
778
+ options.preserveFunctionLength = true; // preserveFunctionLength is on by default
779
+ }
767
780
 
768
781
  if (options.globalVariables && !(options.globalVariables instanceof Set)) {
769
782
  options.globalVariables = new Set(Object.keys(options.globalVariables));
package/src/order.ts CHANGED
@@ -46,11 +46,11 @@ export enum ObfuscateOrder {
46
46
 
47
47
  Minify = 28,
48
48
 
49
+ AntiTooling = 29,
50
+
49
51
  RenameVariables = 30,
50
52
 
51
53
  ES5 = 31,
52
54
 
53
- AntiTooling = 34,
54
-
55
55
  Finalizer = 35,
56
56
  }
@@ -1,19 +1,59 @@
1
+ import {
2
+ placeholderVariablePrefix,
3
+ predictableFunctionTag,
4
+ } from "../constants";
1
5
  import Template from "./template";
2
6
 
3
- export const BufferToStringTemplate = Template(`
4
- function __getGlobal(){
7
+ export const GetGlobalTemplate = Template(`
8
+ function ${placeholderVariablePrefix}CFG__getGlobalThis${predictableFunctionTag}(){
9
+ return globalThis
10
+ }
11
+
12
+ function ${placeholderVariablePrefix}CFG__getGlobal${predictableFunctionTag}(){
13
+ return global
14
+ }
15
+
16
+ function ${placeholderVariablePrefix}CFG__getWindow${predictableFunctionTag}(){
17
+ return window
18
+ }
19
+
20
+ function ${placeholderVariablePrefix}CFG__getThisFunction${predictableFunctionTag}(){
21
+ return new Function("return this")()
22
+ }
23
+
24
+ function {getGlobalFnName}(array = [
25
+ ${placeholderVariablePrefix}CFG__getGlobalThis${predictableFunctionTag},
26
+ ${placeholderVariablePrefix}CFG__getGlobal${predictableFunctionTag},
27
+ ${placeholderVariablePrefix}CFG__getWindow${predictableFunctionTag},
28
+ ${placeholderVariablePrefix}CFG__getThisFunction${predictableFunctionTag}
29
+ ]){
30
+ var bestMatch
31
+ var itemsToSearch = []
5
32
  try {
6
- return global||window|| ( new Function("return this") )();
7
- } catch ( e ) {
33
+ bestMatch = Object
34
+ itemsToSearch["push"](("")["__proto__"]["constructor"]["name"])
35
+ } catch(e) {
36
+
37
+ }
38
+ A: for(var i = 0; i < array["length"]; i++) {
8
39
  try {
9
- return this;
10
- } catch ( e ) {
11
- return {};
12
- }
40
+ bestMatch = array[i]()
41
+ for(var j = 0; j < itemsToSearch["length"]; j++) {
42
+ if(typeof bestMatch[itemsToSearch[j]] === "undefined") continue A;
43
+ }
44
+ return bestMatch
45
+ } catch(e) {}
13
46
  }
47
+
48
+ return bestMatch || this;
14
49
  }
50
+ `);
15
51
 
16
- var __globalObject = __getGlobal() || {};
52
+ export const BufferToStringTemplate = Template(`
53
+
54
+ ${GetGlobalTemplate.source}
55
+
56
+ var __globalObject = {getGlobalFnName}() || {};
17
57
  var __TextDecoder = __globalObject["TextDecoder"];
18
58
  var __Uint8Array = __globalObject["Uint8Array"];
19
59
  var __Buffer = __globalObject["Buffer"];
@@ -63,6 +103,4 @@ export const BufferToStringTemplate = Template(`
63
103
  return utf8ArrayToStr(buffer);
64
104
  }
65
105
  }
66
-
67
-
68
106
  `);
@@ -3,12 +3,30 @@ import Template from "./template";
3
3
  /**
4
4
  * Helper function to set `function.length` property.
5
5
  */
6
- export const FunctionLengthTemplate = Template(`
6
+ export const FunctionLengthTemplate = Template(
7
+ `
7
8
  function {name}(functionObject, functionLength){
8
- Object["defineProperty"](functionObject, "length", {
9
+ {ObjectDefineProperty}(functionObject, "length", {
9
10
  "value": functionLength,
10
11
  "configurable": true
11
12
  });
12
13
  return functionObject;
13
14
  }
14
- `);
15
+ `,
16
+ `
17
+ function {name}(functionObject, functionLength){
18
+ return {ObjectDefineProperty}(functionObject, "length", {
19
+ "value": functionLength,
20
+ "configurable": true
21
+ });
22
+ }
23
+ `,
24
+ `
25
+ function {name}(functionObject, functionLength){
26
+ return {ObjectDefineProperty}["call"](null, functionObject, "length", {
27
+ "value": functionLength,
28
+ "configurable": true
29
+ });
30
+ }
31
+ `
32
+ );
@@ -0,0 +1,3 @@
1
+ import Template from "./template";
2
+
3
+ export const ObjectDefineProperty = Template(`Object["defineProperty"]`);
@@ -1,57 +1,103 @@
1
1
  import { Node } from "../util/gen";
2
2
  import { parseSnippet, parseSync } from "../parser";
3
+ import { ok } from "assert";
4
+ import { choice } from "../util/random";
5
+ import { placeholderVariablePrefix } from "../constants";
3
6
 
4
7
  export interface ITemplate {
5
- fill(variables?: { [name: string]: string | number }): string;
8
+ fill(variables?: { [name: string]: string | number }): {
9
+ output: string;
10
+ template: string;
11
+ };
6
12
 
7
13
  compile(variables?: { [name: string]: string | number }): Node[];
8
14
 
9
15
  single(variables?: { [name: string]: string | number }): Node;
10
16
 
17
+ variables(variables): ITemplate;
18
+
19
+ ignoreMissingVariables(): ITemplate;
20
+
21
+ templates: string[];
11
22
  source: string;
12
23
  }
13
24
 
14
- export default function Template(template: string): ITemplate {
15
- var neededVariables = 0;
16
- while (template.includes(`{$${neededVariables + 1}}`)) {
17
- neededVariables++;
25
+ export default function Template(...templates: string[]): ITemplate {
26
+ ok(templates.length);
27
+
28
+ var requiredVariables = new Set<string>();
29
+ var providedVariables = {};
30
+ var defaultVariables: { [key: string]: string } = Object.create(null);
31
+
32
+ // This may picked up "$mb[pP`x]" from String Encoding function
33
+ // ignoreMissingVariables() prevents this
34
+ var matches = templates[0].match(/{[$A-z0-9_]+}/g);
35
+ if (matches !== null) {
36
+ matches.forEach((variable) => {
37
+ var name = variable.slice(1, -1);
38
+
39
+ // $ variables are for default variables
40
+ if (name.startsWith("$")) {
41
+ defaultVariables[name] =
42
+ placeholderVariablePrefix +
43
+ "td_" +
44
+ Object.keys(defaultVariables).length;
45
+ } else {
46
+ requiredVariables.add(name);
47
+ }
48
+ });
18
49
  }
19
- var vars = Object.create(null);
20
- new Array(neededVariables + 1).fill(0).forEach((x, i) => {
21
- vars["\\$" + i] = "temp_" + i;
22
- });
23
-
24
- function fill(variables?: { [name: string]: string | number }): string {
25
- if (!variables) {
26
- variables = Object.create(null);
27
- }
28
50
 
29
- var cloned = template;
51
+ function fill(
52
+ variables: { [name: string]: string | number } = Object.create(null)
53
+ ) {
54
+ var userVariables = { ...providedVariables, ...variables };
55
+
56
+ // Validate all variables were passed in
57
+ for (var requiredVariable of requiredVariables) {
58
+ if (typeof userVariables[requiredVariable] === "undefined") {
59
+ throw new Error(
60
+ templates[0] +
61
+ " missing variable: " +
62
+ requiredVariable +
63
+ " from " +
64
+ JSON.stringify(userVariables)
65
+ );
66
+ }
67
+ }
30
68
 
31
- var keys = { ...variables, ...vars };
69
+ var template = choice(templates);
70
+ var output = template;
71
+ var allVariables = {
72
+ ...defaultVariables,
73
+ ...userVariables,
74
+ };
32
75
 
33
- Object.keys(keys).forEach((name) => {
34
- var bracketName = "{" + name + "}";
35
- var value = keys[name] + "";
76
+ Object.keys(allVariables).forEach((name) => {
77
+ var bracketName = "{" + name.replace("$", "\\$") + "}";
78
+ var value = allVariables[name] + "";
36
79
 
37
80
  var reg = new RegExp(bracketName, "g");
38
81
 
39
- cloned = cloned.replace(reg, value);
82
+ output = output.replace(reg, value);
40
83
  });
41
84
 
42
- return cloned;
85
+ return { output, template };
43
86
  }
44
87
 
45
88
  function compile(variables: { [name: string]: string | number }): Node[] {
46
- var code = fill(variables);
89
+ var { output, template } = fill(variables);
47
90
  try {
48
- var program = parseSnippet(code);
91
+ var program = parseSnippet(output);
49
92
 
50
93
  return program.body;
51
94
  } catch (e) {
52
95
  console.error(e);
53
96
  console.error(template);
54
- throw new Error("Template failed to parse");
97
+ console.error({ ...providedVariables, ...variables });
98
+ throw new Error(
99
+ "Template failed to parse: OUTPUT= " + output + " SOURCE= " + template
100
+ );
55
101
  }
56
102
  }
57
103
 
@@ -60,11 +106,25 @@ export default function Template(template: string): ITemplate {
60
106
  return nodes[0];
61
107
  }
62
108
 
109
+ function variables(newVariables) {
110
+ Object.assign(providedVariables, newVariables);
111
+ return obj;
112
+ }
113
+
114
+ function ignoreMissingVariables() {
115
+ defaultVariables = Object.create(null);
116
+ requiredVariables.clear();
117
+ return obj;
118
+ }
119
+
63
120
  var obj: ITemplate = {
64
121
  fill,
65
122
  compile,
66
123
  single,
67
- source: template,
124
+ templates,
125
+ variables,
126
+ ignoreMissingVariables,
127
+ source: templates[0],
68
128
  };
69
129
 
70
130
  return obj;
@@ -1,32 +1,51 @@
1
1
  import { ObfuscateOrder } from "../order";
2
+ import Template from "../templates/template";
2
3
  import { isBlock } from "../traverse";
3
4
  import {
5
+ Node,
4
6
  ExpressionStatement,
5
- SequenceExpression,
6
- UnaryExpression,
7
+ CallExpression,
8
+ Identifier,
7
9
  } from "../util/gen";
8
- import { choice } from "../util/random";
10
+ import { prepend } from "../util/insert";
9
11
  import Transform from "./transform";
10
12
 
11
13
  // JsNice.org tries to separate sequence expressions into multiple lines, this stops that.
12
14
  export default class AntiTooling extends Transform {
15
+ fnName: string;
16
+
13
17
  constructor(o) {
14
18
  super(o, ObfuscateOrder.AntiTooling);
15
19
  }
16
20
 
21
+ apply(tree: Node) {
22
+ super.apply(tree);
23
+
24
+ if (typeof this.fnName === "string") {
25
+ prepend(
26
+ tree,
27
+ Template(`
28
+ function {fnName}(){
29
+ }
30
+ `).single({ fnName: this.fnName })
31
+ );
32
+ }
33
+ }
34
+
17
35
  match(object, parents) {
18
36
  return isBlock(object) || object.type == "SwitchCase";
19
37
  }
20
38
 
21
39
  transform(object, parents) {
22
40
  return () => {
23
- var exprs = [];
24
- var deleteExprs = [];
41
+ var exprs: Node[] = [];
42
+ var deleteExprs: Node[] = [];
25
43
 
26
- var body = object.type == "SwitchCase" ? object.consequent : object.body;
44
+ var body: Node[] =
45
+ object.type == "SwitchCase" ? object.consequent : object.body;
27
46
 
28
47
  const end = () => {
29
- function flatten(expr) {
48
+ function flatten(expr: Node) {
30
49
  if (expr.type == "ExpressionStatement") {
31
50
  flatten(expr.expression);
32
51
  } else if (expr.type == "SequenceExpression") {
@@ -41,13 +60,16 @@ export default class AntiTooling extends Transform {
41
60
 
42
61
  if (flattened.length > 1) {
43
62
  flattened[0] = { ...flattened[0] };
63
+
64
+ if (!this.fnName) {
65
+ this.fnName = this.getPlaceholder();
66
+ }
67
+
68
+ // (expr1,expr2,expr3) -> F(expr1, expr2, expr3)
44
69
  this.replace(
45
70
  exprs[0],
46
71
  ExpressionStatement(
47
- UnaryExpression(
48
- choice(["typeof", "void", "!"]),
49
- SequenceExpression(flattened)
50
- )
72
+ CallExpression(Identifier(this.fnName), [...flattened])
51
73
  )
52
74
  );
53
75
 
@@ -47,9 +47,8 @@ import {
47
47
  import { chance, choice, getRandomInteger, shuffle } from "../../util/random";
48
48
  import Transform from "../transform";
49
49
  import ExpressionObfuscation from "./expressionObfuscation";
50
- import { isModuleSource } from "../string/stringConcealing";
51
50
  import { reservedIdentifiers } from "../../constants";
52
- import { isDirective } from "../../util/compare";
51
+ import { isDirective, isModuleSource } from "../../util/compare";
53
52
 
54
53
  const flattenStructures = new Set([
55
54
  "IfStatement",
@@ -1571,6 +1570,7 @@ export default class ControlFlowFlattening extends Transform {
1571
1570
  !this.isDebug &&
1572
1571
  o.type === "Identifier" &&
1573
1572
  this.mangleIdentifiers &&
1573
+ !reservedIdentifiers.has(o.name) &&
1574
1574
  chance(50 - this.mangledExpressionsMade / 100) &&
1575
1575
  !p.find((x) => isVarContext(x))
1576
1576
  ) {