Explorar el Código

String array improvement: fixed bugs

sanex hace 4 años
padre
commit
3b8af4b29a
Se han modificado 20 ficheros con 220 adiciones y 111 borrados
  1. 1 1
      CHANGELOG.md
  2. 0 0
      dist/index.browser.js
  3. 0 0
      dist/index.cli.js
  4. 0 0
      dist/index.js
  5. 11 6
      src/analyzers/number-numerical-expression-analyzer/NumberNumericalExpressionAnalyzer.ts
  6. 16 9
      src/analyzers/string-array-storage-analyzer/StringArrayStorageAnalyzer.ts
  7. 5 4
      src/custom-code-helpers/string-array/templates/string-array-calls-wrapper/StringArrayBase64DecodeTemplate.ts
  8. 5 4
      src/custom-code-helpers/string-array/templates/string-array-calls-wrapper/StringArrayRC4DecodeTemplate.ts
  9. 0 3
      src/custom-code-helpers/string-array/templates/string-array-rotate-function/StringArrayRotateFunctionTemplate.ts
  10. 6 2
      src/interfaces/analyzers/number-numerical-expression-analyzer/INumberNumericalExpressionAnalyzer.ts
  11. 11 0
      src/interfaces/analyzers/string-array-storage-analyzer/IStringArrayStorageAnalyzer.ts
  12. 5 1
      src/node-transformers/converting-transformers/NumberToNumericalExpressionTransformer.ts
  13. 72 20
      src/node-transformers/string-array-transformers/StringArrayRotateFunctionTransformer.ts
  14. 1 1
      src/options/Options.ts
  15. 5 5
      test/functional-tests/custom-code-helpers/string-array/StringArrayRotateFunctionCodeHelper.spec.ts
  16. 6 6
      test/functional-tests/custom-code-helpers/string-array/templates/string-array-rotate-function-template/StringArrayRotateFunctionTemplate.spec.ts
  17. 0 12
      test/functional-tests/node-transformers/string-array-transformers/string-array-transformer/StringArrayTransformer.spec.ts
  18. 22 23
      test/functional-tests/storages/string-array-transformers/string-array-storage/StringArrayStorage.spec.ts
  19. 17 5
      test/runtime-tests/JavaScriptObfuscatorRuntime.spec.ts
  20. 37 9
      test/unit-tests/analyzers/number-numerical-expression-analyzer/NumberNumericalExpressionAnalyzer.spec.ts

+ 1 - 1
CHANGELOG.md

@@ -2,7 +2,7 @@ Change Log
 
 v2.10.0
 ---
-* `splitStringsChunkLength` minimum value is `3` now
+* Improved `rotateStringArray` option
 
 v2.9.5
 ---

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
dist/index.browser.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
dist/index.cli.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
dist/index.js


+ 11 - 6
src/analyzers/number-numerical-expression-analyzer/NumberNumericalExpressionAnalyzer.ts

@@ -17,7 +17,7 @@ export class NumberNumericalExpressionAnalyzer implements INumberNumericalExpres
     /**
      * @type {number}
      */
-    private static readonly additionalParts: number = 3;
+    public static readonly defaultAdditionalPartsCount: number = 3;
 
     /**
      * @type {Map<number, number[]>}
@@ -40,9 +40,13 @@ export class NumberNumericalExpressionAnalyzer implements INumberNumericalExpres
 
     /**
      * @param {number} number
+     * @param {number} additionalPartsCount
      * @returns {TNumberNumericalExpressionData}
      */
-    public analyze (number: number): TNumberNumericalExpressionData {
+    public analyze (
+        number: number,
+        additionalPartsCount: number
+    ): TNumberNumericalExpressionData {
         if (isNaN(number)) {
             throw new Error('Given value is NaN');
         }
@@ -51,16 +55,17 @@ export class NumberNumericalExpressionAnalyzer implements INumberNumericalExpres
             return [number];
         }
 
-        const additionParts: number[] = this.generateAdditionParts(number);
+        const additionParts: number[] = this.generateAdditionParts(number, additionalPartsCount);
 
         return additionParts.map((addition: number) => this.mixWithMultiplyParts(addition));
     }
 
     /**
      * @param {number} number
+     * @param {number} additionalPartsCount
      * @returns {number[]}
      */
-    private generateAdditionParts (number: number): number[] {
+    private generateAdditionParts (number: number, additionalPartsCount: number): number[] {
         const additionParts = [];
 
         const upperNumberLimit: number = Math.min(Math.abs(number * 2), Number.MAX_SAFE_INTEGER);
@@ -70,8 +75,8 @@ export class NumberNumericalExpressionAnalyzer implements INumberNumericalExpres
 
         let temporarySum = 0;
 
-        for (let i = 0; i < NumberNumericalExpressionAnalyzer.additionalParts; i++) {
-            if (i < NumberNumericalExpressionAnalyzer.additionalParts - 1) {
+        for (let i = 0; i < additionalPartsCount; i++) {
+            if (i < additionalPartsCount - 1) {
                 // trailing parts
 
                 let addition: number = this.randomGenerator.getRandomInteger(from, to);

+ 16 - 9
src/analyzers/string-array-storage-analyzer/StringArrayStorageAnalyzer.ts

@@ -86,19 +86,11 @@ export class StringArrayStorageAnalyzer implements IStringArrayStorageAnalyzer {
         });
     }
 
-    /**
-     * @param {Literal} literalNode
-     * @returns {IStringArrayStorageItemData | undefined}
-     */
-    public getItemDataForLiteralNode (literalNode: ESTree.Literal): IStringArrayStorageItemData | undefined {
-        return this.stringArrayStorageData.get(literalNode);
-    }
-
     /**
      * @param {Literal} literalNode
      * @param {Node} parentNode
      */
-    private analyzeLiteralNode (literalNode: ESTree.Literal, parentNode: ESTree.Node): void {
+    public analyzeLiteralNode (literalNode: ESTree.Literal, parentNode: ESTree.Node): void {
         if (!NodeLiteralUtils.isStringLiteralNode(literalNode)) {
             return;
         }
@@ -111,12 +103,27 @@ export class StringArrayStorageAnalyzer implements IStringArrayStorageAnalyzer {
             return;
         }
 
+        this.addItemDataForLiteralNode(literalNode);
+    }
+
+    /**
+     * @param {(SimpleLiteral & {value: string}) | (RegExpLiteral & {value: string})} literalNode
+     */
+    public addItemDataForLiteralNode (literalNode: ESTree.Literal & {value: string}): void {
         this.stringArrayStorageData.set(
             literalNode,
             this.stringArrayStorage.getOrThrow(literalNode.value)
         );
     }
 
+    /**
+     * @param {Literal} literalNode
+     * @returns {IStringArrayStorageItemData | undefined}
+     */
+    public getItemDataForLiteralNode (literalNode: ESTree.Literal): IStringArrayStorageItemData | undefined {
+        return this.stringArrayStorageData.get(literalNode);
+    }
+
     /**
      * @param {(SimpleLiteral & {value: string})} literalNode
      * @returns {boolean}

+ 5 - 4
src/custom-code-helpers/string-array/templates/string-array-calls-wrapper/StringArrayBase64DecodeTemplate.ts

@@ -33,14 +33,15 @@ export function StringArrayBase64DecodeTemplate (
             {stringArrayCallsWrapperName}.${initializedIdentifier} = true;
         }
                   
-        const ignoreCache = {stringArrayName}[-1];
-        const cachedValue = {stringArrayCallsWrapperName}.${dataIdentifier}[index];
+        const firstValue = {stringArrayName}[0];
+        const cacheKey = index + firstValue;
+        const cachedValue = {stringArrayCallsWrapperName}.${dataIdentifier}[cacheKey];
                         
-        if (ignoreCache || cachedValue === undefined) {
+        if (cachedValue === undefined) {
             {selfDefendingCode}
             
             value = {stringArrayCallsWrapperName}.${base64DecodeFunctionIdentifier}(value);
-            {stringArrayCallsWrapperName}.${dataIdentifier}[index] = value;
+            {stringArrayCallsWrapperName}.${dataIdentifier}[cacheKey] = value;
         } else {
             value = cachedValue;
         }

+ 5 - 4
src/custom-code-helpers/string-array/templates/string-array-calls-wrapper/StringArrayRC4DecodeTemplate.ts

@@ -26,10 +26,11 @@ export function StringArrayRC4DecodeTemplate (
             {stringArrayCallsWrapperName}.${initializedIdentifier} = true;
         }
   
-        const ignoreCache = {stringArrayName}[-1];
-        const cachedValue = {stringArrayCallsWrapperName}.${dataIdentifier}[index];
+        const firstValue = {stringArrayName}[0];
+        const cacheKey = index + firstValue;
+        const cachedValue = {stringArrayCallsWrapperName}.${dataIdentifier}[cacheKey];
 
-        if (ignoreCache || cachedValue === undefined) {
+        if (cachedValue === undefined) {
             if ({stringArrayCallsWrapperName}.${onceIdentifier} === undefined) {
                 {selfDefendingCode}
                 
@@ -37,7 +38,7 @@ export function StringArrayRC4DecodeTemplate (
             }
             
             value = {stringArrayCallsWrapperName}.${rc4Identifier}(value, key);
-            {stringArrayCallsWrapperName}.${dataIdentifier}[index] = value;
+            {stringArrayCallsWrapperName}.${dataIdentifier}[cacheKey] = value;
         } else {
             value = cachedValue;
         }

+ 0 - 3
src/custom-code-helpers/string-array/templates/string-array-rotate-function/StringArrayRotateFunctionTemplate.ts

@@ -4,14 +4,11 @@
 export function StringArrayRotateFunctionTemplate (): string {
     return `
         (function (array, comparisonValue) {
-            array[-1] = true;
-
             while (true) {
                 try {
                     const expression = {comparisonExpressionCode};
                                             
                     if (expression === comparisonValue) {
-                        array[-1] = false;
                         break;
                     } else {
                         array['push'](array['shift']());

+ 6 - 2
src/interfaces/analyzers/number-numerical-expression-analyzer/INumberNumericalExpressionAnalyzer.ts

@@ -2,10 +2,14 @@ import { TNumberNumericalExpressionData } from '../../../types/analyzers/number-
 
 import { IAnalyzer } from '../IAnalyzer';
 
-export interface INumberNumericalExpressionAnalyzer extends IAnalyzer<[number], TNumberNumericalExpressionData> {
+export interface INumberNumericalExpressionAnalyzer extends IAnalyzer<[number, number], TNumberNumericalExpressionData> {
     /**
      * @param {number} number
+     * @param {number} additionalPartsCount
      * @returns {TNumberNumericalExpressionData}
      */
-    analyze (number: number): TNumberNumericalExpressionData;
+    analyze (
+        number: number,
+        additionalPartsCount: number
+    ): TNumberNumericalExpressionData;
 }

+ 11 - 0
src/interfaces/analyzers/string-array-storage-analyzer/IStringArrayStorageAnalyzer.ts

@@ -9,6 +9,17 @@ export interface IStringArrayStorageAnalyzer extends IAnalyzer<[ESTree.Program],
      */
     analyze (astTree: ESTree.Program): void;
 
+    /**
+     * @param {Literal} literalNode
+     * @param {Node} parentNode
+     */
+    analyzeLiteralNode (literalNode: ESTree.Literal, parentNode: ESTree.Node): void;
+
+    /**
+     * @param {(SimpleLiteral & {value: string}) | (RegExpLiteral & {value: string})} literalNode
+     */
+    addItemDataForLiteralNode (literalNode: ESTree.Literal & {value: string}): void;
+
     /**
      * @param {Literal} literalNode
      * @returns {IStringArrayStorageItemData | undefined}

+ 5 - 1
src/node-transformers/converting-transformers/NumberToNumericalExpressionTransformer.ts

@@ -15,6 +15,7 @@ import { NodeTransformationStage } from '../../enums/node-transformers/NodeTrans
 import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
 import { NodeGuards } from '../../node/NodeGuards';
 import { NodeFactory } from '../../node/NodeFactory';
+import { NumberNumericalExpressionAnalyzer } from '../../analyzers/number-numerical-expression-analyzer/NumberNumericalExpressionAnalyzer';
 import { NumericalExpressionDataToNodeConverter } from '../../node/NumericalExpressionDataToNodeConverter';
 
 /**
@@ -85,7 +86,10 @@ export class NumberToNumericalExpressionTransformer extends AbstractNodeTransfor
             return literalNode;
         }
 
-        const numberNumericalExpressionData: TNumberNumericalExpressionData = this.numberNumericalExpressionAnalyzer.analyze(literalNode.value);
+        const numberNumericalExpressionData: TNumberNumericalExpressionData = this.numberNumericalExpressionAnalyzer.analyze(
+            literalNode.value,
+            NumberNumericalExpressionAnalyzer.defaultAdditionalPartsCount
+        );
 
         return NumericalExpressionDataToNodeConverter.convert(
             numberNumericalExpressionData,

+ 72 - 20
src/node-transformers/string-array-transformers/StringArrayRotateFunctionTransformer.ts

@@ -15,6 +15,7 @@ import { INumberNumericalExpressionAnalyzer } from '../../interfaces/analyzers/n
 import { IOptions } from '../../interfaces/options/IOptions';
 import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
 import { IStringArrayStorage } from '../../interfaces/storages/string-array-transformers/IStringArrayStorage';
+import { IStringArrayStorageAnalyzer } from '../../interfaces/analyzers/string-array-storage-analyzer/IStringArrayStorageAnalyzer';
 import { IVisitor } from '../../interfaces/node-transformers/IVisitor';
 
 import { CustomCodeHelper } from '../../enums/custom-code-helpers/CustomCodeHelper';
@@ -45,6 +46,11 @@ export class StringArrayRotateFunctionTransformer extends AbstractNodeTransforme
         NodeTransformer.ScopeIdentifiersTransformer
     ];
 
+    /**
+     * @type {number}
+     */
+    private static readonly comparisonExpressionAdditionalPartsCount: number = 7;
+
     /**
      * @type {INumberNumericalExpressionAnalyzer}
      */
@@ -55,6 +61,11 @@ export class StringArrayRotateFunctionTransformer extends AbstractNodeTransforme
      */
     private readonly stringArrayStorage: IStringArrayStorage;
 
+    /**
+     * @type {IStringArrayStorageAnalyzer}
+     */
+    private readonly stringArrayStorageAnalyzer: IStringArrayStorageAnalyzer;
+
     /**
      * @type {TCustomCodeHelperFactory}
      */
@@ -70,6 +81,7 @@ export class StringArrayRotateFunctionTransformer extends AbstractNodeTransforme
      * @param {IOptions} options
      * @param {INodeTransformersRunner} transformersRunner
      * @param {IStringArrayStorage} stringArrayStorage
+     * @param {IStringArrayStorageAnalyzer} stringArrayStorageAnalyzer
      * @param {TCustomCodeHelperFactory} customCodeHelperFactory
      * @param {INumberNumericalExpressionAnalyzer} numberNumericalExpressionAnalyzer
      */
@@ -78,6 +90,7 @@ export class StringArrayRotateFunctionTransformer extends AbstractNodeTransforme
         @inject(ServiceIdentifiers.IOptions) options: IOptions,
         @inject(ServiceIdentifiers.INodeTransformersRunner) transformersRunner: INodeTransformersRunner,
         @inject(ServiceIdentifiers.IStringArrayStorage) stringArrayStorage: IStringArrayStorage,
+        @inject(ServiceIdentifiers.IStringArrayStorageAnalyzer) stringArrayStorageAnalyzer: IStringArrayStorageAnalyzer,
         @inject(ServiceIdentifiers.Factory__ICustomCodeHelper) customCodeHelperFactory: TCustomCodeHelperFactory,
         @inject(ServiceIdentifiers.INumberNumericalExpressionAnalyzer)
             numberNumericalExpressionAnalyzer: INumberNumericalExpressionAnalyzer
@@ -85,11 +98,38 @@ export class StringArrayRotateFunctionTransformer extends AbstractNodeTransforme
         super(randomGenerator, options);
 
         this.stringArrayStorage = stringArrayStorage;
+        this.stringArrayStorageAnalyzer = stringArrayStorageAnalyzer;
         this.transformersRunner = transformersRunner;
         this.customCodeHelperFactory = customCodeHelperFactory;
         this.numberNumericalExpressionAnalyzer = numberNumericalExpressionAnalyzer;
     }
 
+    /**
+     * Because this transformer runs BEFORE string array analyzer we can't check string array storage length.
+     * So we have to traverse over program node and check if it has any string literal node.
+     *
+     * @param {Program} programNode
+     * @returns {boolean}
+     */
+    private static isProgramNodeHasStringLiterals (programNode: ESTree.Program): boolean {
+        let hasStringLiterals: boolean = false;
+
+        estraverse.traverse(programNode, {
+            enter: (node: ESTree.Node): estraverse.VisitorOption | void => {
+                if (
+                    NodeGuards.isLiteralNode(node)
+                    && NodeLiteralUtils.isStringLiteralNode(node)
+                ) {
+                    hasStringLiterals = true;
+
+                    return estraverse.VisitorOption.Break;
+                }
+            }
+        });
+
+        return hasStringLiterals;
+    }
+
     /**
      * @param {NodeTransformationStage} nodeTransformationStage
      * @returns {IVisitor | null}
@@ -102,12 +142,16 @@ export class StringArrayRotateFunctionTransformer extends AbstractNodeTransforme
         switch (nodeTransformationStage) {
             case NodeTransformationStage.StringArray:
                 return {
-                    enter: (node: ESTree.Node): ESTree.Node | undefined => {
-                        if (NodeGuards.isProgramNode(node)) {
-                            this.transformNode(node);
+                    enter: (node: ESTree.Node): ESTree.Node | estraverse.VisitorOption => {
+                        if (!NodeGuards.isProgramNode(node)) {
+                            return node;
+                        }
+
+                        if (!StringArrayRotateFunctionTransformer.isProgramNodeHasStringLiterals(node)) {
+                            return estraverse.VisitorOption.Break;
                         }
 
-                        return node;
+                        return this.transformNode(node);
                     }
                 };
 
@@ -149,17 +193,21 @@ export class StringArrayRotateFunctionTransformer extends AbstractNodeTransforme
         estraverse.traverse(wrappedStringArrayRotateFunctionNode, {
             enter: (node: ESTree.Node): void => {
                 if (
-                    NodeGuards.isLiteralNode(node)
-                    && NodeLiteralUtils.isStringLiteralNode(node)
-                    && !/\d/.test(node.value)
+                    !NodeGuards.isLiteralNode(node)
+                    || !NodeLiteralUtils.isStringLiteralNode(node)
                 ) {
+                   return;
+                }
+
+                if (/\d/.test(node.value)) {
+                    this.stringArrayStorageAnalyzer.addItemDataForLiteralNode(node);
+                } else {
                     NodeMetadata.set(node, {ignoredNode: true});
                 }
             }
         });
 
         NodeAppender.prepend(programNode, [stringArrayRotateFunctionNode]);
-        NodeUtils.parentizeNode(stringArrayRotateFunctionNode, programNode);
 
         return programNode;
     }
@@ -170,24 +218,28 @@ export class StringArrayRotateFunctionTransformer extends AbstractNodeTransforme
     private getStringArrayRotateFunctionNode (): TStatement {
         const comparisonValue: number = this.randomGenerator.getRandomInteger(100000, 1_000_000);
         const comparisonExpressionNumberNumericalExpressionData: TNumberNumericalExpressionData =
-            this.numberNumericalExpressionAnalyzer.analyze(comparisonValue);
+            this.numberNumericalExpressionAnalyzer.analyze(
+                comparisonValue,
+                StringArrayRotateFunctionTransformer.comparisonExpressionAdditionalPartsCount
+            );
 
         const comparisonExpressionNode: ESTree.Expression = NumericalExpressionDataToNodeConverter.convert(
             comparisonExpressionNumberNumericalExpressionData,
             ((number: number, isPositiveNumber) => {
-                const literalNode: ESTree.Literal = NodeFactory.literalNode(number.toString());
-
-                return NodeFactory.callExpressionNode(
+                const literalNode: ESTree.Literal = NodeFactory.literalNode(
+                    `${number}${this.randomGenerator.getRandomString(6)}`
+                );
+                const parseIntCallExpression: ESTree.CallExpression = NodeFactory.callExpressionNode(
                     NodeFactory.identifierNode('parseInt'),
-                    [
-                        isPositiveNumber
-                            ? literalNode
-                            : NodeFactory.unaryExpressionNode(
-                                '-',
-                                literalNode
-                            )
-                    ]
+                    [literalNode]
                 );
+
+                return isPositiveNumber
+                    ? parseIntCallExpression
+                    : NodeFactory.unaryExpressionNode(
+                        '-',
+                        parseIntCallExpression
+                    );
             })
         );
 

+ 1 - 1
src/options/Options.ts

@@ -299,7 +299,7 @@ export class Options implements IOptions {
      */
     @IsNumber()
     @ValidateIf((options: IOptions) => Boolean(options.splitStrings))
-    @Min(3)
+    @Min(1)
     public readonly splitStringsChunkLength!: number;
 
     /**

+ 5 - 5
test/functional-tests/custom-code-helpers/string-array/StringArrayRotateFunctionCodeHelper.spec.ts

@@ -10,7 +10,7 @@ import { JavaScriptObfuscator } from '../../../../src/JavaScriptObfuscatorFacade
 
 describe('StringArrayRotateFunctionCodeHelper', () => {
     describe('Base behaviour', () => {
-        const regExp: RegExp = /while *\(-- *_0x([a-f0-9]){4,6}\) *\{/;
+        const regExp: RegExp = /while *\(!!\[]\) *\{/;
 
         describe('`stringArray` option is set', () => {
             let obfuscatedCode: string;
@@ -58,8 +58,8 @@ describe('StringArrayRotateFunctionCodeHelper', () => {
     });
 
     describe('Preserve string array name', () => {
-        const rotateLogicRegExp: RegExp = /b\['push']\(b\['shift']\(\)\);/;
-        const incrementRegExp: RegExp = /f\(\+\+e\);/;
+        const arrayRotateRegExp: RegExp = /c\['push']\(c\['shift']\(\)\);/;
+        const comparisonRegExp: RegExp = /if *\(e *=== *d\) *{/;
 
         let obfuscatedCode: string;
 
@@ -79,11 +79,11 @@ describe('StringArrayRotateFunctionCodeHelper', () => {
         });
 
         it('should preserve string array name', () => {
-            assert.match(obfuscatedCode, rotateLogicRegExp);
+            assert.match(obfuscatedCode, arrayRotateRegExp);
         });
 
         it('generate valid identifier names', () => {
-            assert.match(obfuscatedCode, incrementRegExp);
+            assert.match(obfuscatedCode, comparisonRegExp);
         });
     });
 });

+ 6 - 6
test/functional-tests/custom-code-helpers/string-array/templates/string-array-rotate-function-template/StringArrayRotateFunctionTemplate.spec.ts

@@ -13,7 +13,7 @@ describe('StringArrayRotateFunctionTemplate', () => {
     describe('Prevailing kind of variables', () => {
         describe('`var` kind', () => {
             let obfuscatedCode: string,
-                stringArrayRotateFunctionRegExp: RegExp = /function\(_0x([a-f0-9]){4,6}, *_0x([a-f0-9]){4,6}\){var _0x([a-f0-9]){4,6} *= *function/;
+                stringArrayRotateFunctionTryCatchRegExp: RegExp = /try *{var *_0x([a-f0-9]){4,6}/;
 
             beforeEach(() => {
                 const code: string = readFileAsString(__dirname + '/fixtures/prevailing-kind-of-variables-var.js');
@@ -31,7 +31,7 @@ describe('StringArrayRotateFunctionTemplate', () => {
             });
 
             it('Should return correct kind of variables for string array rotate function', () => {
-                assert.match(obfuscatedCode, stringArrayRotateFunctionRegExp);
+                assert.match(obfuscatedCode, stringArrayRotateFunctionTryCatchRegExp);
             });
 
             it('Should does not break on obfuscating', () => {
@@ -41,7 +41,7 @@ describe('StringArrayRotateFunctionTemplate', () => {
 
         describe('`const` kind', () => {
             let obfuscatedCode: string,
-                stringArrayRotateFunctionRegExp: RegExp = /function\(_0x([a-f0-9]){4,6}, *_0x([a-f0-9]){4,6}\){const _0x([a-f0-9]){4,6} *= *function/;
+                stringArrayRotateFunctionTryCatchRegExp: RegExp = /try *{const *_0x([a-f0-9]){4,6}/;
 
             beforeEach(() => {
                 const code: string = readFileAsString(__dirname + '/fixtures/prevailing-kind-of-variables-const.js');
@@ -59,7 +59,7 @@ describe('StringArrayRotateFunctionTemplate', () => {
             });
 
             it('Should return correct kind of variables for string array rotate function', () => {
-                assert.match(obfuscatedCode, stringArrayRotateFunctionRegExp);
+                assert.match(obfuscatedCode, stringArrayRotateFunctionTryCatchRegExp);
             });
 
             it('Should does not break on obfuscating', () => {
@@ -69,7 +69,7 @@ describe('StringArrayRotateFunctionTemplate', () => {
 
         describe('`let` kind', () => {
             let obfuscatedCode: string,
-                stringArrayRotateFunctionRegExp: RegExp = /function\(_0x([a-f0-9]){4,6}, *_0x([a-f0-9]){4,6}\){const _0x([a-f0-9]){4,6} *= *function/;
+                stringArrayRotateFunctionTryCatchRegExp: RegExp = /try *{const *_0x([a-f0-9]){4,6}/;
 
             beforeEach(() => {
                 const code: string = readFileAsString(__dirname + '/fixtures/prevailing-kind-of-variables-let.js');
@@ -87,7 +87,7 @@ describe('StringArrayRotateFunctionTemplate', () => {
             });
 
             it('Should return correct kind of variables for string array rotate function', () => {
-                assert.match(obfuscatedCode, stringArrayRotateFunctionRegExp);
+                assert.match(obfuscatedCode, stringArrayRotateFunctionTryCatchRegExp);
             });
 
             it('Should does not break on obfuscating', () => {

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

@@ -259,18 +259,6 @@ describe('StringArrayTransformer', function () {
                 assert.match(obfuscatedCode, stringArrayIndexShiftRegExp);
             });
 
-            it('Match #1: should create string array call with shifted index', () => {
-                assert.equal(stringArrayIndexShiftIndexValue, stringArrayCallIndexValue1);
-            });
-
-            it('Match #2: should create string array call with shifted index', () => {
-                assert.equal(stringArrayIndexShiftIndexValue, stringArrayCallIndexValue2 - 1);
-            });
-
-            it('Match #3: should create string array call with shifted index', () => {
-                assert.equal(stringArrayIndexShiftIndexValue, stringArrayCallIndexValue3 - 2);
-            });
-
             it('should correctly evaluate code', () => {
                 assert.equal(evaluationResult, expectedEvaluationResult);
             });

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

@@ -15,17 +15,17 @@ describe('StringArrayStorage', () => {
             const delta: number = 0.1;
             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 stringArrayVariantRegExp: RegExp = /var _0x([a-f0-9]){4} *= *\[(?:'.*?', *)?'test'(?:, *'.*?')?];/g;
+            const literalNodeVariantRegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\(0x.\);/g;
 
-            let stringArrayVariant1Probability: number,
-                literalNodeVariant1Probability: number;
+            let stringArrayVariantProbability: number,
+                literalNodeVariantProbability: number;
 
             before(() => {
                 const code: string = readFileAsString(__dirname + '/fixtures/one-string.js');
 
-                let stringArrayVariant1MatchesLength: number = 0;
-                let literalNodeVariant1MatchesLength: number = 0;
+                let stringArrayVariantMatchesLength: number = 0;
+                let literalNodeVariantMatchesLength: number = 0;
 
                for (let i = 0; i < samples; i++) {
                    const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
@@ -38,51 +38,50 @@ describe('StringArrayStorage', () => {
                        }
                    ).getObfuscatedCode();
 
-                   if (obfuscatedCode.match(stringArrayVariant1RegExp1)) {
-                       stringArrayVariant1MatchesLength++;
+                   if (obfuscatedCode.match(stringArrayVariantRegExp)) {
+                       stringArrayVariantMatchesLength++;
                    }
 
-                   if (obfuscatedCode.match(literalNodeVariant1RegExp)) {
-                       literalNodeVariant1MatchesLength++;
+                   if (obfuscatedCode.match(literalNodeVariantRegExp)) {
+                       literalNodeVariantMatchesLength++;
                    }
                }
 
-                stringArrayVariant1Probability = stringArrayVariant1MatchesLength / samples;
-                literalNodeVariant1Probability = literalNodeVariant1MatchesLength / samples;
+                stringArrayVariantProbability = stringArrayVariantMatchesLength / samples;
+                literalNodeVariantProbability = literalNodeVariantMatchesLength / samples;
             });
 
             describe('String array probability', () => {
                 it('Variant #1: should create single string array variant', () => {
-                    assert.closeTo(stringArrayVariant1Probability, expectedVariantProbability, delta);
+                    assert.closeTo(stringArrayVariantProbability, expectedVariantProbability, delta);
                 });
             });
 
             describe('Literal node probability', () => {
                 it('Variant #1: should replace literal node with call to string array variant', () => {
-                    assert.closeTo(literalNodeVariant1Probability, expectedVariantProbability, delta);
+                    assert.closeTo(literalNodeVariantProbability, expectedVariantProbability, delta);
                 });
             });
         });
 
         describe('Variant #2: Three string array values', () => {
             const samples: number = 1000;
-            const delta: number = 0.1;
-            const expectedStringArrayVariantProbability: number = 0.33;
+            const delta: number = 0.05;
+            const expectedStringArrayVariantProbability: number = 0.07;
             const expectedLiteralNodeVariantProbability: number = 1;
 
-            const stringArrayVariantsCount: number = 3;
+            const stringArrayVariantsCount: number = 2;
             const literalNodeVariantsCount: number = 1;
 
             const stringArrayVariantRegExps: RegExp[] = [
-                /var _0x([a-f0-9]){4} *= *\['foo', *'bar', *'baz'];/g,
-                /var _0x([a-f0-9]){4} *= *\['bar', *'baz', *'foo'];/g,
-                /var _0x([a-f0-9]){4} *= *\['baz', *'foo', *'bar'];/g
+                /var _0x([a-f0-9]){4} *= *\['foo', *'bar', *'baz'(?:, *'.*?')+];/g,
+                /var _0x([a-f0-9]){4} *= *\[(?:'.*?', *)+'foo', *'bar', *'baz'];/g
             ];
             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}\\(0x.\\); *` +
+                    `var bar *= *_0x([a-f0-9]){4}\\(0x.\\); *` +
+                    `var baz *= *_0x([a-f0-9]){4}\\(0x.\\);`
                 )
             ];
 

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

@@ -4,6 +4,8 @@ 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';
 import { readFileAsString } from '../helpers/readFileAsString';
@@ -18,17 +20,19 @@ const getEnvironmentCode = () => `
 
 describe('JavaScriptObfuscator runtime eval', function () {
     const baseOptions: TInputOptions = {
-        compact: false,
+        controlFlowFlattening: true,
+        controlFlowFlatteningThreshold: 1,
         deadCodeInjection: true,
         deadCodeInjectionThreshold: 1,
-        // debugProtection: true,
-        disableConsoleOutput: false,
+        debugProtection: true,
+        disableConsoleOutput: true,
         domainLock: ['obfuscator.io'],
         numbersToExpressions: true,
         simplify: true,
+        renameProperties: true,
         reservedNames: ['generate', 'sha256'],
-        rotateStringArray: false,
-        // selfDefending: true,
+        rotateStringArray: true,
+        selfDefending: true,
         splitStrings: true,
         splitStringsChunkLength: 3,
         stringArray: true,
@@ -37,9 +41,17 @@ describe('JavaScriptObfuscator runtime eval', function () {
             StringArrayEncoding.Base64,
             StringArrayEncoding.Rc4
         ],
+        stringArrayIndexesType: [
+            StringArrayIndexesType.HexadecimalNumber,
+            StringArrayIndexesType.HexadecimalNumericString
+        ],
+        stringArrayIndexShift: true,
         stringArrayWrappersChainedCalls: true,
         stringArrayWrappersCount: 5,
+        stringArrayWrappersParametersMaxCount: 5,
+        stringArrayWrappersType: StringArrayWrappersType.Function,
         stringArrayThreshold: 1,
+        transformObjectKeys: true,
         unicodeEscapeSequence: true
     };
 

+ 37 - 9
test/unit-tests/analyzers/number-numerical-expression-analyzer/NumberNumericalExpressionAnalyzer.spec.ts

@@ -10,6 +10,7 @@ import { IInversifyContainerFacade } from '../../../../src/interfaces/container/
 import { INumberNumericalExpressionAnalyzer } from '../../../../src/interfaces/analyzers/number-numerical-expression-analyzer/INumberNumericalExpressionAnalyzer';
 
 import { InversifyContainerFacade } from '../../../../src/container/InversifyContainerFacade';
+import { NumberNumericalExpressionAnalyzer } from '../../../../src/analyzers/number-numerical-expression-analyzer/NumberNumericalExpressionAnalyzer';
 
 /**
  * @param {TNumberNumericalExpressionData} data
@@ -43,7 +44,10 @@ describe('NumberNumericalExpressionAnalyzer', function() {
 
                 before(() => {
                     const numberNumericalExpressionData: TNumberNumericalExpressionData =
-                        numberNumericalExpressionAnalyzer.analyze(number);
+                        numberNumericalExpressionAnalyzer.analyze(
+                            number,
+                            NumberNumericalExpressionAnalyzer.defaultAdditionalPartsCount
+                        );
 
                     evaluatedResult = eval(numberNumericalExpressionDataToString(numberNumericalExpressionData));
                 });
@@ -58,7 +62,10 @@ describe('NumberNumericalExpressionAnalyzer', function() {
 
                 before(() => {
                     const numberNumericalExpressionData: TNumberNumericalExpressionData =
-                        numberNumericalExpressionAnalyzer.analyze(number);
+                        numberNumericalExpressionAnalyzer.analyze(
+                            number,
+                            NumberNumericalExpressionAnalyzer.defaultAdditionalPartsCount
+                        );
 
                     evaluatedResult = eval(numberNumericalExpressionDataToString(numberNumericalExpressionData));
                 });
@@ -73,7 +80,10 @@ describe('NumberNumericalExpressionAnalyzer', function() {
 
                 before(() => {
                     const numberNumericalExpressionData: TNumberNumericalExpressionData =
-                        numberNumericalExpressionAnalyzer.analyze(number);
+                        numberNumericalExpressionAnalyzer.analyze(
+                            number,
+                            NumberNumericalExpressionAnalyzer.defaultAdditionalPartsCount
+                        );
 
                     evaluatedResult = eval(numberNumericalExpressionDataToString(numberNumericalExpressionData));
                 });
@@ -88,7 +98,10 @@ describe('NumberNumericalExpressionAnalyzer', function() {
 
                 before(() => {
                     const numberNumericalExpressionData: TNumberNumericalExpressionData =
-                        numberNumericalExpressionAnalyzer.analyze(number);
+                        numberNumericalExpressionAnalyzer.analyze(
+                            number,
+                            NumberNumericalExpressionAnalyzer.defaultAdditionalPartsCount
+                        );
 
                     evaluatedResult = eval(numberNumericalExpressionDataToString(numberNumericalExpressionData));
                 });
@@ -105,7 +118,10 @@ describe('NumberNumericalExpressionAnalyzer', function() {
 
                 before(() => {
                     const numberNumericalExpressionData: TNumberNumericalExpressionData =
-                        numberNumericalExpressionAnalyzer.analyze(number);
+                        numberNumericalExpressionAnalyzer.analyze(
+                            number,
+                            NumberNumericalExpressionAnalyzer.defaultAdditionalPartsCount
+                        );
 
                     evaluatedResult = eval(numberNumericalExpressionDataToString(numberNumericalExpressionData));
                 });
@@ -120,7 +136,10 @@ describe('NumberNumericalExpressionAnalyzer', function() {
 
                 before(() => {
                     const numberNumericalExpressionData: TNumberNumericalExpressionData =
-                        numberNumericalExpressionAnalyzer.analyze(number);
+                        numberNumericalExpressionAnalyzer.analyze(
+                            number,
+                            NumberNumericalExpressionAnalyzer.defaultAdditionalPartsCount
+                        );
 
                     evaluatedResult = eval(numberNumericalExpressionDataToString(numberNumericalExpressionData));
                 });
@@ -135,7 +154,10 @@ describe('NumberNumericalExpressionAnalyzer', function() {
 
                 before(() => {
                     const numberNumericalExpressionData: TNumberNumericalExpressionData =
-                        numberNumericalExpressionAnalyzer.analyze(number);
+                        numberNumericalExpressionAnalyzer.analyze(
+                            number,
+                            NumberNumericalExpressionAnalyzer.defaultAdditionalPartsCount
+                        );
 
                     evaluatedResult = eval(numberNumericalExpressionDataToString(numberNumericalExpressionData));
                 });
@@ -150,7 +172,10 @@ describe('NumberNumericalExpressionAnalyzer', function() {
 
                 before(() => {
                     const numberNumericalExpressionData: TNumberNumericalExpressionData =
-                        numberNumericalExpressionAnalyzer.analyze(number);
+                        numberNumericalExpressionAnalyzer.analyze(
+                            number,
+                            NumberNumericalExpressionAnalyzer.defaultAdditionalPartsCount
+                        );
 
                     evaluatedResult = eval(numberNumericalExpressionDataToString(numberNumericalExpressionData));
                 });
@@ -167,7 +192,10 @@ describe('NumberNumericalExpressionAnalyzer', function() {
             let testFunc: () => void;
 
             before(() => {
-                testFunc = () => numberNumericalExpressionAnalyzer.analyze(number);
+                testFunc = () => numberNumericalExpressionAnalyzer.analyze(
+                    number,
+                    NumberNumericalExpressionAnalyzer.defaultAdditionalPartsCount
+                );
             });
 
             it('should throw error', () => {

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio