js-confuser 2.0.0-alpha.2 → 2.0.0-alpha.4

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 (91) hide show
  1. package/.prettierrc +4 -0
  2. package/CHANGELOG.md +42 -8
  3. package/Migration.md +23 -8
  4. package/README.md +2 -2
  5. package/dist/constants.js +11 -2
  6. package/dist/index.js +49 -6
  7. package/dist/obfuscator.js +121 -10
  8. package/dist/order.js +0 -1
  9. package/dist/probability.js +1 -96
  10. package/dist/templates/getGlobalTemplate.js +4 -1
  11. package/dist/templates/integrityTemplate.js +1 -1
  12. package/dist/templates/stringCompressionTemplate.js +3 -3
  13. package/dist/templates/tamperProtectionTemplates.js +1 -1
  14. package/dist/templates/template.js +17 -12
  15. package/dist/transforms/controlFlowFlattening.js +112 -83
  16. package/dist/transforms/deadCode.js +21 -22
  17. package/dist/transforms/dispatcher.js +62 -37
  18. package/dist/transforms/extraction/duplicateLiteralsRemoval.js +5 -0
  19. package/dist/transforms/extraction/objectExtraction.js +1 -2
  20. package/dist/transforms/finalizer.js +1 -1
  21. package/dist/transforms/flatten.js +2 -19
  22. package/dist/transforms/identifier/globalConcealing.js +3 -4
  23. package/dist/transforms/identifier/movedDeclarations.js +12 -5
  24. package/dist/transforms/identifier/renameVariables.js +40 -6
  25. package/dist/transforms/lock/integrity.js +9 -1
  26. package/dist/transforms/lock/lock.js +16 -9
  27. package/dist/transforms/minify.js +64 -27
  28. package/dist/transforms/opaquePredicates.js +6 -7
  29. package/dist/transforms/pack.js +32 -5
  30. package/dist/transforms/plugin.js +20 -39
  31. package/dist/transforms/preparation.js +25 -36
  32. package/dist/transforms/renameLabels.js +1 -2
  33. package/dist/transforms/rgf.js +36 -16
  34. package/dist/transforms/shuffle.js +10 -11
  35. package/dist/transforms/string/stringCompression.js +14 -10
  36. package/dist/transforms/string/stringConcealing.js +7 -5
  37. package/dist/transforms/string/stringEncoding.js +4 -2
  38. package/dist/transforms/string/stringSplitting.js +4 -2
  39. package/dist/transforms/variableMasking.js +3 -2
  40. package/dist/utils/NameGen.js +5 -2
  41. package/dist/utils/PredicateGen.js +62 -0
  42. package/dist/utils/ast-utils.js +24 -9
  43. package/dist/utils/random-utils.js +10 -0
  44. package/dist/validateOptions.js +2 -2
  45. package/index.d.ts +16 -2
  46. package/package.json +2 -2
  47. package/src/constants.ts +15 -5
  48. package/src/index.ts +15 -5
  49. package/src/obfuscationResult.ts +7 -1
  50. package/src/obfuscator.ts +152 -12
  51. package/src/options.ts +26 -8
  52. package/src/order.ts +0 -2
  53. package/src/templates/getGlobalTemplate.ts +5 -1
  54. package/src/templates/integrityTemplate.ts +14 -19
  55. package/src/templates/stringCompressionTemplate.ts +4 -28
  56. package/src/templates/tamperProtectionTemplates.ts +7 -3
  57. package/src/templates/template.ts +5 -3
  58. package/src/transforms/controlFlowFlattening.ts +139 -83
  59. package/src/transforms/deadCode.ts +27 -30
  60. package/src/transforms/dispatcher.ts +24 -5
  61. package/src/transforms/extraction/duplicateLiteralsRemoval.ts +10 -1
  62. package/src/transforms/extraction/objectExtraction.ts +1 -2
  63. package/src/transforms/finalizer.ts +1 -1
  64. package/src/transforms/flatten.ts +3 -22
  65. package/src/transforms/identifier/globalConcealing.ts +26 -17
  66. package/src/transforms/identifier/movedDeclarations.ts +18 -6
  67. package/src/transforms/identifier/renameVariables.ts +48 -6
  68. package/src/transforms/lock/integrity.ts +11 -1
  69. package/src/transforms/lock/lock.ts +26 -10
  70. package/src/transforms/minify.ts +85 -38
  71. package/src/transforms/opaquePredicates.ts +6 -9
  72. package/src/transforms/pack.ts +41 -5
  73. package/src/transforms/plugin.ts +47 -69
  74. package/src/transforms/preparation.ts +33 -46
  75. package/src/transforms/renameLabels.ts +1 -2
  76. package/src/transforms/rgf.ts +52 -23
  77. package/src/transforms/shuffle.ts +28 -26
  78. package/src/transforms/string/encoding.ts +1 -1
  79. package/src/transforms/string/stringCompression.ts +22 -13
  80. package/src/transforms/string/stringConcealing.ts +13 -7
  81. package/src/transforms/string/stringEncoding.ts +6 -2
  82. package/src/transforms/string/stringSplitting.ts +9 -4
  83. package/src/transforms/variableMasking.ts +2 -2
  84. package/src/utils/NameGen.ts +13 -3
  85. package/src/utils/PredicateGen.ts +61 -0
  86. package/src/utils/ast-utils.ts +16 -9
  87. package/src/utils/random-utils.ts +14 -0
  88. package/src/validateOptions.ts +7 -4
  89. package/src/probability.ts +0 -110
  90. package/src/transforms/functionOutlining.ts +0 -225
  91. package/src/utils/ControlObject.ts +0 -141
@@ -1,13 +1,11 @@
1
1
  import { NodePath, Visitor } from "@babel/traverse";
2
2
  import Obfuscator from "../obfuscator";
3
- import { chance, choice, getRandomString } from "../utils/random-utils";
3
+ import { getRandomString } from "../utils/random-utils";
4
4
  import { Order } from "../order";
5
5
  import * as t from "@babel/types";
6
- import { FN_LENGTH, NodeSymbol, SKIP, CONTROL_OBJECTS } from "../constants";
6
+ import { FN_LENGTH, NodeSymbol, SKIP } from "../constants";
7
7
  import { SetFunctionLengthTemplate } from "../templates/setFunctionLengthTemplate";
8
8
  import { prepend, prependProgram } from "../utils/ast-utils";
9
- import ControlObject from "../utils/ControlObject";
10
- import { ok } from "assert";
11
9
  import { numericLiteral } from "../utils/node";
12
10
 
13
11
  export interface PluginObject {
@@ -30,9 +28,14 @@ export class PluginInstance {
30
28
  constructor(
31
29
  public pluginOptions: { name?: string; order?: number },
32
30
  public obfuscator: Obfuscator
33
- ) {}
31
+ ) {
32
+ this.computeProbabilityMap = obfuscator.computeProbabilityMap.bind(
33
+ this.obfuscator
34
+ );
35
+ }
34
36
 
35
37
  public changeData: { [key: string]: number } = {};
38
+ public computeProbabilityMap: Obfuscator["computeProbabilityMap"];
36
39
 
37
40
  get name() {
38
41
  return this.pluginOptions.name || "unnamed";
@@ -74,43 +77,48 @@ export class PluginInstance {
74
77
  setFunctionLength(path: NodePath<t.Function>, originalLength: number) {
75
78
  (path.node as NodeSymbol)[FN_LENGTH] = originalLength;
76
79
 
77
- // Function length
78
- if (this.options.preserveFunctionLength && originalLength > 0) {
79
- if (!this.setFunctionLengthName) {
80
- this.setFunctionLengthName = this.getPlaceholder("fnLength");
81
-
82
- this.skip(
83
- prependProgram(
84
- path,
85
- SetFunctionLengthTemplate.compile({
86
- fnName: this.setFunctionLengthName,
87
- })
88
- )
89
- );
90
- }
91
- if (t.isFunctionDeclaration(path.node)) {
92
- prepend(
93
- path.parentPath,
94
- t.expressionStatement(
95
- t.callExpression(t.identifier(this.setFunctionLengthName), [
96
- t.identifier(path.node.id.name),
97
- numericLiteral(originalLength),
98
- ])
99
- )
100
- );
101
- } else if (
102
- t.isFunctionExpression(path.node) ||
103
- t.isArrowFunctionExpression(path.node)
104
- ) {
105
- path.replaceWith(
80
+ // Skip if user disabled this feature
81
+ if (!this.options.preserveFunctionLength) return;
82
+
83
+ // Skip if function has no parameters
84
+ if (originalLength === 0) return;
85
+
86
+ // Create the function length setter if it doesn't exist
87
+ if (!this.setFunctionLengthName) {
88
+ this.setFunctionLengthName = this.getPlaceholder("fnLength");
89
+
90
+ this.skip(
91
+ prependProgram(
92
+ path,
93
+ SetFunctionLengthTemplate.compile({
94
+ fnName: this.setFunctionLengthName,
95
+ })
96
+ )
97
+ );
98
+ }
99
+
100
+ if (t.isFunctionDeclaration(path.node)) {
101
+ prepend(
102
+ path.parentPath,
103
+ t.expressionStatement(
106
104
  t.callExpression(t.identifier(this.setFunctionLengthName), [
107
- path.node,
105
+ t.identifier(path.node.id.name),
108
106
  numericLiteral(originalLength),
109
107
  ])
110
- );
111
- } else {
112
- // TODO
113
- }
108
+ )
109
+ );
110
+ } else if (
111
+ t.isFunctionExpression(path.node) ||
112
+ t.isArrowFunctionExpression(path.node)
113
+ ) {
114
+ path.replaceWith(
115
+ t.callExpression(t.identifier(this.setFunctionLengthName), [
116
+ path.node,
117
+ numericLiteral(originalLength),
118
+ ])
119
+ );
120
+ } else {
121
+ // TODO
114
122
  }
115
123
  }
116
124
 
@@ -125,36 +133,6 @@ export class PluginInstance {
125
133
  return "__p_" + getRandomString(4) + (suffix ? "_" + suffix : "");
126
134
  }
127
135
 
128
- /**
129
- * Retrieves (or creates) a `ControlObject` for the given `blockPath`.
130
- */
131
- getControlObject(blockPath: NodePath<t.Block>, createMultiple = true) {
132
- ok(blockPath.isBlock());
133
-
134
- var controlObjects = (blockPath.node as NodeSymbol)[CONTROL_OBJECTS];
135
- if (!controlObjects) {
136
- controlObjects = [];
137
- }
138
-
139
- if (
140
- controlObjects.length === 0 ||
141
- (createMultiple &&
142
- chance(
143
- controlObjects[0].propertyNames.size - 15 * controlObjects.length
144
- ))
145
- ) {
146
- var newControlObject = new ControlObject(this, blockPath);
147
-
148
- controlObjects.push(newControlObject);
149
-
150
- (blockPath.node as NodeSymbol)[CONTROL_OBJECTS] = controlObjects;
151
-
152
- return newControlObject;
153
- }
154
-
155
- return choice(controlObjects);
156
- }
157
-
158
136
  /**
159
137
  * Logs a message to the console, only if `verbose` is enabled.
160
138
  * @param messages
@@ -2,7 +2,6 @@ import { NodePath } from "@babel/traverse";
2
2
  import { PluginArg, PluginObject } from "./plugin";
3
3
  import * as t from "@babel/types";
4
4
  import { Order } from "../order";
5
- import path from "path";
6
5
  import {
7
6
  NodeSymbol,
8
7
  PREDICTABLE,
@@ -13,8 +12,10 @@ import { ok } from "assert";
13
12
  import {
14
13
  getParentFunctionOrProgram,
15
14
  getPatternIdentifierNames,
15
+ isVariableIdentifier,
16
16
  } from "../utils/ast-utils";
17
17
  import { isVariableFunctionIdentifier } from "../utils/function-utils";
18
+ import Template from "../templates/template";
18
19
 
19
20
  /**
20
21
  * Preparation arranges the user's code into an AST the obfuscator can easily transform.
@@ -53,6 +54,37 @@ export default ({ Plugin }: PluginArg): PluginObject => {
53
54
  },
54
55
  },
55
56
 
57
+ // @js-confuser-var "myVar" -> __JS_CONFUSER_VAR__(myVar)
58
+ StringLiteral: {
59
+ exit(path) {
60
+ // Check for @js-confuser-var comment
61
+ if (
62
+ path.node.leadingComments?.find((comment) =>
63
+ comment.value.includes("@js-confuser-var")
64
+ )
65
+ ) {
66
+ var identifierName = path.node.value;
67
+ ok(
68
+ t.isValidIdentifier(identifierName),
69
+ "Invalid identifier name: " + identifierName
70
+ );
71
+
72
+ // Create a new __JS_CONFUSER_VAR__ call with the identifier
73
+ var newExpression = new Template(
74
+ `__JS_CONFUSER_VAR__({identifier})`
75
+ ).expression({
76
+ identifier: t.identifier(identifierName),
77
+ });
78
+
79
+ path.replaceWith(newExpression);
80
+
81
+ // Remove comment and skip further processing
82
+ path.node.leadingComments = [];
83
+ path.skip();
84
+ }
85
+ },
86
+ },
87
+
56
88
  // `Hello ${username}` -> "Hello " + username
57
89
  TemplateLiteral: {
58
90
  exit(path) {
@@ -310,51 +342,6 @@ export default ({ Plugin }: PluginArg): PluginObject => {
310
342
  }
311
343
  },
312
344
  },
313
-
314
- // function a(param = ()=>b)
315
- // _getB = ()=> ()=>b
316
- // function a(param = _getB())
317
- // Basically Babel scope.rename misses this edge case, so we need to manually handle it
318
- // Here were essentially making the variables easier to understand
319
- Function: {
320
- exit(path) {
321
- for (var param of path.get("params")) {
322
- param.traverse({
323
- "FunctionExpression|ArrowFunctionExpression"(_innerPath) {
324
- let innerPath = _innerPath as NodePath<
325
- t.FunctionExpression | t.ArrowFunctionExpression
326
- >;
327
- const child = innerPath.find((path) =>
328
- path.parentPath?.isAssignmentPattern()
329
- );
330
-
331
- if (!child) return;
332
-
333
- if (
334
- t.isAssignmentPattern(child.parent) &&
335
- child.parent.right === child.node
336
- ) {
337
- var creatorName = me.getPlaceholder();
338
- var insertPath = path.insertBefore(
339
- t.variableDeclaration("const", [
340
- t.variableDeclarator(
341
- t.identifier(creatorName),
342
- t.arrowFunctionExpression([], innerPath.node, false)
343
- ),
344
- ])
345
- )[0];
346
-
347
- path.scope.parent.registerDeclaration(insertPath);
348
-
349
- innerPath.replaceWith(
350
- t.callExpression(t.identifier(creatorName), [])
351
- );
352
- }
353
- },
354
- });
355
- }
356
- },
357
- },
358
345
  },
359
346
  };
360
347
  };
@@ -4,7 +4,6 @@ import { PluginArg, PluginObject } from "./plugin";
4
4
  import { Order } from "../order";
5
5
  import { NameGen } from "../utils/NameGen";
6
6
  import { ok } from "assert";
7
- import { computeProbabilityMap } from "../probability";
8
7
 
9
8
  const LABEL = Symbol("label");
10
9
 
@@ -127,7 +126,7 @@ export default function ({ Plugin }: PluginArg): PluginObject {
127
126
  if (isRequired) {
128
127
  var newName = labelInterface.label;
129
128
  if (
130
- computeProbabilityMap(
129
+ me.computeProbabilityMap(
131
130
  me.options.renameLabels,
132
131
  labelInterface.label
133
132
  )
@@ -3,7 +3,6 @@ import { PluginArg, PluginObject } from "./plugin";
3
3
  import { Order } from "../order";
4
4
  import * as t from "@babel/types";
5
5
  import Obfuscator from "../obfuscator";
6
- import { computeProbabilityMap } from "../probability";
7
6
  import {
8
7
  append,
9
8
  getFunctionName,
@@ -13,6 +12,7 @@ import {
13
12
  prepend,
14
13
  } from "../utils/ast-utils";
15
14
  import {
15
+ MULTI_TRANSFORM,
16
16
  NodeSymbol,
17
17
  PREDICTABLE,
18
18
  reservedIdentifiers,
@@ -24,6 +24,8 @@ import { numericLiteral } from "../utils/node";
24
24
  import Template from "../templates/template";
25
25
  import { createEvalIntegrityTemplate } from "../templates/tamperProtectionTemplates";
26
26
 
27
+ const RGF_ELIGIBLE = Symbol("rgfEligible");
28
+
27
29
  /**
28
30
  * RGF (Runtime-Generated-Function) uses the `new Function("code")` syntax to create executable code from strings.
29
31
  *
@@ -96,14 +98,21 @@ export default ({ Plugin }: PluginArg): PluginObject => {
96
98
  },
97
99
  },
98
100
  "FunctionDeclaration|FunctionExpression": {
99
- exit(_path) {
101
+ enter(_path) {
100
102
  if (!active) return;
103
+
104
+ // On enter, determine if Function is eligible for RGF transformation
105
+
101
106
  const path = _path as NodePath<
102
107
  t.FunctionDeclaration | t.FunctionExpression
103
108
  >;
104
109
 
105
110
  if (me.isSkipped(path)) return;
106
111
 
112
+ // Skip nested functions if the parent function is already deemed eligible
113
+ if (path.find((p) => p.node[RGF_ELIGIBLE] || p.node[MULTI_TRANSFORM]))
114
+ return;
115
+
107
116
  // Skip async and generator functions
108
117
  if (path.node.async || path.node.generator) return;
109
118
 
@@ -111,10 +120,8 @@ export default ({ Plugin }: PluginArg): PluginObject => {
111
120
  if (name === me.options.lock?.countermeasures) return;
112
121
  if (me.obfuscator.isInternalVariable(name)) return;
113
122
 
114
- me.log(name);
115
-
116
123
  if (
117
- !computeProbabilityMap(
124
+ !me.computeProbabilityMap(
118
125
  me.options.rgf,
119
126
  name,
120
127
  path.getFunctionParent() === null
@@ -140,13 +147,14 @@ export default ({ Plugin }: PluginArg): PluginObject => {
140
147
 
141
148
  const binding = idPath.scope.getBinding(name);
142
149
  if (!binding) {
143
- identifierPreventingTransform = name;
144
- idPath.stop();
150
+ // Global variables are allowed
145
151
  return;
146
152
  }
147
153
 
154
+ var isOutsideVariable =
155
+ path.scope.parent.getBinding(name) === binding;
148
156
  // If the binding is not in the current scope, it is an outside reference
149
- if (binding.scope !== path.scope) {
157
+ if (isOutsideVariable) {
150
158
  identifierPreventingTransform = name;
151
159
  idPath.stop();
152
160
  }
@@ -163,9 +171,24 @@ export default ({ Plugin }: PluginArg): PluginObject => {
163
171
  return;
164
172
  }
165
173
 
174
+ me.log("Function " + name + " is eligible for RGF transformation");
175
+ path.node[RGF_ELIGIBLE] = true;
176
+ },
177
+ exit(_path) {
178
+ if (!active) return;
179
+
180
+ const path = _path as NodePath<
181
+ t.FunctionDeclaration | t.FunctionExpression
182
+ >;
183
+
184
+ if (me.isSkipped(path)) return;
185
+
186
+ // Function is not eligible for RGF transformation
187
+ if (!path.node[RGF_ELIGIBLE]) return;
188
+
166
189
  const embeddedName = me.getPlaceholder() + "_embedded";
167
190
  const replacementName = me.getPlaceholder() + "_replacement";
168
- const thisName = me.getPlaceholder() + "_this";
191
+ const argumentsName = me.getPlaceholder() + "_args";
169
192
 
170
193
  const lastNode = t.expressionStatement(t.identifier(embeddedName));
171
194
  (lastNode as NodeSymbol)[SKIP] = true;
@@ -179,10 +202,10 @@ export default ({ Plugin }: PluginArg): PluginObject => {
179
202
  t.variableDeclaration("var", [
180
203
  t.variableDeclarator(
181
204
  t.arrayPattern([
182
- t.identifier(thisName),
183
205
  t.identifier(rgfArrayName),
206
+ t.identifier(argumentsName),
184
207
  ]),
185
- t.thisExpression()
208
+ t.identifier("arguments")
186
209
  ),
187
210
  ]),
188
211
  t.functionDeclaration(
@@ -196,7 +219,7 @@ export default ({ Plugin }: PluginArg): PluginObject => {
196
219
  t.identifier(replacementName),
197
220
  t.identifier("apply")
198
221
  ),
199
- [t.identifier(thisName), t.identifier("arguments")]
222
+ [t.thisExpression(), t.identifier(argumentsName)]
200
223
  )
201
224
  ),
202
225
  ])
@@ -225,16 +248,20 @@ export default ({ Plugin }: PluginArg): PluginObject => {
225
248
  .map((plugin) => plugin.pluginInstance.order)
226
249
  );
227
250
 
228
- newObfuscator.plugins = newObfuscator.plugins.filter((plugin) => {
229
- return (
230
- plugin.pluginInstance.order == Order.Preparation ||
231
- !hasRan.has(plugin.pluginInstance.order)
232
- );
233
- });
251
+ // Global Concealing will likely cause issues when Pack is also enabled
252
+ const disallowedTransforms = new Set([Order.GlobalConcealing]);
253
+
254
+ newObfuscator.plugins = newObfuscator.plugins.filter(
255
+ ({ pluginInstance }) => {
256
+ return (
257
+ (pluginInstance.order == Order.Preparation ||
258
+ !hasRan.has(pluginInstance.order)) &&
259
+ !disallowedTransforms.has(pluginInstance.order)
260
+ );
261
+ }
262
+ );
234
263
 
235
- newObfuscator.obfuscateAST(evalFile, {
236
- disablePack: true,
237
- });
264
+ newObfuscator.obfuscateAST(evalFile);
238
265
 
239
266
  const generated = Obfuscator.generateCode(evalFile);
240
267
 
@@ -272,17 +299,19 @@ export default ({ Plugin }: PluginArg): PluginObject => {
272
299
  true
273
300
  ),
274
301
  [
302
+ t.thisExpression(),
275
303
  t.arrayExpression([
276
- t.thisExpression(),
277
304
  t.identifier(rgfArrayName),
305
+ t.identifier("arguments"),
278
306
  ]),
279
- t.identifier("arguments"),
280
307
  ]
281
308
  )
282
309
  ),
283
310
  ])
284
311
  );
285
312
 
313
+ path.skip();
314
+
286
315
  me.setFunctionLength(path, originalLength);
287
316
 
288
317
  me.changeData.functions++;
@@ -1,13 +1,12 @@
1
- import { NodePath } from "@babel/traverse";
2
1
  import { PluginArg, PluginObject } from "./plugin";
3
2
  import * as t from "@babel/types";
4
- import { computeProbabilityMap } from "../probability";
5
3
  import { getRandomInteger } from "../utils/random-utils";
6
4
  import Template from "../templates/template";
7
5
  import { Order } from "../order";
8
6
  import { isStaticValue } from "../utils/static-utils";
9
- import { NodeSymbol, PREDICTABLE } from "../constants";
7
+ import { PREDICTABLE } from "../constants";
10
8
  import { numericLiteral } from "../utils/node";
9
+ import { prependProgram } from "../utils/ast-utils";
11
10
 
12
11
  export default ({ Plugin }: PluginArg): PluginObject => {
13
12
  const me = Plugin(Order.Shuffle, {
@@ -16,6 +15,8 @@ export default ({ Plugin }: PluginArg): PluginObject => {
16
15
  },
17
16
  });
18
17
 
18
+ let fnName: string | null = null;
19
+
19
20
  return {
20
21
  visitor: {
21
22
  ArrayExpression: {
@@ -29,10 +30,31 @@ export default ({ Plugin }: PluginArg): PluginObject => {
29
30
 
30
31
  if (illegalElement) return;
31
32
 
32
- if (!computeProbabilityMap(me.options.shuffle)) {
33
+ if (!me.computeProbabilityMap(me.options.shuffle)) {
33
34
  return;
34
35
  }
35
36
 
37
+ // Create un-shuffling function
38
+ if (!fnName) {
39
+ fnName = me.getPlaceholder() + "_shuffle";
40
+
41
+ prependProgram(
42
+ path,
43
+ new Template(
44
+ `
45
+ function ${fnName}(arr, shift) {
46
+ for (var i = 0; i < shift; i++) {
47
+ arr["push"](arr["shift"]());
48
+ }
49
+ return arr;
50
+ }
51
+ `
52
+ )
53
+ .addSymbols(PREDICTABLE)
54
+ .single<t.FunctionDeclaration>()
55
+ );
56
+ }
57
+
36
58
  var shift = getRandomInteger(
37
59
  1,
38
60
  Math.min(30, path.node.elements.length * 6)
@@ -43,30 +65,10 @@ export default ({ Plugin }: PluginArg): PluginObject => {
43
65
  shiftedElements.unshift(shiftedElements.pop());
44
66
  }
45
67
 
46
- var block = path.find((p) => p.isBlock()) as NodePath<t.Block>;
47
-
48
- var functionExpression = new Template(
49
- `
50
- (function(arr) {
51
- for (var i = 0; i < {shiftNode}; i++) {
52
- arr.push(arr.shift());
53
- }
54
- return arr;
55
- })
56
- `
57
- ).expression<t.FunctionExpression>({
58
- shiftNode: numericLiteral(shift),
59
- });
60
-
61
- (functionExpression as NodeSymbol)[PREDICTABLE] = true;
62
-
63
- var memberExpression = me
64
- .getControlObject(block)
65
- .addProperty(functionExpression);
66
-
67
68
  path.replaceWith(
68
- t.callExpression(memberExpression, [
69
+ t.callExpression(t.identifier(fnName), [
69
70
  t.arrayExpression(shiftedElements),
71
+ numericLiteral(shift),
70
72
  ])
71
73
  );
72
74
 
@@ -1,6 +1,6 @@
1
1
  import { CustomStringEncoding } from "../../options";
2
2
  import Template from "../../templates/template";
3
- import { choice, shuffle } from "../../utils/random-utils";
3
+ import { shuffle } from "../../utils/random-utils";
4
4
  import * as t from "@babel/types";
5
5
 
6
6
  let hasAllEncodings = false;
@@ -1,20 +1,20 @@
1
1
  import { PluginArg, PluginObject } from "../plugin";
2
2
  import * as t from "@babel/types";
3
3
  import { Order } from "../../order";
4
- import { computeProbabilityMap } from "../../probability";
5
4
  import {
6
5
  ensureComputedExpression,
6
+ isModuleImport,
7
7
  prependProgram,
8
8
  } from "../../utils/ast-utils";
9
9
  import { numericLiteral } from "../../utils/node";
10
10
  import {
11
- PakoInflateMin,
11
+ StringCompressionLibraryMinified,
12
12
  StringCompressionTemplate,
13
13
  } from "../../templates/stringCompressionTemplate";
14
14
  import Obfuscator from "../../obfuscator";
15
15
  import { createGetGlobalTemplate } from "../../templates/getGlobalTemplate";
16
16
  import { NO_RENAME } from "../../constants";
17
- const pako = require("pako");
17
+ const LZString = require("lz-string");
18
18
 
19
19
  export default ({ Plugin }: PluginArg): PluginObject => {
20
20
  const me = Plugin(Order.StringCompression, {
@@ -23,6 +23,9 @@ export default ({ Plugin }: PluginArg): PluginObject => {
23
23
  },
24
24
  });
25
25
 
26
+ // String Compression is only applied to the main obfuscator
27
+ // Any RGF functions will not have string compression due to the size of the decompression function
28
+
26
29
  const stringDelimiter = "|";
27
30
 
28
31
  return {
@@ -36,6 +39,9 @@ export default ({ Plugin }: PluginArg): PluginObject => {
36
39
  programPath.traverse({
37
40
  StringLiteral: {
38
41
  exit: (path) => {
42
+ // Don't change module imports
43
+ if (isModuleImport(path)) return;
44
+
39
45
  const originalValue = path.node.value;
40
46
 
41
47
  // Must be at least 3 characters long
@@ -48,7 +54,7 @@ export default ({ Plugin }: PluginArg): PluginObject => {
48
54
  if (typeof index === "undefined") {
49
55
  // Allow user option to skip compression for certain strings
50
56
  if (
51
- !computeProbabilityMap(
57
+ !me.computeProbabilityMap(
52
58
  me.options.stringCompression,
53
59
  originalValue
54
60
  )
@@ -81,11 +87,10 @@ export default ({ Plugin }: PluginArg): PluginObject => {
81
87
  );
82
88
 
83
89
  // Compress the string
84
- var compressedBuffer: Uint8Array = pako.deflate(stringPayload);
85
- var compressedBase64 =
86
- Buffer.from(compressedBuffer).toString("base64");
90
+ var compressedString = LZString.compressToUTF16(stringPayload);
87
91
 
88
- let pakoName = me.obfuscator.getStringCompressionLibraryName();
92
+ let stringCompressionLibraryName =
93
+ me.obfuscator.getStringCompressionLibraryName();
89
94
  let insertStringCompressionLibrary = !me.obfuscator.parentObfuscator;
90
95
 
91
96
  prependProgram(
@@ -95,19 +100,23 @@ export default ({ Plugin }: PluginArg): PluginObject => {
95
100
  stringName: me.getPlaceholder(),
96
101
  stringArray: me.getPlaceholder(),
97
102
  stringDelimiter: () => t.stringLiteral(stringDelimiter),
98
- stringValue: () => t.stringLiteral(compressedBase64),
103
+ stringValue: () => t.stringLiteral(compressedString),
99
104
  GetGlobalTemplate: createGetGlobalTemplate(me, programPath),
100
105
  getGlobalFnName: me.getPlaceholder(),
101
- pakoName: pakoName,
106
+ StringCompressionLibrary: stringCompressionLibraryName,
102
107
  })
103
108
  );
104
109
 
105
110
  if (insertStringCompressionLibrary) {
106
- // RGF function should also clone the entire decompression function
111
+ // RGF functions should not clone the entire decompression function
107
112
  prependProgram(
108
113
  programPath,
109
- Obfuscator.parseCode(PakoInflateMin.replace(/{pako}/g, pakoName))
110
- .program.body
114
+ Obfuscator.parseCode(
115
+ StringCompressionLibraryMinified.replace(
116
+ /{StringCompressionLibrary}/g,
117
+ stringCompressionLibraryName
118
+ )
119
+ ).program.body
111
120
  )[0]
112
121
  .get("declarations")[0]
113
122
  .get("id").node[NO_RENAME] = true;