js-confuser 1.5.9 → 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 (143) hide show
  1. package/.github/workflows/node.js.yml +2 -2
  2. package/CHANGELOG.md +55 -0
  3. package/README.md +346 -165
  4. package/dist/constants.js +6 -2
  5. package/dist/index.js +9 -21
  6. package/dist/obfuscator.js +19 -31
  7. package/dist/options.js +5 -5
  8. package/dist/order.js +1 -3
  9. package/dist/presets.js +6 -7
  10. package/dist/probability.js +2 -4
  11. package/dist/templates/bufferToString.js +13 -0
  12. package/dist/templates/crash.js +3 -3
  13. package/dist/templates/es5.js +18 -0
  14. package/dist/templates/functionLength.js +16 -0
  15. package/dist/transforms/calculator.js +77 -21
  16. package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +980 -367
  17. package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +4 -1
  18. package/dist/transforms/controlFlowFlattening/switchCaseObfuscation.js +25 -26
  19. package/dist/transforms/deadCode.js +33 -25
  20. package/dist/transforms/dispatcher.js +8 -4
  21. package/dist/transforms/es5/antiDestructuring.js +2 -0
  22. package/dist/transforms/es5/es5.js +31 -34
  23. package/dist/transforms/extraction/duplicateLiteralsRemoval.js +92 -58
  24. package/dist/transforms/finalizer.js +82 -0
  25. package/dist/transforms/flatten.js +229 -148
  26. package/dist/transforms/identifier/globalAnalysis.js +88 -0
  27. package/dist/transforms/identifier/globalConcealing.js +10 -83
  28. package/dist/transforms/identifier/movedDeclarations.js +35 -88
  29. package/dist/transforms/identifier/renameVariables.js +124 -59
  30. package/dist/transforms/identifier/variableAnalysis.js +58 -62
  31. package/dist/transforms/lock/lock.js +0 -37
  32. package/dist/transforms/minify.js +60 -57
  33. package/dist/transforms/opaquePredicates.js +1 -1
  34. package/dist/transforms/preparation/preparation.js +2 -2
  35. package/dist/transforms/preparation.js +231 -0
  36. package/dist/transforms/renameLabels.js +1 -1
  37. package/dist/transforms/rgf.js +139 -247
  38. package/dist/transforms/stack.js +128 -26
  39. package/dist/transforms/string/encoding.js +150 -179
  40. package/dist/transforms/string/stringCompression.js +14 -15
  41. package/dist/transforms/string/stringConcealing.js +25 -8
  42. package/dist/transforms/string/stringEncoding.js +13 -24
  43. package/dist/transforms/transform.js +12 -19
  44. package/dist/traverse.js +24 -10
  45. package/dist/util/gen.js +17 -1
  46. package/dist/util/identifiers.js +37 -3
  47. package/dist/util/insert.js +35 -4
  48. package/dist/util/random.js +15 -0
  49. package/docs/ControlFlowFlattening.md +595 -0
  50. package/{Countermeasures.md → docs/Countermeasures.md} +1 -15
  51. package/{Integrity.md → docs/Integrity.md} +2 -2
  52. package/docs/RGF.md +419 -0
  53. package/package.json +5 -5
  54. package/src/constants.ts +3 -0
  55. package/src/index.ts +2 -2
  56. package/src/obfuscator.ts +19 -31
  57. package/src/options.ts +14 -103
  58. package/src/order.ts +1 -5
  59. package/src/presets.ts +6 -7
  60. package/src/probability.ts +2 -3
  61. package/src/templates/bufferToString.ts +68 -0
  62. package/src/templates/crash.ts +15 -19
  63. package/src/templates/es5.ts +131 -0
  64. package/src/templates/functionLength.ts +14 -0
  65. package/src/transforms/calculator.ts +122 -59
  66. package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +1583 -571
  67. package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +4 -1
  68. package/src/transforms/deadCode.ts +383 -26
  69. package/src/transforms/dispatcher.ts +9 -4
  70. package/src/transforms/es5/antiDestructuring.ts +2 -0
  71. package/src/transforms/es5/es5.ts +32 -77
  72. package/src/transforms/extraction/duplicateLiteralsRemoval.ts +133 -129
  73. package/src/transforms/{hexadecimalNumbers.ts → finalizer.ts} +29 -13
  74. package/src/transforms/flatten.ts +357 -300
  75. package/src/transforms/identifier/globalAnalysis.ts +85 -0
  76. package/src/transforms/identifier/globalConcealing.ts +14 -103
  77. package/src/transforms/identifier/movedDeclarations.ts +49 -102
  78. package/src/transforms/identifier/renameVariables.ts +149 -78
  79. package/src/transforms/identifier/variableAnalysis.ts +66 -73
  80. package/src/transforms/lock/lock.ts +1 -42
  81. package/src/transforms/minify.ts +91 -75
  82. package/src/transforms/opaquePredicates.ts +2 -2
  83. package/src/transforms/preparation.ts +238 -0
  84. package/src/transforms/renameLabels.ts +2 -2
  85. package/src/transforms/rgf.ts +213 -405
  86. package/src/transforms/stack.ts +156 -36
  87. package/src/transforms/string/encoding.ts +115 -212
  88. package/src/transforms/string/stringCompression.ts +27 -18
  89. package/src/transforms/string/stringConcealing.ts +39 -9
  90. package/src/transforms/string/stringEncoding.ts +18 -18
  91. package/src/transforms/transform.ts +21 -23
  92. package/src/traverse.ts +23 -4
  93. package/src/types.ts +2 -1
  94. package/src/util/gen.ts +28 -3
  95. package/src/util/identifiers.ts +43 -2
  96. package/src/util/insert.ts +38 -3
  97. package/src/util/random.ts +13 -0
  98. package/test/code/Cash.test.ts +1 -1
  99. package/test/code/Dynamic.test.ts +12 -10
  100. package/test/code/ES6.src.js +146 -0
  101. package/test/code/ES6.test.ts +28 -2
  102. package/test/index.test.ts +2 -1
  103. package/test/probability.test.ts +44 -0
  104. package/test/templates/template.test.ts +1 -1
  105. package/test/transforms/antiTooling.test.ts +22 -0
  106. package/test/transforms/calculator.test.ts +40 -0
  107. package/test/transforms/controlFlowFlattening/controlFlowFlattening.test.ts +702 -160
  108. package/test/transforms/controlFlowFlattening/expressionObfuscation.test.ts +173 -0
  109. package/test/transforms/deadCode.test.ts +66 -15
  110. package/test/transforms/dispatcher.test.ts +20 -1
  111. package/test/transforms/es5/antiDestructuring.test.ts +16 -0
  112. package/test/transforms/flatten.test.ts +399 -86
  113. package/test/transforms/identifier/movedDeclarations.test.ts +63 -8
  114. package/test/transforms/identifier/renameVariables.test.ts +119 -0
  115. package/test/transforms/lock/antiDebug.test.ts +2 -2
  116. package/test/transforms/lock/lock.test.ts +1 -48
  117. package/test/transforms/minify.test.ts +104 -0
  118. package/test/transforms/preparation.test.ts +157 -0
  119. package/test/transforms/rgf.test.ts +261 -381
  120. package/test/transforms/stack.test.ts +143 -21
  121. package/test/transforms/string/stringCompression.test.ts +39 -0
  122. package/test/transforms/string/stringConcealing.test.ts +82 -0
  123. package/test/transforms/string/stringEncoding.test.ts +53 -2
  124. package/test/transforms/transform.test.ts +66 -0
  125. package/test/traverse.test.ts +139 -0
  126. package/test/util/identifiers.test.ts +113 -1
  127. package/test/util/insert.test.ts +57 -3
  128. package/src/transforms/controlFlowFlattening/choiceFlowObfuscation.ts +0 -87
  129. package/src/transforms/controlFlowFlattening/controlFlowObfuscation.ts +0 -203
  130. package/src/transforms/controlFlowFlattening/switchCaseObfuscation.ts +0 -130
  131. package/src/transforms/eval.ts +0 -89
  132. package/src/transforms/hideInitializingCode.ts +0 -432
  133. package/src/transforms/identifier/nameRecycling.ts +0 -280
  134. package/src/transforms/label.ts +0 -64
  135. package/src/transforms/preparation/nameConflicts.ts +0 -102
  136. package/src/transforms/preparation/preparation.ts +0 -176
  137. package/test/transforms/controlFlowFlattening/controlFlowObfuscation.test.ts +0 -101
  138. package/test/transforms/controlFlowFlattening/switchCaseObfuscation.test.ts +0 -120
  139. package/test/transforms/eval.test.ts +0 -131
  140. package/test/transforms/hideInitializingCode.test.ts +0 -336
  141. package/test/transforms/identifier/nameRecycling.test.ts +0 -205
  142. package/test/transforms/preparation/nameConflicts.test.ts +0 -52
  143. package/test/transforms/preparation/preparation.test.ts +0 -62
@@ -13,22 +13,17 @@ import {
13
13
  BinaryExpression,
14
14
  FunctionDeclaration,
15
15
  ThisExpression,
16
- FunctionExpression,
16
+ ConditionalExpression,
17
17
  } from "../../util/gen";
18
- import {
19
- append,
20
- clone,
21
- getLexContext,
22
- isLexContext,
23
- prepend,
24
- } from "../../util/insert";
18
+ import { append, clone, prepend } from "../../util/insert";
25
19
  import { isDirective, isPrimitive } from "../../util/compare";
26
20
 
27
21
  import { ObfuscateOrder } from "../../order";
28
22
  import { isModuleSource } from "../string/stringConcealing";
29
23
  import { ComputeProbabilityMap } from "../../probability";
30
24
  import { ok } from "assert";
31
- import { choice, getRandomInteger } from "../../util/random";
25
+ import { chance, choice, getRandomInteger } from "../../util/random";
26
+ import { getBlock } from "../../traverse";
32
27
 
33
28
  /**
34
29
  * [Duplicate Literals Removal](https://docs.jscrambler.com/code-integrity/documentation/transformations/duplicate-literals-removal) replaces duplicate literals with a variable name.
@@ -49,20 +44,25 @@ import { choice, getRandomInteger } from "../../util/random";
49
44
  * ```
50
45
  */
51
46
  export default class DuplicateLiteralsRemoval extends Transform {
47
+ // The array holding all the duplicate literals
52
48
  arrayName: string;
49
+ // The array expression node to be inserted into the program
53
50
  arrayExpression: Node;
51
+
52
+ /**
53
+ * Literals in the array
54
+ */
54
55
  map: Map<string, number>;
55
- first: Map<string, Location | null>;
56
56
 
57
57
  /**
58
- * getter fn name -> accumulative shift
58
+ * Literals are saved here the first time they are seen.
59
59
  */
60
- fnShifts: Map<string, number>;
60
+ first: Map<string, Location>;
61
61
 
62
62
  /**
63
- * lex context -> getter fn name
63
+ * Block -> { functionName, indexShift }
64
64
  */
65
- fnGetters: Map<Node, string>;
65
+ functions: Map<Node, { functionName: string; indexShift: number }>;
66
66
 
67
67
  constructor(o) {
68
68
  super(o, ObfuscateOrder.DuplicateLiteralsRemoval);
@@ -70,14 +70,14 @@ export default class DuplicateLiteralsRemoval extends Transform {
70
70
  this.map = new Map();
71
71
  this.first = new Map();
72
72
 
73
- this.fnShifts = new Map();
74
- this.fnGetters = new Map();
73
+ this.functions = new Map();
75
74
  }
76
75
 
77
76
  apply(tree) {
78
77
  super.apply(tree);
79
78
 
80
- if (this.arrayName && this.arrayExpression.elements.length) {
79
+ if (this.arrayName && this.arrayExpression.elements.length > 0) {
80
+ // This function simply returns the array
81
81
  var getArrayFn = this.getPlaceholder();
82
82
  append(
83
83
  tree,
@@ -88,22 +88,79 @@ export default class DuplicateLiteralsRemoval extends Transform {
88
88
  )
89
89
  );
90
90
 
91
+ // This variable holds the array
91
92
  prepend(
92
93
  tree,
93
94
  VariableDeclaration(
94
95
  VariableDeclarator(
95
96
  this.arrayName,
96
97
  CallExpression(
97
- MemberExpression(
98
- Identifier(getArrayFn),
99
- Identifier("call"),
100
- false
101
- ),
98
+ MemberExpression(Identifier(getArrayFn), Literal("call"), true),
102
99
  [ThisExpression()]
103
100
  )
104
101
  )
105
102
  )
106
103
  );
104
+
105
+ // Create all the functions needed
106
+ for (var blockNode of this.functions.keys()) {
107
+ var { functionName, indexShift } = this.functions.get(blockNode);
108
+
109
+ var propertyNode: Node = BinaryExpression(
110
+ "-",
111
+ Identifier("index_param"),
112
+ Literal(indexShift)
113
+ );
114
+
115
+ var indexRangeInclusive = [
116
+ 0 + indexShift - 1,
117
+ this.map.size + indexShift,
118
+ ];
119
+
120
+ // The function uses mangling to hide the index being accessed
121
+ var mangleCount = getRandomInteger(1, 10);
122
+ for (var i = 0; i < mangleCount; i++) {
123
+ var operator = choice([">", "<"]);
124
+ var compareValue = choice(indexRangeInclusive);
125
+
126
+ var test = BinaryExpression(
127
+ operator,
128
+ Identifier("index_param"),
129
+ Literal(compareValue)
130
+ );
131
+
132
+ var alternate = BinaryExpression(
133
+ "-",
134
+ Identifier("index_param"),
135
+ Literal(getRandomInteger(-100, 100))
136
+ );
137
+
138
+ var testValue =
139
+ (operator === ">" && compareValue === indexRangeInclusive[0]) ||
140
+ (operator === "<" && compareValue === indexRangeInclusive[1]);
141
+
142
+ propertyNode = ConditionalExpression(
143
+ test,
144
+ testValue ? propertyNode : alternate,
145
+ !testValue ? propertyNode : alternate
146
+ );
147
+ }
148
+
149
+ var returnArgument = MemberExpression(
150
+ Identifier(this.arrayName),
151
+ propertyNode,
152
+ true
153
+ );
154
+
155
+ prepend(
156
+ blockNode,
157
+ FunctionDeclaration(
158
+ functionName,
159
+ [Identifier("index_param")],
160
+ [ReturnStatement(returnArgument)]
161
+ )
162
+ );
163
+ }
107
164
  }
108
165
  }
109
166
 
@@ -122,104 +179,44 @@ export default class DuplicateLiteralsRemoval extends Transform {
122
179
  * @param parents
123
180
  * @param index
124
181
  */
125
- toCaller(object: Node, parents: Node[], index: number) {
126
- // get all the getters defined here or higher
127
- var getterNames = [object, ...parents]
128
- .map((x) => this.fnGetters.get(x))
129
- .filter((x) => x);
130
-
131
- // use random getter function
132
- var getterName = choice(getterNames);
133
-
134
- // get this literals context
135
- var lexContext = getLexContext(object, parents);
136
-
137
- var hasGetterHere = this.fnGetters.has(lexContext);
138
-
139
- // create one if none are available (or by random chance if none are here locally)
140
- var shouldCreateNew =
141
- !getterName || (!hasGetterHere && Math.random() > 0.9);
142
-
143
- if (shouldCreateNew) {
144
- ok(!this.fnGetters.has(lexContext));
145
-
146
- var lexContextIndex = parents.findIndex(
147
- (x) => x !== lexContext && isLexContext(x)
148
- );
149
- var basedOn =
150
- lexContextIndex !== -1
151
- ? choice(
152
- parents
153
- .slice(lexContextIndex + 1)
154
- .map((x) => this.fnGetters.get(x))
155
- .filter((x) => x)
156
- )
157
- : null;
158
-
159
- var body = [];
160
- var thisShift = getRandomInteger(-250, 250);
161
- // the name of the getter
162
- getterName = this.getPlaceholder() + "_dLR_" + this.fnGetters.size;
163
-
164
- if (basedOn) {
165
- var shift = this.fnShifts.get(basedOn);
166
- ok(typeof shift === "number");
167
-
168
- body = [
169
- ReturnStatement(
170
- CallExpression(Identifier(basedOn), [
171
- BinaryExpression("+", Identifier("index"), Literal(thisShift)),
172
- ])
173
- ),
174
- ];
182
+ transformLiteral(object: Node, parents: Node[], index: number) {
183
+ var blockNode = choice(parents.filter((x) => this.functions.has(x)));
184
+
185
+ // Create initial function if none exist
186
+ if (this.functions.size === 0) {
187
+ var root = parents[parents.length - 1];
188
+ var rootFunctionName = this.getPlaceholder() + "_dLR_0";
189
+ this.functions.set(root, {
190
+ functionName: rootFunctionName,
191
+ indexShift: getRandomInteger(-100, 100),
192
+ });
193
+
194
+ blockNode = root;
195
+ }
175
196
 
176
- this.fnShifts.set(getterName, shift + thisShift);
177
- } else {
178
- // from scratch
179
-
180
- body = [
181
- ReturnStatement(
182
- MemberExpression(
183
- Identifier(this.arrayName),
184
- BinaryExpression("+", Identifier("index"), Literal(thisShift)),
185
- true
186
- )
187
- ),
188
- ];
197
+ // If no function here exist, possibly create new chained function
198
+ var block = getBlock(object, parents);
199
+ if (!this.functions.has(block) && chance(50 - this.functions.size)) {
200
+ var newFunctionName =
201
+ this.getPlaceholder() + "_dLR_" + this.functions.size;
189
202
 
190
- this.fnShifts.set(getterName, thisShift);
191
- }
203
+ this.functions.set(block, {
204
+ functionName: newFunctionName,
205
+ indexShift: getRandomInteger(-100, 100),
206
+ });
192
207
 
193
- this.fnGetters.set(lexContext, getterName);
194
-
195
- prepend(
196
- lexContext,
197
- VariableDeclaration(
198
- VariableDeclarator(
199
- getterName,
200
- CallExpression(
201
- FunctionExpression(
202
- [],
203
- [
204
- ReturnStatement(
205
- FunctionExpression([Identifier("index")], body)
206
- ),
207
- ]
208
- ),
209
- []
210
- )
211
- )
212
- )
213
- );
208
+ blockNode = block;
214
209
  }
215
210
 
216
- var theShift = this.fnShifts.get(getterName);
211
+ // Derive the function to call from the selected blockNode
212
+ var { functionName, indexShift } = this.functions.get(blockNode);
217
213
 
218
- this.replaceIdentifierOrLiteral(
219
- object,
220
- CallExpression(Identifier(getterName), [Literal(index - theShift)]),
221
- parents
222
- );
214
+ // Call the function given it's indexShift
215
+ var callExpression = CallExpression(Identifier(functionName), [
216
+ Literal(index + indexShift),
217
+ ]);
218
+
219
+ this.replaceIdentifierOrLiteral(object, callExpression, parents);
223
220
  }
224
221
 
225
222
  transform(object: Node, parents: Node[]) {
@@ -233,6 +230,9 @@ export default class DuplicateLiteralsRemoval extends Transform {
233
230
  return;
234
231
  }
235
232
 
233
+ // HARD CODED LIMIT of 10,000 (after 1,000 elements)
234
+ if (this.map.size > 1000 && chance(this.map.size / 100)) return;
235
+
236
236
  if (
237
237
  this.arrayName &&
238
238
  parents[0].object &&
@@ -241,11 +241,11 @@ export default class DuplicateLiteralsRemoval extends Transform {
241
241
  return;
242
242
  }
243
243
 
244
- var value;
244
+ var stringValue;
245
245
  if (object.type == "Literal") {
246
- value = typeof object.value + ":" + object.value;
246
+ stringValue = typeof object.value + ":" + object.value;
247
247
  if (object.value === null) {
248
- value = "null:null";
248
+ stringValue = "null:null";
249
249
  } else {
250
250
  // Skip empty strings
251
251
  if (typeof object.value === "string" && !object.value) {
@@ -253,42 +253,46 @@ export default class DuplicateLiteralsRemoval extends Transform {
253
253
  }
254
254
  }
255
255
  } else if (object.type == "Identifier") {
256
- value = "identifier:" + object.name;
256
+ stringValue = "identifier:" + object.name;
257
257
  } else {
258
258
  throw new Error("Unsupported primitive type: " + object.type);
259
259
  }
260
260
 
261
- ok(value);
261
+ ok(stringValue);
262
262
 
263
- if (!this.first.has(value) && !this.map.has(value)) {
264
- this.first.set(value, [object, parents]);
265
- } else {
263
+ if (this.map.has(stringValue) || this.first.has(stringValue)) {
264
+ // Create the array if not already made
266
265
  if (!this.arrayName) {
267
266
  this.arrayName = this.getPlaceholder();
268
267
  this.arrayExpression = ArrayExpression([]);
269
268
  }
270
269
 
271
- var firstLocation = this.first.get(value);
270
+ // Delete with first location
271
+ var firstLocation = this.first.get(stringValue);
272
272
  if (firstLocation) {
273
- this.first.set(value, null);
274
273
  var index = this.map.size;
275
274
 
276
- ok(!this.map.has(value));
277
- this.map.set(value, index);
275
+ ok(!this.map.has(stringValue));
276
+ this.map.set(stringValue, index);
277
+ this.first.delete(stringValue);
278
278
 
279
279
  var pushing = clone(object);
280
280
  this.arrayExpression.elements.push(pushing);
281
281
 
282
282
  ok(this.arrayExpression.elements[index] === pushing);
283
283
 
284
- this.toCaller(firstLocation[0], firstLocation[1], index);
284
+ this.transformLiteral(firstLocation[0], firstLocation[1], index);
285
285
  }
286
286
 
287
- var index = this.map.get(value);
287
+ var index = this.map.get(stringValue);
288
288
  ok(typeof index === "number");
289
289
 
290
- this.toCaller(object, parents, index);
290
+ this.transformLiteral(object, parents, index);
291
+ return;
291
292
  }
293
+
294
+ // Save this, maybe a duplicate will be found.
295
+ this.first.set(stringValue, [object, parents]);
292
296
  };
293
297
  }
294
298
  }
@@ -1,18 +1,28 @@
1
- import Transform from "./transform";
2
1
  import { ObfuscateOrder } from "../order";
3
2
  import { ExitCallback } from "../traverse";
4
3
  import { Identifier, Node } from "../util/gen";
4
+ import StringEncoding from "./string/stringEncoding";
5
+ import Transform from "./transform";
5
6
 
6
7
  /**
7
- * The HexadecimalNumbers transformation converts number literals into the hexadecimal form.
8
+ * The Finalizer is the last transformation before the code is ready to be generated.
9
+ *
10
+ * Hexadecimal numbers:
11
+ * - Convert integer literals into `Identifier` nodes with the name being a hexadecimal number
8
12
  *
9
- * This is done by replacing the number literal with an Identifier to ensure escodegen properly outputs it as such
13
+ * BigInt support:
14
+ * - Convert BigInt literals into `Identifier` nodes with the name being the raw BigInt string value + "n"
10
15
  *
11
- * This transformation also handles BigInt support, so its always enabled for this reason.
16
+ * String Encoding:
17
+ * - Convert String literals into `Identifier` nodes with the name being a unicode escaped string
12
18
  */
13
- export default class HexadecimalNumbers extends Transform {
19
+ export default class Finalizer extends Transform {
20
+ stringEncoding: StringEncoding;
21
+
14
22
  constructor(o) {
15
- super(o, ObfuscateOrder.HexadecimalNumbers);
23
+ super(o, ObfuscateOrder.Finalizer);
24
+
25
+ this.stringEncoding = new StringEncoding(o);
16
26
  }
17
27
 
18
28
  isNumberLiteral(object: Node) {
@@ -27,15 +37,13 @@ export default class HexadecimalNumbers extends Transform {
27
37
  return object.type === "Literal" && typeof object.value === "bigint";
28
38
  }
29
39
 
30
- match(object: Node, parents: Node[]): boolean {
31
- return (
32
- (this.options.hexadecimalNumbers && this.isNumberLiteral(object)) ||
33
- this.isBigIntLiteral(object)
34
- );
40
+ match(object, parents) {
41
+ return object.type === "Literal";
35
42
  }
36
43
 
37
44
  transform(object: Node, parents: Node[]): void | ExitCallback {
38
- if (this.isNumberLiteral(object)) {
45
+ // Hexadecimal Numbers
46
+ if (this.options.hexadecimalNumbers && this.isNumberLiteral(object)) {
39
47
  return () => {
40
48
  // Technically, a Literal will never be negative because it's supposed to be inside a UnaryExpression with a "-" operator.
41
49
  // This code handles it regardless
@@ -48,12 +56,20 @@ export default class HexadecimalNumbers extends Transform {
48
56
  };
49
57
  }
50
58
 
51
- // https://github.com/MichaelXF/js-confuser/issues/79
59
+ // BigInt support
52
60
  if (this.isBigIntLiteral(object)) {
61
+ // https://github.com/MichaelXF/js-confuser/issues/79
53
62
  return () => {
54
63
  // Use an Identifier with the raw string
55
64
  this.replace(object, Identifier(object.raw));
56
65
  };
57
66
  }
67
+
68
+ if (
69
+ this.options.stringEncoding &&
70
+ this.stringEncoding.match(object, parents)
71
+ ) {
72
+ return this.stringEncoding.transform(object, parents);
73
+ }
58
74
  }
59
75
  }