Pārlūkot izejas kodu

New option: `stringArrayIndexesType` accepts an array of types of string array call indexes

sanex 4 gadi atpakaļ
vecāks
revīzija
ed7fbc5bef
33 mainītis faili ar 391 papildinājumiem un 177 dzēšanām
  1. 2 0
      CHANGELOG.md
  2. 24 1
      README.md
  3. 0 0
      dist/index.browser.js
  4. 0 0
      dist/index.cli.js
  5. 0 0
      dist/index.js
  6. 8 0
      src/cli/JavaScriptObfuscatorCLI.ts
  7. 42 6
      src/custom-nodes/string-array-nodes/AbstractStringArrayCallNode.ts
  8. 1 1
      src/custom-nodes/string-array-nodes/StringArrayCallNode.ts
  9. 1 1
      src/custom-nodes/string-array-nodes/StringArrayScopeCallsWrapperFunctionNode.ts
  10. 9 0
      src/enums/node-transformers/string-array-transformers/StringArrayIndexesType.ts
  11. 2 0
      src/interfaces/options/IOptions.ts
  12. 1 1
      src/node-transformers/preparing-transformers/EvalCallExpressionTransformer.ts
  13. 11 0
      src/options/Options.ts
  14. 4 0
      src/options/presets/Default.ts
  15. 4 0
      src/options/presets/NoCustomNodes.ts
  16. 5 0
      src/types/options/TStringArrayIndexesType.ts
  17. 4 0
      test/dev/dev.ts
  18. 4 4
      test/functional-tests/generators/identifier-names-generators/dictionary-identifier-names-generator/DictionaryIdentifierNamesGenerator.spec.ts
  19. 6 6
      test/functional-tests/generators/identifier-names-generators/mangled-identifier-names-generator/MangledIdentifierNamesGenerator.spec.ts
  20. 8 3
      test/functional-tests/javascript-obfuscator/JavaScriptObfuscator.spec.ts
  21. 2 2
      test/functional-tests/node-transformers/converting-transformers/member-expression-transformer/MemberExpressionTransformer.spec.ts
  22. 2 2
      test/functional-tests/node-transformers/converting-transformers/method-definition-transformer/MethodDefinitionTransformer.spec.ts
  23. 14 14
      test/functional-tests/node-transformers/dead-code-injection-transformers/DeadCodeInjectionTransformer.spec.ts
  24. 7 0
      test/functional-tests/node-transformers/finalizing-transformers/escape-sequence-transformer/EscapeSequenceTransformer.spec.ts
  25. 60 22
      test/functional-tests/node-transformers/preparing-transformers/eval-call-expression-transformer/EvalCallExpressionTransformer.spec.ts
  26. 1 1
      test/functional-tests/node-transformers/preparing-transformers/obfuscating-guards/black-list-obfuscating-guard/BlackListObfuscatingGuard.spec.ts
  27. 1 1
      test/functional-tests/node-transformers/preparing-transformers/obfuscating-guards/force-transform-string-obfuscating-guard/ForceTransformStringObfuscatingGuard.spec.ts
  28. 3 3
      test/functional-tests/node-transformers/preparing-transformers/obfuscating-guards/ignored-require-import-obfuscating-guard/IgnoredRequireImportObfuscatingGuard.spec.ts
  29. 2 2
      test/functional-tests/node-transformers/preparing-transformers/variable-preserve-transformer/VariablePreserveTransformer.spec.ts
  30. 108 57
      test/functional-tests/node-transformers/string-array-transformers/string-array-scope-calls-wrapper-transformer/StringArrayScopeCallsWrapperTransformer.spec.ts
  31. 27 27
      test/functional-tests/node-transformers/string-array-transformers/string-array-transformer/StringArrayTransformer.spec.ts
  32. 23 23
      test/functional-tests/storages/string-array-transformers/string-array-storage/StringArrayStorage.spec.ts
  33. 5 0
      test/runtime-tests/JavaScriptObfuscatorRuntime.spec.ts

+ 2 - 0
CHANGELOG.md

@@ -2,6 +2,8 @@ Change Log
 
 v2.9.0
 ---
+* New option: `stringArrayIndexesType` accepts an array of types of string array call indexes
+* Changed default type of all string array call indexes from `hexadecimal-numeric-string` to `hexadecimal-number`
 * New option: `stringArrayIndexShift` enables additional index shift for all string array calls
 
 v2.8.1

+ 24 - 1
README.md

@@ -364,6 +364,9 @@ Following options are available for the JS Obfuscator:
     splitStrings: false,
     splitStringsChunkLength: 10,
     stringArray: true,
+    stringArrayCallsIndexType: [
+        'hexadecimal-number'
+    ],
     stringArrayEncoding: [],
     stringArrayIndexShift: true,
     stringArrayWrappersCount: 1,
@@ -418,6 +421,7 @@ Following options are available for the JS Obfuscator:
     --split-strings <boolean>
     --split-strings-chunk-length <number>
     --string-array <boolean>
+    --string-array-calls-index-type '<list>' (comma separated) [hexadecimal-number, hexadecimal-numeric-string]
     --string-array-encoding '<list>' (comma separated) [none, base64, rc4]
     --string-array-index-shift <boolean>
     --string-array-wrappers-count <number>
@@ -962,7 +966,7 @@ Sets chunk length of [`splitStrings`](#splitstrings) option.
 Type: `boolean` Default: `true`
 
 Removes string literals and place them in a special array. For instance, the string `"Hello World"` in `var m = "Hello World";` will be replaced with something like `var m = _0x12c456[0x1];`
-    
+
 ### `stringArrayEncoding`
 Type: `string[]` Default: `[]`
 
@@ -989,6 +993,25 @@ stringArrayEncoding: [
 ]
 ```
 
+### `stringArrayIndexesType`
+Type: `string[]` Default: `['hexadecimal-number']`
+
+##### :warning: `stringArray` option must be enabled
+
+Allows to control the type of string array call indexes.
+
+Each `stringArray` call index will be transformed by the randomly picked type from the passed list. This makes possible to use multiple types.
+
+Available values:
+* `'hexadecimal-number'` (`default`): transforms string array call indexes as hexadecimal numbers
+* `'hexadecimal-numeric-string'`: transforms string array call indexes as hexadecimal numeric string
+
+Before `2.9.0` release `javascript-obfuscator` transformed all string array call indexes with `hexadecimal-numeric-string` type. This makes some manual deobfuscation slightly harder but it allows easy detection of these calls by automatic deobfuscators.
+
+The new `hexadecimal-number` type approaches to make harder auto-detect of string array call patterns in the code.
+
+More types will be added in the future.
+
 ### `stringArrayIndexShift`
 Type: `boolean` Default: `true`
 

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
dist/index.browser.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
dist/index.cli.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
dist/index.js


+ 8 - 0
src/cli/JavaScriptObfuscatorCLI.ts

@@ -30,6 +30,7 @@ import { Logger } from '../logger/Logger';
 import { ObfuscatedCodeWriter } from './utils/ObfuscatedCodeWriter';
 import { SourceCodeReader } from './utils/SourceCodeReader';
 import { Utils } from '../utils/Utils';
+import { StringArrayIndexesType } from '../enums/node-transformers/string-array-transformers/StringArrayIndexesType';
 
 export class JavaScriptObfuscatorCLI implements IInitializable {
     /**
@@ -350,6 +351,13 @@ export class JavaScriptObfuscatorCLI implements IInitializable {
                 `Default: ${StringArrayEncoding.None}`,
                 ArraySanitizer
             )
+            .option(
+                '--string-array-indexes-type <list> (comma separated, without whitespaces)',
+                'Encodes each string in strings array using base64 or rc4 (this option can slow down your code speed). ' +
+                `Values: ${CLIUtils.stringifyOptionAvailableValues(StringArrayIndexesType)}. ` +
+                `Default: ${StringArrayIndexesType.HexadecimalNumber}`,
+                ArraySanitizer
+            )
             .option(
                 '--string-array-index-shift <boolean>',
                 'Enables additional index shift for all string array calls',

+ 42 - 6
src/custom-nodes/string-array-nodes/AbstractStringArrayCallNode.ts

@@ -4,11 +4,14 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 import * as ESTree from 'estree';
 
 import { TIdentifierNamesGeneratorFactory } from '../../types/container/generators/TIdentifierNamesGeneratorFactory';
+import { TStringArrayIndexesType } from '../../types/options/TStringArrayIndexesType';
 
 import { ICustomCodeHelperFormatter } from '../../interfaces/custom-code-helpers/ICustomCodeHelperFormatter';
 import { IOptions } from '../../interfaces/options/IOptions';
 import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
 
+import { StringArrayIndexesType } from '../../enums/node-transformers/string-array-transformers/StringArrayIndexesType';
+
 import { AbstractCustomNode } from '../AbstractCustomNode';
 import { NodeFactory } from '../../node/NodeFactory';
 import { NodeMetadata } from '../../node/NodeMetadata';
@@ -42,20 +45,33 @@ export abstract class AbstractStringArrayCallNode extends AbstractCustomNode {
      * @param {number} index
      * @returns {Expression}
      */
-    protected getHexadecimalNode (index: number): ESTree.Expression {
+    protected getStringArrayCallIndexNode (index: number): ESTree.Expression {
         const isPositive: boolean = index >= 0;
         const normalizedIndex: number = Math.abs(index);
 
-        const hexadecimalIndex: string = NumberUtils.toHex(normalizedIndex);
-        const hexadecimalLiteralNode: ESTree.Literal = NodeFactory.literalNode(hexadecimalIndex);
+        const stringArrayCallsIndexType: TStringArrayIndexesType = this.randomGenerator
+            .getRandomGenerator()
+            .pickone(this.options.stringArrayIndexesType);
+        let stringArrayCallIndexNode: ESTree.Expression;
+
+        switch (stringArrayCallsIndexType) {
+            case StringArrayIndexesType.HexadecimalNumber:
+                stringArrayCallIndexNode = this.getHexadecimalNumberCallIndexNode(normalizedIndex);
+                break;
+
+            case StringArrayIndexesType.HexadecimalNumericString:
+            default:
+                stringArrayCallIndexNode = this.getHexadecimalNumericStringCallIndexNode(normalizedIndex);
+                break;
+        }
 
-        NodeMetadata.set(hexadecimalLiteralNode, { replacedLiteral: true });
+        NodeMetadata.set(stringArrayCallIndexNode, { replacedLiteral: true });
 
         const hexadecimalNode: ESTree.Expression = isPositive
-            ? hexadecimalLiteralNode
+            ? stringArrayCallIndexNode
             : NodeFactory.unaryExpressionNode(
                 '-',
-                hexadecimalLiteralNode
+                stringArrayCallIndexNode
             );
 
         NodeUtils.parentizeAst(hexadecimalNode);
@@ -74,4 +90,24 @@ export abstract class AbstractStringArrayCallNode extends AbstractCustomNode {
 
         return rc4KeyLiteralNode;
     }
+
+    /**
+     * @param {number} index
+     * @returns {Expression}
+     */
+    private getHexadecimalNumberCallIndexNode (index: number): ESTree.Expression {
+        const hexadecimalIndex: string = NumberUtils.toHex(index);
+
+        return NodeFactory.literalNode(index, hexadecimalIndex);
+    }
+
+    /**
+     * @param {number} index
+     * @returns {Expression}
+     */
+    private getHexadecimalNumericStringCallIndexNode (index: number): ESTree.Expression {
+        const hexadecimalIndex: string = NumberUtils.toHex(index);
+
+        return NodeFactory.literalNode(hexadecimalIndex);
+    }
 }

+ 1 - 1
src/custom-nodes/string-array-nodes/StringArrayCallNode.ts

@@ -86,7 +86,7 @@ export class StringArrayCallNode extends AbstractStringArrayCallNode {
      */
     protected getNodeStructure (): TStatement[] {
         const callExpressionArgs: ESTree.Expression[] = [
-            this.getHexadecimalNode(this.indexShiftAmount + this.index)
+            this.getStringArrayCallIndexNode(this.indexShiftAmount + this.index)
         ];
 
         if (this.decodeKey) {

+ 1 - 1
src/custom-nodes/string-array-nodes/StringArrayScopeCallsWrapperFunctionNode.ts

@@ -101,7 +101,7 @@ export class StringArrayScopeCallsWrapperFunctionNode extends AbstractStringArra
                             NodeFactory.binaryExpressionNode(
                                 '-',
                                 firstCallArgumentIdentifierNode,
-                                this.getHexadecimalNode(this.shiftedIndex)
+                                this.getStringArrayCallIndexNode(this.shiftedIndex)
                             ),
                             secondCallArgumentIdentifierNode
                         ]

+ 9 - 0
src/enums/node-transformers/string-array-transformers/StringArrayIndexesType.ts

@@ -0,0 +1,9 @@
+import { Utils } from '../../../utils/Utils';
+
+export const StringArrayIndexesType: Readonly<{
+    HexadecimalNumber: 'hexadecimal-number';
+    HexadecimalNumericString: 'hexadecimal-numeric-string';
+}> = Utils.makeEnum({
+    HexadecimalNumber: 'hexadecimal-number',
+    HexadecimalNumericString: 'hexadecimal-numeric-string'
+});

+ 2 - 0
src/interfaces/options/IOptions.ts

@@ -1,4 +1,5 @@
 import { TOptionsPreset } from '../../types/options/TOptionsPreset';
+import { TStringArrayIndexesType } from '../../types/options/TStringArrayIndexesType';
 import { TStringArrayEncoding } from '../../types/options/TStringArrayEncoding';
 import { TStringArrayWrappersType } from '../../types/options/TStringArrayWrappersType';
 import { TTypeFromEnum } from '../../types/utils/TTypeFromEnum';
@@ -43,6 +44,7 @@ export interface IOptions {
     readonly splitStringsChunkLength: number;
     readonly stringArray: boolean;
     readonly stringArrayEncoding: TStringArrayEncoding[];
+    readonly stringArrayIndexesType: TStringArrayIndexesType[];
     readonly stringArrayIndexShift: boolean;
     readonly stringArrayWrappersChainedCalls: boolean;
     readonly stringArrayWrappersCount: number;

+ 1 - 1
src/node-transformers/preparing-transformers/EvalCallExpressionTransformer.ts

@@ -19,7 +19,7 @@ import { StringUtils } from '../../utils/StringUtils';
 @injectable()
 export class EvalCallExpressionTransformer extends AbstractNodeTransformer {
     /**
-     * @type {NodeTransformer.ParentificationTransformer[]}
+     * @type {NodeTransformer.NodeTransformer[]}
      */
     public readonly runAfter: NodeTransformer[] = [
         NodeTransformer.EscapeSequenceTransformer,

+ 11 - 0
src/options/Options.ts

@@ -20,6 +20,7 @@ import {
 
 import { TInputOptions } from '../types/options/TInputOptions';
 import { TOptionsPreset } from '../types/options/TOptionsPreset';
+import { TStringArrayIndexesType } from '../types/options/TStringArrayIndexesType';
 import { TStringArrayEncoding } from '../types/options/TStringArrayEncoding';
 import { TStringArrayWrappersType } from '../types/options/TStringArrayWrappersType';
 import { TTypeFromEnum } from '../types/utils/TTypeFromEnum';
@@ -31,6 +32,7 @@ import { IdentifierNamesGenerator } from '../enums/generators/identifier-names-g
 import { ObfuscationTarget } from '../enums/ObfuscationTarget';
 import { OptionsPreset } from '../enums/options/presets/OptionsPreset';
 import { SourceMapMode } from '../enums/source-map/SourceMapMode';
+import { StringArrayIndexesType } from '../enums/node-transformers/string-array-transformers/StringArrayIndexesType';
 import { StringArrayEncoding } from '../enums/node-transformers/string-array-transformers/StringArrayEncoding';
 import { StringArrayWrappersType } from '../enums/node-transformers/string-array-transformers/StringArrayWrappersType';
 
@@ -314,6 +316,15 @@ export class Options implements IOptions {
     @IsIn([StringArrayEncoding.None, StringArrayEncoding.Base64, StringArrayEncoding.Rc4], { each: true })
     public readonly stringArrayEncoding!: TStringArrayEncoding[];
 
+    /**
+     * @type {TStringArrayIndexesType[]}
+     */
+    @IsArray()
+    @ArrayNotEmpty()
+    @ArrayUnique()
+    @IsIn([StringArrayIndexesType.HexadecimalNumber, StringArrayIndexesType.HexadecimalNumericString], { each: true })
+    public readonly stringArrayIndexesType!: TStringArrayIndexesType[];
+
     /**
      * @type {boolean}
      */

+ 4 - 0
src/options/presets/Default.ts

@@ -4,6 +4,7 @@ import { IdentifierNamesGenerator } from '../../enums/generators/identifier-name
 import { ObfuscationTarget } from '../../enums/ObfuscationTarget';
 import { OptionsPreset } from '../../enums/options/presets/OptionsPreset';
 import { SourceMapMode } from '../../enums/source-map/SourceMapMode';
+import { StringArrayIndexesType } from '../../enums/node-transformers/string-array-transformers/StringArrayIndexesType';
 import { StringArrayEncoding } from '../../enums/node-transformers/string-array-transformers/StringArrayEncoding';
 import { StringArrayWrappersType } from '../../enums/node-transformers/string-array-transformers/StringArrayWrappersType';
 
@@ -47,6 +48,9 @@ export const DEFAULT_PRESET: TInputOptions = Object.freeze({
     stringArrayEncoding: [
         StringArrayEncoding.None
     ],
+    stringArrayIndexesType: [
+        StringArrayIndexesType.HexadecimalNumber
+    ],
     stringArrayIndexShift: true,
     stringArrayWrappersChainedCalls: true,
     stringArrayWrappersCount: 1,

+ 4 - 0
src/options/presets/NoCustomNodes.ts

@@ -5,6 +5,7 @@ import { ObfuscationTarget } from '../../enums/ObfuscationTarget';
 import { SourceMapMode } from '../../enums/source-map/SourceMapMode';
 import { StringArrayEncoding } from '../../enums/node-transformers/string-array-transformers/StringArrayEncoding';
 import { StringArrayWrappersType } from '../../enums/node-transformers/string-array-transformers/StringArrayWrappersType';
+import { StringArrayIndexesType } from '../../enums/node-transformers/string-array-transformers/StringArrayIndexesType';
 
 export const NO_ADDITIONAL_NODES_PRESET: TInputOptions = Object.freeze({
     compact: true,
@@ -44,6 +45,9 @@ export const NO_ADDITIONAL_NODES_PRESET: TInputOptions = Object.freeze({
     stringArrayEncoding: [
         StringArrayEncoding.None
     ],
+    stringArrayIndexesType: [
+        StringArrayIndexesType.HexadecimalNumber
+    ],
     stringArrayIndexShift: false,
     stringArrayWrappersChainedCalls: false,
     stringArrayWrappersCount: 0,

+ 5 - 0
src/types/options/TStringArrayIndexesType.ts

@@ -0,0 +1,5 @@
+import { TTypeFromEnum } from '../utils/TTypeFromEnum';
+
+import { StringArrayIndexesType } from '../../enums/node-transformers/string-array-transformers/StringArrayIndexesType';
+
+export type TStringArrayIndexesType = TTypeFromEnum<typeof StringArrayIndexesType>;

+ 4 - 0
test/dev/dev.ts

@@ -1,6 +1,7 @@
 'use strict';
 
 import { NO_ADDITIONAL_NODES_PRESET } from '../../src/options/presets/NoCustomNodes';
+import { StringArrayIndexesType } from '../../src/enums/node-transformers/string-array-transformers/StringArrayIndexesType';
 
 (function () {
     const JavaScriptObfuscator: any = require('../../index');
@@ -34,6 +35,9 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../src/options/presets/NoCustomNo
             rotateStringArray: true,
             shuffleStringArray: true,
             stringArray: true,
+            stringArrayIndexesType: [
+                StringArrayIndexesType.HexadecimalNumber
+            ],
             stringArrayIndexShift: true,
             stringArrayThreshold: 1,
             stringArrayWrappersCount: 2,

+ 4 - 4
test/functional-tests/generators/identifier-names-generators/dictionary-identifier-names-generator/DictionaryIdentifierNamesGenerator.spec.ts

@@ -14,7 +14,7 @@ describe('DictionaryIdentifierNamesGenerator', () => {
         describe('Variant #1: should not generate same name for string array as existing name in code', () => {
             describe('Variant #1: `renameGlobals` option is disabled', () => {
                 const stringArrayStorageRegExp: RegExp = /const a[aB] *= *\['abc'];/;
-                const variableDeclarationIdentifierNameRegExp: RegExp = /const ab *= *a[abAB]\('0x0'\);/;
+                const variableDeclarationIdentifierNameRegExp: RegExp = /const ab *= *a[abAB]\(0x0\);/;
 
                 let obfuscatedCode: string;
 
@@ -46,7 +46,7 @@ describe('DictionaryIdentifierNamesGenerator', () => {
 
             describe('Variant #2: `renameGlobals` option is enabled', () => {
                 const stringArrayStorageRegExp: RegExp = /const a[aB] *= *\['abc'];/;
-                const lastVariableDeclarationIdentifierNameRegExp: RegExp = /const a[AB] *= *a[AB]\('0x0'\);/;
+                const lastVariableDeclarationIdentifierNameRegExp: RegExp = /const a[AB] *= *a[AB]\(0x0\);/;
 
                 let obfuscatedCode: string;
 
@@ -85,7 +85,7 @@ describe('DictionaryIdentifierNamesGenerator', () => {
 
             describe('Variant #1: `renameGlobals` option is disabled', () => {
                 const stringArrayStorageRegExp: RegExp = /const ([abAB]{1,3}) *= *\['first', *'abc'];/;
-                const variableDeclarationIdentifierNameRegExp: RegExp = /const ([abAB]{1,3}){1,2} *= *[abAB]{1,3}\('0x0'\);/;
+                const variableDeclarationIdentifierNameRegExp: RegExp = /const ([abAB]{1,3}){1,2} *= *[abAB]{1,3}\(0x0\);/;
 
                 let isIdentifiersAreConflicted: boolean = false;
 
@@ -124,7 +124,7 @@ describe('DictionaryIdentifierNamesGenerator', () => {
 
             describe('Variant #2: `renameGlobals` option is enabled', () => {
                 const stringArrayStorageRegExp: RegExp = /const ([abAB]{1,3}) *= *\['first', *'abc'];/;
-                const variableDeclarationIdentifierNameRegExp: RegExp = /const ([abAB]{1,3}){1,2} *= *[abAB]{1,3}\('0x0'\);/;
+                const variableDeclarationIdentifierNameRegExp: RegExp = /const ([abAB]{1,3}){1,2} *= *[abAB]{1,3}\(0x0\);/;
 
                 let isIdentifiersAreConflicted: boolean = false;
 

+ 6 - 6
test/functional-tests/generators/identifier-names-generators/mangled-identifier-names-generator/MangledIdentifierNamesGenerator.spec.ts

@@ -13,7 +13,7 @@ describe('MangledIdentifierNamesGenerator', () => {
         describe('Variant #1: should not generate same name for string array as existing name in code', () => {
             describe('Variant #1: `renameGlobals` option is disabled', () => {
                 const stringArrayStorageRegExp: RegExp = /const ab *= *\['abc'];/;
-                const lastVariableDeclarationIdentifierNameRegExp: RegExp = /const aa *= *ac\('0x0'\);/;
+                const lastVariableDeclarationIdentifierNameRegExp: RegExp = /const aa *= *ac\(0x0\);/;
 
                 let obfuscatedCode: string;
 
@@ -44,7 +44,7 @@ describe('MangledIdentifierNamesGenerator', () => {
 
             describe('Variant #2: `renameGlobals` option is enabled', () => {
                 const stringArrayStorageRegExp: RegExp = /const ab *= *\['abc'];/;
-                const lastVariableDeclarationIdentifierNameRegExp: RegExp = /const aB *= *ac\('0x0'\);/;
+                const lastVariableDeclarationIdentifierNameRegExp: RegExp = /const aB *= *ac\(0x0\);/;
 
                 let obfuscatedCode: string;
 
@@ -79,7 +79,7 @@ describe('MangledIdentifierNamesGenerator', () => {
             describe('Variant #1: `renameGlobals` option is disabled', () => {
                 const stringArrayStorageRegExp: RegExp = /const aa *= *\['abc', *'last'];/;
                 const functionDeclarationIdentifierNameRegExp: RegExp = /function foo *\(\) *{/;
-                const lastVariableDeclarationIdentifierNameRegExp: RegExp = /const ac *= *ab\('0x1'\);/;
+                const lastVariableDeclarationIdentifierNameRegExp: RegExp = /const ac *= *ab\(0x1\);/;
 
                 let obfuscatedCode: string;
 
@@ -115,7 +115,7 @@ describe('MangledIdentifierNamesGenerator', () => {
             describe('Variant #2: `renameGlobals` option is enabled', () => {
                 const stringArrayStorageRegExp: RegExp = /const aa *= *\['abc', *'last'];/;
                 const functionDeclarationIdentifierNameRegExp: RegExp = /function ac *\(\) *{/;
-                const lastVariableDeclarationIdentifierNameRegExp: RegExp = /const ad *= *ab\('0x1'\);/;
+                const lastVariableDeclarationIdentifierNameRegExp: RegExp = /const ad *= *ab\(0x1\);/;
 
                 let obfuscatedCode: string;
 
@@ -222,7 +222,7 @@ describe('MangledIdentifierNamesGenerator', () => {
         describe('Variant #2: Should generate different names set for different lexical scopes when string array is enabled', () => {
             describe('Variant #1: `renameGlobals` option is disabled', () => {
                 const stringArrayIdentifierRegExp: RegExp = /var a *= *\['abc'];/;
-                const variableIdentifierRegExp: RegExp = /var foo *= *b\('0x0'\);/;
+                const variableIdentifierRegExp: RegExp = /var foo *= *b\(0x0\);/;
                 const functionDeclarationRegExp1: RegExp = /function bar *\(c, *d\) *{}/;
                 const functionDeclarationRegExp2: RegExp = /function baz *\(c, *d\) *{}/;
 
@@ -261,7 +261,7 @@ describe('MangledIdentifierNamesGenerator', () => {
 
             describe('Variant #2: `renameGlobals` option is enabled', () => {
                 const stringArrayIdentifierRegExp: RegExp = /var a *= *\['abc'];/;
-                const variableIdentifierRegExp: RegExp = /var c *= *b\('0x0'\);/;
+                const variableIdentifierRegExp: RegExp = /var c *= *b\(0x0\);/;
                 const functionDeclarationRegExp1: RegExp = /function d *\(f, *g\) *{}/;
                 const functionDeclarationRegExp2: RegExp = /function e *\(f, *g\) *{}/;
 

+ 8 - 3
test/functional-tests/javascript-obfuscator/JavaScriptObfuscator.spec.ts

@@ -9,6 +9,7 @@ import { IObfuscatedCode } from '../../../src/interfaces/source-code/IObfuscated
 
 import { SourceMapMode } from '../../../src/enums/source-map/SourceMapMode';
 import { StringArrayEncoding } from '../../../src/enums/node-transformers/string-array-transformers/StringArrayEncoding';
+import { StringArrayIndexesType } from '../../../src/enums/node-transformers/string-array-transformers/StringArrayIndexesType';
 import { StringArrayWrappersType } from '../../../src/enums/node-transformers/string-array-transformers/StringArrayWrappersType';
 
 import { JavaScriptObfuscator } from '../../../src/JavaScriptObfuscatorFacade';
@@ -276,7 +277,7 @@ describe('JavaScriptObfuscator', () => {
 
             describe('Variant #4: with `stringArray`, `renameGlobals` and `identifiersPrefix` options', () => {
                 const stringArrayRegExp: RegExp = /^var foo_0x(\w){4} *= *\['abc'\];/;
-                const stringArrayCallRegExp: RegExp = /var foo_0x(\w){4,6} *= *foo_0x(\w){4}\('0x0'\);$/;
+                const stringArrayCallRegExp: RegExp = /var foo_0x(\w){4,6} *= *foo_0x(\w){4}\(0x0\);$/;
 
                 let obfuscatedCode: string;
 
@@ -368,7 +369,7 @@ describe('JavaScriptObfuscator', () => {
 
         describe('latin literal variable value', () => {
             const stringArrayLatinRegExp: RegExp = /^var _0x(\w){4} *= *\['abc'\];/;
-            const stringArrayCallRegExp: RegExp = /var test *= *_0x(\w){4}\('0x0'\);$/;
+            const stringArrayCallRegExp: RegExp = /var test *= *_0x(\w){4}\(0x0\);$/;
 
             let obfuscatedCode: string;
 
@@ -396,7 +397,7 @@ describe('JavaScriptObfuscator', () => {
 
         describe('cyrillic literal variable value', () => {
             const stringArrayCyrillicRegExp: RegExp = /^var _0x(\w){4} *= *\['абц'\];/;
-            const stringArrayCallRegExp: RegExp = /var test *= *_0x(\w){4}\('0x0'\);$/;
+            const stringArrayCallRegExp: RegExp = /var test *= *_0x(\w){4}\(0x0\);$/;
 
             let obfuscatedCode: string;
 
@@ -918,6 +919,10 @@ describe('JavaScriptObfuscator', () => {
                             StringArrayEncoding.Base64,
                             StringArrayEncoding.Rc4
                         ],
+                        stringArrayIndexesType: [
+                            StringArrayIndexesType.HexadecimalNumber,
+                            StringArrayIndexesType.HexadecimalNumericString
+                        ],
                         stringArrayIndexShift: true,
                         stringArrayWrappersChainedCalls: true,
                         stringArrayWrappersCount: 10,

+ 2 - 2
test/functional-tests/node-transformers/converting-transformers/member-expression-transformer/MemberExpressionTransformer.spec.ts

@@ -31,7 +31,7 @@ describe('MemberExpressionTransformer', () => {
 
         describe('`stringArray` option is enabled', () => {
             const stringArrayRegExp: RegExp = /var _0x([a-f0-9]){4} *= *\['log'\];/;
-            const stringArrayCallRegExp: RegExp = /var test *= *console\[_0x([a-f0-9]){4}\('0x0'\)\];/;
+            const stringArrayCallRegExp: RegExp = /var test *= *console\[_0x([a-f0-9]){4}\(0x0\)\];/;
 
             let obfuscatedCode: string;
 
@@ -61,7 +61,7 @@ describe('MemberExpressionTransformer', () => {
     describe('transformation of member expression node with square brackets', () => {
         describe('Variant #1: square brackets literal ', () => {
             const stringArrayRegExp: RegExp = /var _0x([a-f0-9]){4} *= *\['log'\];/;
-            const stringArrayCallRegExp: RegExp = /var test *= *console\[_0x([a-f0-9]){4}\('0x0'\)\];/;
+            const stringArrayCallRegExp: RegExp = /var test *= *console\[_0x([a-f0-9]){4}\(0x0\)\];/;
 
             let obfuscatedCode: string;
 

+ 2 - 2
test/functional-tests/node-transformers/converting-transformers/method-definition-transformer/MethodDefinitionTransformer.spec.ts

@@ -31,7 +31,7 @@ describe('MethodDefinitionTransformer', () => {
 
         describe('Variant #2: `stringArray` option is enabled', () => {
             const stringArrayRegExp: RegExp = /var _0x([a-f0-9]){4} *= *\['bar'\];/;
-            const stringArrayCallRegExp: RegExp = /\[_0x([a-f0-9]){4}\('0x0'\)\]\(\)\{\}/;
+            const stringArrayCallRegExp: RegExp = /\[_0x([a-f0-9]){4}\(0x0\)\]\(\)\{\}/;
 
             let obfuscatedCode: string;
 
@@ -103,7 +103,7 @@ describe('MethodDefinitionTransformer', () => {
 
         describe('Variant #2: `stringArray` option is enabled', () => {
             const stringArrayRegExp: RegExp = /var _0x([a-f0-9]){4} *= *\['constructor', *'bar'];/;
-            const stringArrayCallRegExp: RegExp = /\[_0x([a-f0-9]){4}\('0x1'\)\]\(\)\{\}/;
+            const stringArrayCallRegExp: RegExp = /\[_0x([a-f0-9]){4}\(0x1\)\]\(\)\{\}/;
 
             let obfuscatedCode: string;
 

+ 14 - 14
test/functional-tests/node-transformers/dead-code-injection-transformers/DeadCodeInjectionTransformer.spec.ts

@@ -12,17 +12,17 @@ import { JavaScriptObfuscator } from '../../../../src/JavaScriptObfuscatorFacade
 describe('DeadCodeInjectionTransformer', () => {
     const variableMatch: string = '_0x([a-f0-9]){4,6}';
     const hexMatch: string = '0x[a-f0-9]';
-    const stringArrayCallMatch: string = `${variableMatch}\\('${hexMatch}'\\)`;
+    const stringArrayCallMatch: string = `${variableMatch}\\(${hexMatch}\\)`;
 
     describe('transformNode', function () {
         this.timeout(100000);
 
         describe('Variant #1 - 5 simple block statements', () => {
             const regExp: RegExp = new RegExp(
-                `if *\\(${variableMatch}\\('${hexMatch}'\\) *[=|!]== *${variableMatch}\\('${hexMatch}'\\)\\) *\\{`+
-                    `(?:console|${variableMatch})\\[${variableMatch}\\('${hexMatch}'\\)\\]\\(${variableMatch}\\('${hexMatch}'\\)\\);` +
+                `if *\\(${variableMatch}\\(${hexMatch}\\) *[=|!]== *${variableMatch}\\(${hexMatch}\\)\\) *\\{`+
+                    `(?:console|${variableMatch})\\[${variableMatch}\\(${hexMatch}\\)\\]\\(${variableMatch}\\(${hexMatch}\\)\\);` +
                 `\\} *else *\\{`+
-                    `(?:console|${variableMatch})\\[${variableMatch}\\('${hexMatch}'\\)\\]\\(${variableMatch}\\('${hexMatch}'\\)\\);` +
+                    `(?:console|${variableMatch})\\[${variableMatch}\\(${hexMatch}\\)\\]\\(${variableMatch}\\(${hexMatch}\\)\\);` +
                 `\\}`,
                 'g'
             );
@@ -58,7 +58,7 @@ describe('DeadCodeInjectionTransformer', () => {
         describe('Variant #2 - block statements count is less than `5`', () => {
             const regexp: RegExp = new RegExp(
                 `var ${variableMatch} *= *function *\\(\\) *\\{` +
-                    `console\\[${variableMatch}\\('${hexMatch}'\\)\\]\\(${variableMatch}\\('${hexMatch}'\\)\\);` +
+                    `console\\[${variableMatch}\\(${hexMatch}\\)\\]\\(${variableMatch}\\(${hexMatch}\\)\\);` +
                 `\\};`,
                 'g'
             );
@@ -94,7 +94,7 @@ describe('DeadCodeInjectionTransformer', () => {
         describe('Variant #3 - deadCodeInjectionThreshold: 0', () => {
             const regexp: RegExp = new RegExp(
                 `var ${variableMatch} *= *function *\\(\\) *\\{` +
-                    `console\\[${variableMatch}\\('${hexMatch}'\\)\\]\\(${variableMatch}\\('${hexMatch}'\\)\\);` +
+                    `console\\[${variableMatch}\\(${hexMatch}\\)\\]\\(${variableMatch}\\(${hexMatch}\\)\\);` +
                 `\\};`,
                 'g'
             );
@@ -131,7 +131,7 @@ describe('DeadCodeInjectionTransformer', () => {
             describe('Variant #1 - function declaration in block statement', () => {
                 const functionRegExp: RegExp = new RegExp(
                     `var ${variableMatch} *= *function *\\(\\) *\\{` +
-                        `console\\[${variableMatch}\\('${hexMatch}'\\)\\]\\(${variableMatch}\\('${hexMatch}'\\)\\);` +
+                        `console\\[${variableMatch}\\(${hexMatch}\\)\\]\\(${variableMatch}\\(${hexMatch}\\)\\);` +
                     `\\};`,
                     'g'
                 );
@@ -183,7 +183,7 @@ describe('DeadCodeInjectionTransformer', () => {
                 describe('Variant #1', () => {
                     const functionRegExp: RegExp = new RegExp(
                         `var ${variableMatch} *= *function *\\(\\) *\\{` +
-                            `console\\[${variableMatch}\\('${hexMatch}'\\)\\]\\(${variableMatch}\\('${hexMatch}'\\)\\);` +
+                            `console\\[${variableMatch}\\(${hexMatch}\\)\\]\\(${variableMatch}\\(${hexMatch}\\)\\);` +
                         `\\};`,
                         'g'
                     );
@@ -236,7 +236,7 @@ describe('DeadCodeInjectionTransformer', () => {
                 describe('Variant #2', () => {
                     const functionRegExp: RegExp = new RegExp(
                         `var ${variableMatch} *= *function *\\(\\) *\\{` +
-                            `console\\[${variableMatch}\\('${hexMatch}'\\)\\]\\(${variableMatch}\\('${hexMatch}'\\)\\);` +
+                            `console\\[${variableMatch}\\(${hexMatch}\\)\\]\\(${variableMatch}\\(${hexMatch}\\)\\);` +
                         `\\};`,
                         'g'
                     );
@@ -289,7 +289,7 @@ describe('DeadCodeInjectionTransformer', () => {
             describe('Variant #3 - await expression in block statement', () => {
                 const functionRegExp: RegExp = new RegExp(
                     `var ${variableMatch} *= *function *\\(\\) *\\{` +
-                        `console\\[${variableMatch}\\('${hexMatch}'\\)\\]\\(${variableMatch}\\('${hexMatch}'\\)\\);` +
+                        `console\\[${variableMatch}\\(${hexMatch}\\)\\]\\(${variableMatch}\\(${hexMatch}\\)\\);` +
                     `\\};`,
                     'g'
                 );
@@ -340,7 +340,7 @@ describe('DeadCodeInjectionTransformer', () => {
             describe('Variant #4 - yield expression in block statement', () => {
                 const functionRegExp: RegExp = new RegExp(
                     `var ${variableMatch} *= *function *\\(\\) *\\{` +
-                        `console\\[${variableMatch}\\('${hexMatch}'\\)\\]\\(${variableMatch}\\('${hexMatch}'\\)\\);` +
+                        `console\\[${variableMatch}\\(${hexMatch}\\)\\]\\(${variableMatch}\\(${hexMatch}\\)\\);` +
                     `\\};`,
                     'g'
                 );
@@ -391,7 +391,7 @@ describe('DeadCodeInjectionTransformer', () => {
             describe('Variant #5 - super expression in block statement', () => {
                 const functionRegExp: RegExp = new RegExp(
                     `var ${variableMatch} *= *function *\\(\\) *\\{` +
-                        `console\\[${variableMatch}\\('${hexMatch}'\\)\\]\\(${variableMatch}\\('${hexMatch}'\\)\\);` +
+                        `console\\[${variableMatch}\\(${hexMatch}\\)\\]\\(${variableMatch}\\(${hexMatch}\\)\\);` +
                     `\\};`,
                     'g'
                 );
@@ -442,7 +442,7 @@ describe('DeadCodeInjectionTransformer', () => {
             describe('Variant #6 - for-await expression in block statement', () => {
                 const functionRegExp: RegExp = new RegExp(
                     `var ${variableMatch} *= *function *\\(\\) *\\{` +
-                        `console\\[${variableMatch}\\('${hexMatch}'\\)\\]\\(${variableMatch}\\('${hexMatch}'\\)\\);` +
+                        `console\\[${variableMatch}\\(${hexMatch}\\)\\]\\(${variableMatch}\\(${hexMatch}\\)\\);` +
                     `\\};`,
                     'g'
                 );
@@ -596,7 +596,7 @@ describe('DeadCodeInjectionTransformer', () => {
         describe('Variant #6 - block scope of block statement is `ProgramNode`', () => {
             const regExp: RegExp = new RegExp(
                 `if *\\(!!\\[\\]\\) *{` +
-                    `console\\[${variableMatch}\\('${hexMatch}'\\)\\]\\(${variableMatch}\\('${hexMatch}'\\)\\);` +
+                    `console\\[${variableMatch}\\(${hexMatch}\\)\\]\\(${variableMatch}\\(${hexMatch}\\)\\);` +
                 `\\}`
             );
 

+ 7 - 0
test/functional-tests/node-transformers/finalizing-transformers/escape-sequence-transformer/EscapeSequenceTransformer.spec.ts

@@ -3,6 +3,7 @@ import { assert } from 'chai';
 import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes';
 
 import { IdentifierNamesGenerator } from '../../../../../src/enums/generators/identifier-names-generators/IdentifierNamesGenerator';
+import { StringArrayIndexesType } from '../../../../../src/enums/node-transformers/string-array-transformers/StringArrayIndexesType';
 
 import { readFileAsString } from '../../../../helpers/readFileAsString';
 
@@ -69,6 +70,9 @@ describe('EscapeSequenceTransformer', function () {
                 {
                     ...NO_ADDITIONAL_NODES_PRESET,
                     stringArray: true,
+                    stringArrayIndexesType: [
+                        StringArrayIndexesType.HexadecimalNumericString
+                    ],
                     stringArrayThreshold: 1,
                     unicodeEscapeSequence: true
                 }
@@ -191,6 +195,9 @@ describe('EscapeSequenceTransformer', function () {
                     ...NO_ADDITIONAL_NODES_PRESET,
                     identifierNamesGenerator: IdentifierNamesGenerator.MangledIdentifierNamesGenerator,
                     stringArray: true,
+                    stringArrayIndexesType: [
+                        StringArrayIndexesType.HexadecimalNumericString
+                    ],
                     stringArrayThreshold: 1,
                     stringArrayWrappersChainedCalls: true,
                     stringArrayWrappersCount: 1,

+ 60 - 22
test/functional-tests/node-transformers/preparing-transformers/eval-call-expression-transformer/EvalCallExpressionTransformer.spec.ts

@@ -2,6 +2,8 @@ import { assert } from 'chai';
 
 import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes';
 
+import { StringArrayIndexesType } from '../../../../../src/enums/node-transformers/string-array-transformers/StringArrayIndexesType';
+
 import { readFileAsString } from '../../../../helpers/readFileAsString';
 
 import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade';
@@ -92,30 +94,66 @@ describe('EvalCallExpressionTransformer', () => {
     });
 
     describe('Variant #4: string array calls wrapper call', () => {
-        const stringArrayRegExp: RegExp = /var _0x([a-f0-9]){4} *= *\['log', *'bar'];/;
-        const stringArrayCallsWrapperRegExp: RegExp = /eval *\('console\[_0x([a-f0-9]){4,6}\(\\'0x0\\'\)]\(_0x([a-f0-9]){4,6}\(\\'0x1\\'\)\);'\);/;
-
-        let obfuscatedCode: string;
-
-        before(() => {
-            const code: string = readFileAsString(__dirname + '/fixtures/string-array-calls-wrapper-call.js');
-
-            obfuscatedCode = JavaScriptObfuscator.obfuscate(
-                code,
-                {
-                    ...NO_ADDITIONAL_NODES_PRESET,
-                    stringArray: true,
-                    stringArrayThreshold: 1
-                }
-            ).getObfuscatedCode();
-        });
-
-        it('match #1: should add strings from eval expression to the string array', () => {
-            assert.match(obfuscatedCode, stringArrayRegExp);
+        describe('Variant #1: hexadecimal number indexes type', () => {
+            const stringArrayRegExp: RegExp = /var _0x([a-f0-9]){4} *= *\['log', *'bar'];/;
+            const stringArrayCallsWrapperRegExp: RegExp = /eval *\('console\[_0x([a-f0-9]){4,6}\(0\)]\(_0x([a-f0-9]){4,6}\(1\)\);'\);/;
+
+            let obfuscatedCode: string;
+
+            before(() => {
+                const code: string = readFileAsString(__dirname + '/fixtures/string-array-calls-wrapper-call.js');
+
+                obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                    code,
+                    {
+                        ...NO_ADDITIONAL_NODES_PRESET,
+                        stringArray: true,
+                        stringArrayIndexesType: [
+                            StringArrayIndexesType.HexadecimalNumber
+                        ],
+                        stringArrayThreshold: 1
+                    }
+                ).getObfuscatedCode();
+            });
+
+            it('match #1: should add strings from eval expression to the string array', () => {
+                assert.match(obfuscatedCode, stringArrayRegExp);
+            });
+
+            it('match #1: should replace string with call to the string array calls wrapper', () => {
+                assert.match(obfuscatedCode, stringArrayCallsWrapperRegExp);
+            });
         });
 
-        it('match #1: should replace string with call to the string array calls wrapper', () => {
-            assert.match(obfuscatedCode, stringArrayCallsWrapperRegExp);
+        describe('Variant #1: hexadecimal numeric string indexes type', () => {
+            const stringArrayRegExp: RegExp = /var _0x([a-f0-9]){4} *= *\['log', *'bar'];/;
+            const stringArrayCallsWrapperRegExp: RegExp = /eval *\('console\[_0x([a-f0-9]){4,6}\(\\'0x0\\'\)]\(_0x([a-f0-9]){4,6}\(\\'0x1\\'\)\);'\);/;
+
+            let obfuscatedCode: string;
+
+            before(() => {
+                const code: string = readFileAsString(__dirname + '/fixtures/string-array-calls-wrapper-call.js');
+
+                obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                    code,
+                    {
+                        ...NO_ADDITIONAL_NODES_PRESET,
+                        stringArray: true,
+                        stringArrayIndexesType: [
+                            StringArrayIndexesType.HexadecimalNumericString
+                        ],
+                        stringArrayThreshold: 1
+                    }
+                ).getObfuscatedCode();
+            });
+
+            it('match #1: should add strings from eval expression to the string array', () => {
+                assert.match(obfuscatedCode, stringArrayRegExp);
+            });
+
+            it('match #1: should replace string with call to the string array calls wrapper', () => {
+                assert.match(obfuscatedCode, stringArrayCallsWrapperRegExp);
+            });
         });
     });
 

+ 1 - 1
test/functional-tests/node-transformers/preparing-transformers/obfuscating-guards/black-list-obfuscating-guard/BlackListObfuscatingGuard.spec.ts

@@ -11,7 +11,7 @@ describe('BlackListObfuscatingGuard', () => {
         describe('`\'use strict\';` operator', () => {
             const useStrictOperatorRegExp: RegExp = /'use *strict';/;
             const stringArrayLatinRegExp: RegExp = /var _0x(\w){4} *= *\['abc'\];/;
-            const stringArrayCallRegExp: RegExp = /var test *= *_0x(\w){4}\('0x0'\);$/;
+            const stringArrayCallRegExp: RegExp = /var test *= *_0x(\w){4}\(0x0\);$/;
 
             let obfuscatedCode: string;
 

+ 1 - 1
test/functional-tests/node-transformers/preparing-transformers/obfuscating-guards/force-transform-string-obfuscating-guard/ForceTransformStringObfuscatingGuard.spec.ts

@@ -13,7 +13,7 @@ describe('ForceTransformStringObfuscatingGuard', () => {
         describe('`forceTransformStrings` option is enabled', () => {
             const obfuscatingGuardRegExp: RegExp = new RegExp(
                 'var foo *= *\'foo\';' +
-                'var bar *= *b\\(\'0x0\'\\);'
+                'var bar *= *b\\(0x0\\);'
             );
 
             let obfuscatedCode: string;

+ 3 - 3
test/functional-tests/node-transformers/preparing-transformers/obfuscating-guards/ignored-require-import-obfuscating-guard/IgnoredRequireImportObfuscatingGuard.spec.ts

@@ -12,7 +12,7 @@ describe('IgnoredRequireImportObfuscatingGuard', () => {
             const obfuscatingGuardRegExp: RegExp = new RegExp(
                 'const foo *= *require\\(\'\\./foo\'\\); *' +
                 'import _0x(?:[a-f0-9]){4,6} from *\'\\./bar\'; *' +
-                'const baz *= *_0x(?:[a-f0-9]){4,6}\\(\'0x0\'\\);'
+                'const baz *= *_0x(?:[a-f0-9]){4,6}\\(0x0\\);'
             );
 
             let obfuscatedCode: string;
@@ -38,9 +38,9 @@ describe('IgnoredRequireImportObfuscatingGuard', () => {
 
         describe('`ignoreRequireImports` option is disabled', () => {
             const obfuscatingGuardRegExp: RegExp = new RegExp(
-                'const foo *= *require\\(_0x(?:[a-f0-9]){4,6}\\(\'0x0\'\\)\\); *' +
+                'const foo *= *require\\(_0x(?:[a-f0-9]){4,6}\\(0x0\\)\\); *' +
                 'import _0x(?:[a-f0-9]){4,6} from *\'\\./bar\'; *' +
-                'const baz *= *_0x(?:[a-f0-9]){4,6}\\(\'0x1\'\\);'
+                'const baz *= *_0x(?:[a-f0-9]){4,6}\\(0x1\\);'
             );
 
             let obfuscatedCode: string;

+ 2 - 2
test/functional-tests/node-transformers/preparing-transformers/variable-preserve-transformer/VariablePreserveTransformer.spec.ts

@@ -12,7 +12,7 @@ describe('VariablePreserveTransformer', () => {
     describe('Variant #1: string array storage name conflicts with identifier name', () => {
         describe('Variant #1: `renameGlobals` option is disabled', () => {
             const stringArrayStorageNameRegExp: RegExp = /const b *= *\['abc'];/;
-            const identifierNameRegExp: RegExp = /const a *= *c\('0x0'\);/;
+            const identifierNameRegExp: RegExp = /const a *= *c\(0x0\);/;
 
             let obfuscatedCode: string;
 
@@ -41,7 +41,7 @@ describe('VariablePreserveTransformer', () => {
 
         describe('Variant #2: `renameGlobals` option is enabled', () => {
             const stringArrayStorageNameRegExp: RegExp = /const b *= *\['abc'];/;
-            const identifierNameRegExp: RegExp = /const d *= *c\('0x0'\);/;
+            const identifierNameRegExp: RegExp = /const d *= *c\(0x0\);/;
 
             let obfuscatedCode: string;
 

+ 108 - 57
test/functional-tests/node-transformers/string-array-transformers/string-array-scope-calls-wrapper-transformer/StringArrayScopeCallsWrapperTransformer.spec.ts

@@ -9,6 +9,7 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/N
 import { readFileAsString } from '../../../../helpers/readFileAsString';
 
 import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade';
+import { StringArrayIndexesType } from '../../../../../src/enums/node-transformers/string-array-transformers/StringArrayIndexesType';
 
 describe('StringArrayScopeCallsWrapperTransformer', function () {
     this.timeout(120000);
@@ -21,9 +22,9 @@ describe('StringArrayScopeCallsWrapperTransformer', function () {
                     '};' +
                     'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
                     'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
-                    'const foo *= *_0x([a-f0-9]){4,6}\\(\'0x0\'\\);' +
-                    'const bar *= *_0x([a-f0-9]){4,6}\\(\'0x1\'\\);' +
-                    'const baz *= *_0x([a-f0-9]){4,6}\\(\'0x2\'\\);'
+                    'const foo *= *_0x([a-f0-9]){4,6}\\(0x0\\);' +
+                    'const bar *= *_0x([a-f0-9]){4,6}\\(0x1\\);' +
+                    'const baz *= *_0x([a-f0-9]){4,6}\\(0x2\\);'
                 );
 
                 let obfuscatedCode: string;
@@ -54,9 +55,9 @@ describe('StringArrayScopeCallsWrapperTransformer', function () {
                     'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
                     'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
                     'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
-                    'const foo *= *_0x([a-f0-9]){4,6}\\(\'0x0\'\\);' +
-                    'const bar *= *_0x([a-f0-9]){4,6}\\(\'0x1\'\\);' +
-                    'const baz *= *_0x([a-f0-9]){4,6}\\(\'0x2\'\\);'
+                    'const foo *= *_0x([a-f0-9]){4,6}\\(0x0\\);' +
+                    'const bar *= *_0x([a-f0-9]){4,6}\\(0x1\\);' +
+                    'const baz *= *_0x([a-f0-9]){4,6}\\(0x2\\);'
                 );
 
                 let obfuscatedCode: string;
@@ -84,9 +85,9 @@ describe('StringArrayScopeCallsWrapperTransformer', function () {
                 const stringArrayCallRegExp: RegExp = new RegExp(
                     'const f *= *b;' +
                     'const g *= *b;' +
-                    'const foo *= *[f|g]\\(\'0x0\'\\);' +
-                    'const bar *= *[f|g]\\(\'0x1\'\\);' +
-                    'const baz *= *[f|g]\\(\'0x2\'\\);'
+                    'const foo *= *[f|g]\\(0x0\\);' +
+                    'const bar *= *[f|g]\\(0x1\\);' +
+                    'const baz *= *[f|g]\\(0x2\\);'
                 );
 
                 let obfuscatedCode: string;
@@ -118,9 +119,9 @@ describe('StringArrayScopeCallsWrapperTransformer', function () {
                     'function test *\\( *\\) *{' +
                         'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
                         'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
-                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x3\'\\);' +
-                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x4\'\\);' +
-                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x5\'\\);' +
+                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(0x3\\);' +
+                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(0x4\\);' +
+                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(0x5\\);' +
                     '}'
                 );
 
@@ -151,9 +152,9 @@ describe('StringArrayScopeCallsWrapperTransformer', function () {
                         'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
                         'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
                         'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
-                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x3\'\\);' +
-                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x4\'\\);' +
-                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x5\'\\);' +
+                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(0x3\\);' +
+                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(0x4\\);' +
+                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(0x5\\);' +
                     '}'
                 );
 
@@ -183,9 +184,9 @@ describe('StringArrayScopeCallsWrapperTransformer', function () {
                     'function test *\\( *\\) *{' +
                         'const h *= *b;' +
                         'const i *= *b;' +
-                        'const c *= *[h|i]\\(\'0x3\'\\);' +
-                        'const d *= *[h|i]\\(\'0x4\'\\);' +
-                        'const e *= *[h|i]\\(\'0x5\'\\);' +
+                        'const c *= *[h|i]\\(0x3\\);' +
+                        'const d *= *[h|i]\\(0x4\\);' +
+                        'const e *= *[h|i]\\(0x5\\);' +
                     '}'
                 );
 
@@ -214,10 +215,10 @@ describe('StringArrayScopeCallsWrapperTransformer', function () {
             describe('Variant #4: correct wrapper for the function default parameter', () => {
                 const stringArrayCallRegExp: RegExp = new RegExp(
                     'const e *= *b;' +
-                    'const foo *= *e\\(\'0x0\'\\);' +
-                    'function test *\\(c *= *e\\(\'0x1\'\\)\\) *{' +
+                    'const foo *= *e\\(0x0\\);' +
+                    'function test *\\(c *= *e\\(0x1\\)\\) *{' +
                         'const f *= *b;' +
-                        'const d *= *f\\(\'0x2\'\\);' +
+                        'const d *= *f\\(0x2\\);' +
                     '}'
                 );
 
@@ -249,7 +250,7 @@ describe('StringArrayScopeCallsWrapperTransformer', function () {
                 const stringArrayCallRegExp: RegExp = new RegExp(
                     'var c *= *b;' +
                     'if *\\(!!\\[]\\) *{' +
-                        'var foo *= *c\\(\'0x0\'\\);' +
+                        'var foo *= *c\\(0x0\\);' +
                     '}'
                 );
 
@@ -278,7 +279,7 @@ describe('StringArrayScopeCallsWrapperTransformer', function () {
             describe('Variant #2: arrow function scope without statements', () => {
                 const stringArrayCallRegExp: RegExp = new RegExp(
                     'var c *= *b;' +
-                    '\\[]\\[c\\(\'0x0\'\\)]\\(\\(\\) *=> *c\\(\'0x1\'\\)\\);'
+                    '\\[]\\[c\\(0x0\\)]\\(\\(\\) *=> *c\\(0x1\\)\\);'
                 );
 
                 let obfuscatedCode: string;
@@ -310,9 +311,9 @@ describe('StringArrayScopeCallsWrapperTransformer', function () {
                 '};' +
                 'var _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
                 'var _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
-                'var foo *= *_0x([a-f0-9]){4,6}\\(\'0x0\'\\);' +
-                'var bar *= *_0x([a-f0-9]){4,6}\\(\'0x1\'\\);' +
-                'var baz *= *_0x([a-f0-9]){4,6}\\(\'0x2\'\\);'
+                'var foo *= *_0x([a-f0-9]){4,6}\\(0x0\\);' +
+                'var bar *= *_0x([a-f0-9]){4,6}\\(0x1\\);' +
+                'var baz *= *_0x([a-f0-9]){4,6}\\(0x2\\);'
             );
 
             let obfuscatedCode: string;
@@ -366,19 +367,19 @@ describe('StringArrayScopeCallsWrapperTransformer', function () {
                 describe('Variant #1: `Mangled` identifier names generator', () => {
                     const stringArrayCallRegExp: RegExp = new RegExp(
                         'const q *= *b;' +
-                        'const foo *= *q\\(\'0x0\'\\);' +
+                        'const foo *= *q\\(0x0\\);' +
                         'function test\\(c, *d\\) *{' +
                             'const r *= *q;' +
-                            'const e *= *r\\(\'0x1\'\\);' +
-                            'const f *= *r\\(\'0x2\'\\);' +
+                            'const e *= *r\\(0x1\\);' +
+                            'const f *= *r\\(0x2\\);' +
                             'function g\\(h, *i\\) *{' +
                                 'const s *= *r;' +
-                                'const j *= *s\\(\'0x3\'\\);' +
-                                'const k *= *s\\(\'0x4\'\\);' +
+                                'const j *= *s\\(0x3\\);' +
+                                'const k *= *s\\(0x4\\);' +
                                 'function l\\(m, *n *\\) *{' +
                                     'const t *= *s;' +
-                                    'const o *= *t\\(\'0x3\'\\);' +
-                                    'const p *= *t\\(\'0x4\'\\);' +
+                                    'const o *= *t\\(0x3\\);' +
+                                    'const p *= *t\\(0x4\\);' +
                                     'return o *\\+ *p;' +
                                 '}' +
                                 'return j *\\+ *k;' +
@@ -578,6 +579,52 @@ describe('StringArrayScopeCallsWrapperTransformer', function () {
             const hexadecimalIndexMatch: string = '0x[a-z0-9]{1,3}';
 
             describe('Variant #1: base', () => {
+                describe('Variant #1: `hexadecimal-number` indexes type', () => {
+                    const stringArrayCallRegExp: RegExp = new RegExp(
+                        'const f *= *function *\\(c, *d\\) *{' +
+                            `return b\\(c *-(?: -)?${hexadecimalIndexMatch}, *d\\);` +
+                        '};' +
+                        `const foo *= *f\\(-? *${hexadecimalIndexMatch}\\);` +
+                        `const bar *= *f\\(-? *${hexadecimalIndexMatch}\\);` +
+                        `const baz *= *f\\(-? *${hexadecimalIndexMatch}\\);` +
+                        'function test *\\( *\\) *{' +
+                            'const g *= *function *\\(c, *d\\) *{' +
+                                `return b\\(c *-(?: -)?${hexadecimalIndexMatch}, *d\\);` +
+                            '};' +
+                            `const c *= *g\\(-? *${hexadecimalIndexMatch}\\);` +
+                            `const d *= *g\\(-? *${hexadecimalIndexMatch}\\);` +
+                            `const e *= *g\\(-? *${hexadecimalIndexMatch}\\);` +
+                        '}'
+                    );
+
+                    let obfuscatedCode: string;
+
+                    before(() => {
+                        const code: string = readFileAsString(__dirname + '/fixtures/wrappers-count-const.js');
+
+                        obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                            code,
+                            {
+                                ...NO_ADDITIONAL_NODES_PRESET,
+                                identifierNamesGenerator: IdentifierNamesGenerator.MangledIdentifierNamesGenerator,
+                                stringArray: true,
+                                stringArrayIndexesType: [
+                                    StringArrayIndexesType.HexadecimalNumber
+                                ],
+                                stringArrayThreshold: 1,
+                                stringArrayWrappersChainedCalls: false,
+                                stringArrayWrappersCount: 1,
+                                stringArrayWrappersType: StringArrayWrappersType.Function
+                            }
+                        ).getObfuscatedCode();
+                    });
+
+                    it('should add correct scope calls wrappers', () => {
+                        assert.match(obfuscatedCode, stringArrayCallRegExp);
+                    });
+                });
+
+                describe('Variant #2: `hexadecimal-numeric-string` indexes type', () => {
                     const stringArrayCallRegExp: RegExp = new RegExp(
                         'const f *= *function *\\(c, *d\\) *{' +
                             `return b\\(c *-(?: -)?'${hexadecimalIndexMatch}', *d\\);` +
@@ -606,6 +653,9 @@ describe('StringArrayScopeCallsWrapperTransformer', function () {
                                 ...NO_ADDITIONAL_NODES_PRESET,
                                 identifierNamesGenerator: IdentifierNamesGenerator.MangledIdentifierNamesGenerator,
                                 stringArray: true,
+                                stringArrayIndexesType: [
+                                    StringArrayIndexesType.HexadecimalNumericString
+                                ],
                                 stringArrayThreshold: 1,
                                 stringArrayWrappersChainedCalls: false,
                                 stringArrayWrappersCount: 1,
@@ -618,22 +668,23 @@ describe('StringArrayScopeCallsWrapperTransformer', function () {
                         assert.match(obfuscatedCode, stringArrayCallRegExp);
                     });
                 });
+            });
 
             describe('Variant #2: correct chained calls', () => {
                     const stringArrayCallRegExp: RegExp = new RegExp(
                         'const f *= *function *\\(c, *d\\) *{' +
-                            `return b\\(c *-(?: -)?'${hexadecimalIndexMatch}', *d\\);` +
+                            `return b\\(c *-(?: -)?${hexadecimalIndexMatch}, *d\\);` +
                         '};' +
-                        `const foo *= *f\\(-? *'${hexadecimalIndexMatch}'\\);` +
-                        `const bar *= *f\\(-? *'${hexadecimalIndexMatch}'\\);` +
-                        `const baz *= *f\\(-? *'${hexadecimalIndexMatch}'\\);` +
+                        `const foo *= *f\\(-? *${hexadecimalIndexMatch}\\);` +
+                        `const bar *= *f\\(-? *${hexadecimalIndexMatch}\\);` +
+                        `const baz *= *f\\(-? *${hexadecimalIndexMatch}\\);` +
                         'function test *\\( *\\) *{' +
                             'const g *= *function *\\(c, *d\\) *{' +
-                                `return f\\(c *-(?: -)?'${hexadecimalIndexMatch}', *d\\);` +
+                                `return f\\(c *-(?: -)?${hexadecimalIndexMatch}, *d\\);` +
                             '};' +
-                            `const c *= *g\\(-? *'${hexadecimalIndexMatch}'\\);` +
-                            `const d *= *g\\(-? *'${hexadecimalIndexMatch}'\\);` +
-                            `const e *= *g\\(-? *'${hexadecimalIndexMatch}'\\);` +
+                            `const c *= *g\\(-? *${hexadecimalIndexMatch}\\);` +
+                            `const d *= *g\\(-? *${hexadecimalIndexMatch}\\);` +
+                            `const e *= *g\\(-? *${hexadecimalIndexMatch}\\);` +
                         '}'
                     );
 
@@ -667,11 +718,11 @@ describe('StringArrayScopeCallsWrapperTransformer', function () {
                         '};' +
                         'function test *\\( *\\) *{' +
                             'const f *= *function *\\(c, *d\\) *{' +
-                                `return b\\(c *-(?: -)?'${hexadecimalIndexMatch}', *d\\);` +
+                                `return b\\(c *-(?: -)?${hexadecimalIndexMatch}, *d\\);` +
                             '};' +
-                            `const c *= *f\\(-? *'${hexadecimalIndexMatch}'\\);` +
-                            `const d *= *f\\(-? *'${hexadecimalIndexMatch}'\\);` +
-                            `const e *= *f\\(-? *'${hexadecimalIndexMatch}'\\);` +
+                            `const c *= *f\\(-? *${hexadecimalIndexMatch}\\);` +
+                            `const d *= *f\\(-? *${hexadecimalIndexMatch}\\);` +
+                            `const e *= *f\\(-? *${hexadecimalIndexMatch}\\);` +
                         '}'
                     );
 
@@ -875,9 +926,9 @@ describe('StringArrayScopeCallsWrapperTransformer', function () {
                     // this one may be added or not depends on:
                     // if all literal values encoded with a single encoding or not
                     '(?:const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};)?' +
-                    'const foo *= *_0x([a-f0-9]){4,6}\\(\'0x0\'\\);' +
-                    'const bar *= *_0x([a-f0-9]){4,6}\\(\'0x1\'\\);' +
-                    'const baz *= *_0x([a-f0-9]){4,6}\\(\'0x2\'\\);'
+                    'const foo *= *_0x([a-f0-9]){4,6}\\(0x0\\);' +
+                    'const bar *= *_0x([a-f0-9]){4,6}\\(0x1\\);' +
+                    'const baz *= *_0x([a-f0-9]){4,6}\\(0x2\\);'
                 );
 
                 let obfuscatedCode: string;
@@ -914,9 +965,9 @@ describe('StringArrayScopeCallsWrapperTransformer', function () {
                     // this one may be added or not depends on:
                     // if all literal values encoded with a single encoding or not
                     '(?:const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};)?' +
-                    'const foo *= *_0x([a-f0-9]){4,6}\\(\'0x0\'\\);' +
-                    'const bar *= *_0x([a-f0-9]){4,6}\\(\'0x1\'\\);' +
-                    'const baz *= *_0x([a-f0-9]){4,6}\\(\'0x2\'\\);'
+                    'const foo *= *_0x([a-f0-9]){4,6}\\(0x0\\);' +
+                    'const bar *= *_0x([a-f0-9]){4,6}\\(0x1\\);' +
+                    'const baz *= *_0x([a-f0-9]){4,6}\\(0x2\\);'
                 );
 
                 let obfuscatedCode: string;
@@ -953,9 +1004,9 @@ describe('StringArrayScopeCallsWrapperTransformer', function () {
                         // this one may be added or not depends on:
                         // if all literal values encoded with a single encoding or not
                         '(?:const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};)?' +
-                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x3\'\\);' +
-                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x4\'\\);' +
-                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x5\'\\);' +
+                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(0x3\\);' +
+                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(0x4\\);' +
+                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(0x5\\);' +
                     '}'
                 );
 
@@ -992,9 +1043,9 @@ describe('StringArrayScopeCallsWrapperTransformer', function () {
                         // this one may be added or not depends on:
                         // if all literal values encoded with a single encoding or not
                         '(?:const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};)?' +
-                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x3\'\\);' +
-                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x4\'\\);' +
-                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x5\'\\);' +
+                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(0x3\\);' +
+                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(0x4\\);' +
+                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(0x5\\);' +
                     '}'
                 );
 

+ 27 - 27
test/functional-tests/node-transformers/string-array-transformers/string-array-transformer/StringArrayTransformer.spec.ts

@@ -17,7 +17,7 @@ describe('StringArrayTransformer', function () {
 
     describe('Variant #1: default behaviour', () => {
         const stringArrayRegExp: RegExp = /^var _0x([a-f0-9]){4} *= *\['test'\];/;
-        const stringArrayCallRegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\('0x0'\);/;
+        const stringArrayCallRegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\(0x0\);/;
 
         let obfuscatedCode: string;
 
@@ -66,9 +66,9 @@ describe('StringArrayTransformer', function () {
 
     describe('Variant #3: `stringArrayIndexShift` option is enabled', () => {
         const stringArrayIndexShiftRegExp: RegExp = /_0x(?:[a-f0-9]){4,6} *= *_0x(?:[a-f0-9]){4,6} *- *(0x[a-z0-9]{1,3});/;
-        const stringArrayCallRegExp1: RegExp = /var _0x(?:[a-f0-9]){4,6} *= *_0x(?:[a-f0-9]){4}\('(0x[a-z0-9]{1,3})'\) *\+ *0x1;/;
-        const stringArrayCallRegExp2: RegExp = /var _0x(?:[a-f0-9]){4,6} *= *_0x(?:[a-f0-9]){4}\('(0x[a-z0-9]{1,3})'\) *\+ *0x2;/;
-        const stringArrayCallRegExp3: RegExp = /var _0x(?:[a-f0-9]){4,6} *= *_0x(?:[a-f0-9]){4}\('(0x[a-z0-9]{1,3})'\) *\+ *0x3;/;
+        const stringArrayCallRegExp1: RegExp = /var _0x(?:[a-f0-9]){4,6} *= *_0x(?:[a-f0-9]){4}\((0x[a-z0-9]{1,3})\) *\+ *0x1;/;
+        const stringArrayCallRegExp2: RegExp = /var _0x(?:[a-f0-9]){4,6} *= *_0x(?:[a-f0-9]){4}\((0x[a-z0-9]{1,3})\) *\+ *0x2;/;
+        const stringArrayCallRegExp3: RegExp = /var _0x(?:[a-f0-9]){4,6} *= *_0x(?:[a-f0-9]){4}\((0x[a-z0-9]{1,3})\) *\+ *0x3;/;
 
         const expectedEvaluationResult: string = 'foo1bar2baz3';
 
@@ -260,7 +260,7 @@ describe('StringArrayTransformer', function () {
 
     describe('Variant #4: same literal node values', () => {
         const stringArrayRegExp: RegExp = /^var _0x([a-f0-9]){4} *= *\['test'\];/;
-        const stringArrayCallRegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\('0x0'\);/;
+        const stringArrayCallRegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\(0x0\);/;
 
         let obfuscatedCode: string;
 
@@ -311,7 +311,7 @@ describe('StringArrayTransformer', function () {
 
     describe('Variant #6: base64 encoding', () => {
         const stringArrayRegExp: RegExp = new RegExp(`^var _0x([a-f0-9]){4} *= *\\['${swapLettersCase('dGVzdA==')}'];`);
-        const stringArrayCallRegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\('0x0'\);/;
+        const stringArrayCallRegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\(0x0\);/;
 
         let obfuscatedCode: string;
 
@@ -340,7 +340,7 @@ describe('StringArrayTransformer', function () {
 
     describe('Variant #7: rc4 encoding', () => {
         describe('Variant #1: single string literal', () => {
-            const regExp: RegExp = /var test *= *_0x([a-f0-9]){4}\('0x0', *'.{4}'\);/;
+            const regExp: RegExp = /var test *= *_0x([a-f0-9]){4}\(0x0, *'.{4}'\);/;
 
             let obfuscatedCode: string;
 
@@ -364,8 +364,8 @@ describe('StringArrayTransformer', function () {
         });
 
         describe('Variant #2: multiple string literals', () => {
-            const variableRegExp1: RegExp = /var test *= *_0x(?:[a-f0-9]){4}\('0x0', *'(.{4})'\);/;
-            const variableRegExp2: RegExp = /var test *= *_0x(?:[a-f0-9]){4}\('0x1', *'(.{4})'\);/;
+            const variableRegExp1: RegExp = /var test *= *_0x(?:[a-f0-9]){4}\(0x0, *'(.{4})'\);/;
+            const variableRegExp2: RegExp = /var test *= *_0x(?:[a-f0-9]){4}\(0x1, *'(.{4})'\);/;
 
             let encodedLiteralValue1: string;
             let encodedLiteralValue2: string;
@@ -466,8 +466,8 @@ describe('StringArrayTransformer', function () {
             const expectedMatchesChance: number = 0.5;
             const expectedMatchesDelta: number = 0.15;
 
-            const noneEncodingRegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\('0x0'\);/;
-            const rc4EncodingRegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\('0x0', *'.{4}'\);/;
+            const noneEncodingRegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\(0x0\);/;
+            const rc4EncodingRegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\(0x0, *'.{4}'\);/;
 
             let noneEncodingMatchesCount: number = 0;
             let rc4EncodingMatchesCount: number = 0;
@@ -522,8 +522,8 @@ describe('StringArrayTransformer', function () {
             const expectedMatchesChance: number = 0.5;
             const expectedMatchesDelta: number = 0.15;
 
-            const base64EncodingRegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\('0x0'\);/;
-            const rc4EncodingRegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\('0x0', *'.{4}'\);/;
+            const base64EncodingRegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\(0x0\);/;
+            const rc4EncodingRegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\(0x0, *'.{4}'\);/;
 
             let base64EncodingMatchesCount: number = 0;
             let rc4EncodingMatchesCount: number = 0;
@@ -577,7 +577,7 @@ describe('StringArrayTransformer', function () {
         const stringArrayThreshold: number = 0.5;
         const delta: number = 0.1;
 
-        const regExp1: RegExp = /var test *= *_0x([a-f0-9]){4}\('0x0'\);/g;
+        const regExp1: RegExp = /var test *= *_0x([a-f0-9]){4}\(0x0\);/g;
         const regExp2: RegExp = /var test *= *'test';/g;
 
         let stringArrayProbability: number,
@@ -616,7 +616,7 @@ describe('StringArrayTransformer', function () {
     });
 
     describe('Variant #12: string array calls wrapper name', () => {
-        const regExp: RegExp = /console\[b\('0x0'\)]\('a'\);/;
+        const regExp: RegExp = /console\[b\(0x0\)]\('a'\);/;
 
         let obfuscatedCode: string;
 
@@ -643,7 +643,7 @@ describe('StringArrayTransformer', function () {
         describe('Variant #1: base `reservedStrings` values', () => {
             describe('Variant #1: single reserved string value', () => {
                 const stringLiteralRegExp1: RegExp = /const foo *= *'foo';/;
-                const stringLiteralRegExp2: RegExp = /const bar *= *_0x([a-f0-9]){4}\('0x0'\);/;
+                const stringLiteralRegExp2: RegExp = /const bar *= *_0x([a-f0-9]){4}\(0x0\);/;
 
                 let obfuscatedCode: string;
 
@@ -702,7 +702,7 @@ describe('StringArrayTransformer', function () {
 
         describe('Variant #2: RegExp `reservedStrings` values', () => {
             describe('Variant #1: single reserved string value', () => {
-                const stringLiteralRegExp1: RegExp = /const foo *= *_0x([a-f0-9]){4}\('0x0'\);/;
+                const stringLiteralRegExp1: RegExp = /const foo *= *_0x([a-f0-9]){4}\(0x0\);/;
                 const stringLiteralRegExp2: RegExp = /const bar *= *'bar';/;
 
                 let obfuscatedCode: string;
@@ -765,7 +765,7 @@ describe('StringArrayTransformer', function () {
         describe('Variant #1: base `forceTransformStrings` values', () => {
             describe('Variant #1: single force transform string value', () => {
                 const stringLiteralRegExp1: RegExp = /const foo *= *'foo';/;
-                const stringLiteralRegExp2: RegExp = /const bar *= *_0x([a-f0-9]){4}\('0x0'\);/;
+                const stringLiteralRegExp2: RegExp = /const bar *= *_0x([a-f0-9]){4}\(0x0\);/;
 
                 let obfuscatedCode: string;
 
@@ -793,8 +793,8 @@ describe('StringArrayTransformer', function () {
             });
 
             describe('Variant #2: two force transform string values', () => {
-                const stringLiteralRegExp1: RegExp = /const foo *= *_0x([a-f0-9]){4}\('0x0'\);/;
-                const stringLiteralRegExp2: RegExp = /const bar *= *_0x([a-f0-9]){4}\('0x1'\);/;
+                const stringLiteralRegExp1: RegExp = /const foo *= *_0x([a-f0-9]){4}\(0x0\);/;
+                const stringLiteralRegExp2: RegExp = /const bar *= *_0x([a-f0-9]){4}\(0x1\);/;
 
                 let obfuscatedCode: string;
 
@@ -825,7 +825,7 @@ describe('StringArrayTransformer', function () {
         describe('Variant #2: RegExp `forceTransformStrings` values', () => {
             describe('Variant #1: single force transform string value', () => {
                 const stringLiteralRegExp1: RegExp = /const foo *= *'foo'/;
-                const stringLiteralRegExp2: RegExp = /const bar *= *_0x([a-f0-9]){4}\('0x0'\);/;
+                const stringLiteralRegExp2: RegExp = /const bar *= *_0x([a-f0-9]){4}\(0x0\);/;
 
                 let obfuscatedCode: string;
 
@@ -853,8 +853,8 @@ describe('StringArrayTransformer', function () {
             });
 
             describe('Variant #2: two force transform string values', () => {
-                const stringLiteralRegExp1: RegExp = /const foo *= *_0x([a-f0-9]){4}\('0x0'\);/;
-                const stringLiteralRegExp2: RegExp = /const bar *= *_0x([a-f0-9]){4}\('0x1'\);/;
+                const stringLiteralRegExp1: RegExp = /const foo *= *_0x([a-f0-9]){4}\(0x0\);/;
+                const stringLiteralRegExp2: RegExp = /const bar *= *_0x([a-f0-9]){4}\(0x1\);/;
 
                 let obfuscatedCode: string;
 
@@ -916,7 +916,7 @@ describe('StringArrayTransformer', function () {
         describe('Variant #4: Priority over `reservedStrings` option', () => {
             describe('Variant #1: base case', () => {
                 const stringLiteralRegExp1: RegExp = /const foo *= *'foo';/;
-                const stringLiteralRegExp2: RegExp = /const bar *= *_0x([a-f0-9]){4}\('0x0'\);/;
+                const stringLiteralRegExp2: RegExp = /const bar *= *_0x([a-f0-9]){4}\(0x0\);/;
 
                 let obfuscatedCode: string;
 
@@ -949,7 +949,7 @@ describe('StringArrayTransformer', function () {
             describe('Variant #1: base case', () => {
                 const stringLiteralRegExp1: RegExp = /const foo *= *'foo';/;
                 const stringLiteralRegExp2: RegExp = /const bar *= *'bar';/;
-                const stringLiteralRegExp3: RegExp = /const baz *= *_0x([a-f0-9]){4}\('0x0'\);/;
+                const stringLiteralRegExp3: RegExp = /const baz *= *_0x([a-f0-9]){4}\(0x0\);/;
 
                 let obfuscatedCode: string;
 
@@ -985,7 +985,7 @@ describe('StringArrayTransformer', function () {
     describe('Variant #15: object expression key literal', () => {
         describe('Variant #1: base key literal', () => {
             const stringArrayRegExp: RegExp = /^var _0x([a-f0-9]){4} *= *\['bar'];/;
-            const objectExpressionRegExp: RegExp = /var test *= *{'foo' *: *_0x([a-f0-9]){4}\('0x0'\)};/;
+            const objectExpressionRegExp: RegExp = /var test *= *{'foo' *: *_0x([a-f0-9]){4}\(0x0\)};/;
 
             let obfuscatedCode: string;
 
@@ -1013,7 +1013,7 @@ describe('StringArrayTransformer', function () {
 
         describe('Variant #2: computed key literal', () => {
             const stringArrayRegExp: RegExp = /^var _0x([a-f0-9]){4} *= *\['foo', *'bar'];/;
-            const objectExpressionRegExp: RegExp = /var test *= *{\[_0x([a-f0-9]){4}\('0x0'\)] *: *_0x([a-f0-9]){4}\('0x1'\)};/;
+            const objectExpressionRegExp: RegExp = /var test *= *{\[_0x([a-f0-9]){4}\(0x0\)] *: *_0x([a-f0-9]){4}\(0x1\)};/;
 
             let obfuscatedCode: string;
 

+ 23 - 23
test/functional-tests/storages/string-array-transformers/string-array-storage/StringArrayStorage.spec.ts

@@ -16,7 +16,7 @@ describe('StringArrayStorage', () => {
             const expectedVariantProbability: number = 1;
 
             const stringArrayVariant1RegExp1: RegExp = /var _0x([a-f0-9]){4} *= *\['test'];/g;
-            const literalNodeVariant1RegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\('0x0'\);/g;
+            const literalNodeVariant1RegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\(0x0\);/g;
 
             let stringArrayVariant1Probability: number,
                 literalNodeVariant1Probability: number;
@@ -80,9 +80,9 @@ describe('StringArrayStorage', () => {
             ];
             const literalNodeVariantRegExps: RegExp[] = [
                 new RegExp(
-                    `var foo *= *_0x([a-f0-9]){4}\\('0x0'\\); *` +
-                    `var bar *= *_0x([a-f0-9]){4}\\('0x1'\\); *` +
-                    `var baz *= *_0x([a-f0-9]){4}\\('0x2'\\);`
+                    `var foo *= *_0x([a-f0-9]){4}\\(0x0\\); *` +
+                    `var bar *= *_0x([a-f0-9]){4}\\(0x1\\); *` +
+                    `var baz *= *_0x([a-f0-9]){4}\\(0x2\\);`
                 )
             ];
 
@@ -157,7 +157,7 @@ describe('StringArrayStorage', () => {
             const expectedVariantProbability: number = 1;
 
             const stringArrayVariantRegExp1: RegExp = /var _0x([a-f0-9]){4} *= *\['test'];/g;
-            const literalNodeVariant1RegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\('0x0'\);/g;
+            const literalNodeVariant1RegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\(0x0\);/g;
 
             let stringArrayVariant1Probability: number,
                 literalNodeVariant1Probability: number;
@@ -223,34 +223,34 @@ describe('StringArrayStorage', () => {
 
             const literalNodeVariantRegExps: RegExp[] = [
                 new RegExp(
-                    `var foo *= *_0x([a-f0-9]){4}\\('0x0'\\); *` +
-                    `var bar *= *_0x([a-f0-9]){4}\\('0x1'\\); *` +
-                    `var baz *= *_0x([a-f0-9]){4}\\('0x2'\\);`
+                    `var foo *= *_0x([a-f0-9]){4}\\(0x0\\); *` +
+                    `var bar *= *_0x([a-f0-9]){4}\\(0x1\\); *` +
+                    `var baz *= *_0x([a-f0-9]){4}\\(0x2\\);`
                 ),
                 new RegExp(
-                    `var foo *= *_0x([a-f0-9]){4}\\('0x0'\\); *` +
-                    `var bar *= *_0x([a-f0-9]){4}\\('0x2'\\); *` +
-                    `var baz *= *_0x([a-f0-9]){4}\\('0x1'\\);`
+                    `var foo *= *_0x([a-f0-9]){4}\\(0x0\\); *` +
+                    `var bar *= *_0x([a-f0-9]){4}\\(0x2\\); *` +
+                    `var baz *= *_0x([a-f0-9]){4}\\(0x1\\);`
                 ),
                 new RegExp(
-                    `var foo *= *_0x([a-f0-9]){4}\\('0x1'\\); *` +
-                    `var bar *= *_0x([a-f0-9]){4}\\('0x0'\\); *` +
-                    `var baz *= *_0x([a-f0-9]){4}\\('0x2'\\);`
+                    `var foo *= *_0x([a-f0-9]){4}\\(0x1\\); *` +
+                    `var bar *= *_0x([a-f0-9]){4}\\(0x0\\); *` +
+                    `var baz *= *_0x([a-f0-9]){4}\\(0x2\\);`
                 ),
                 new RegExp(
-                    `var foo *= *_0x([a-f0-9]){4}\\('0x1'\\); *` +
-                    `var bar *= *_0x([a-f0-9]){4}\\('0x2'\\); *` +
-                    `var baz *= *_0x([a-f0-9]){4}\\('0x0'\\);`
+                    `var foo *= *_0x([a-f0-9]){4}\\(0x1\\); *` +
+                    `var bar *= *_0x([a-f0-9]){4}\\(0x2\\); *` +
+                    `var baz *= *_0x([a-f0-9]){4}\\(0x0\\);`
                 ),
                 new RegExp(
-                    `var foo *= *_0x([a-f0-9]){4}\\('0x2'\\); *` +
-                    `var bar *= *_0x([a-f0-9]){4}\\('0x0'\\); *` +
-                    `var baz *= *_0x([a-f0-9]){4}\\('0x1'\\);`
+                    `var foo *= *_0x([a-f0-9]){4}\\(0x2\\); *` +
+                    `var bar *= *_0x([a-f0-9]){4}\\(0x0\\); *` +
+                    `var baz *= *_0x([a-f0-9]){4}\\(0x1\\);`
                 ),
                 new RegExp(
-                    `var foo *= *_0x([a-f0-9]){4}\\('0x2'\\); *` +
-                    `var bar *= *_0x([a-f0-9]){4}\\('0x1'\\); *` +
-                    `var baz *= *_0x([a-f0-9]){4}\\('0x0'\\);`
+                    `var foo *= *_0x([a-f0-9]){4}\\(0x2\\); *` +
+                    `var bar *= *_0x([a-f0-9]){4}\\(0x1\\); *` +
+                    `var baz *= *_0x([a-f0-9]){4}\\(0x0\\);`
                 )
             ];
 

+ 5 - 0
test/runtime-tests/JavaScriptObfuscatorRuntime.spec.ts

@@ -4,6 +4,7 @@ import { TInputOptions } from '../../src/types/options/TInputOptions';
 
 import { IdentifierNamesGenerator } from '../../src/enums/generators/identifier-names-generators/IdentifierNamesGenerator';
 import { StringArrayEncoding } from '../../src/enums/node-transformers/string-array-transformers/StringArrayEncoding';
+import { StringArrayIndexesType } from '../../src/enums/node-transformers/string-array-transformers/StringArrayIndexesType';
 import { StringArrayWrappersType } from '../../src/enums/node-transformers/string-array-transformers/StringArrayWrappersType';
 
 import { evaluateInWorker } from '../helpers/evaluateInWorker';
@@ -40,6 +41,10 @@ describe('JavaScriptObfuscator runtime eval', function () {
             StringArrayEncoding.Base64,
             StringArrayEncoding.Rc4
         ],
+        stringArrayIndexesType: [
+            StringArrayIndexesType.HexadecimalNumber,
+            StringArrayIndexesType.HexadecimalNumericString
+        ],
         stringArrayIndexShift: true,
         stringArrayWrappersChainedCalls: true,
         stringArrayWrappersCount: 5,

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels