浏览代码

String array calls transform fix (#1050)

* Fixed the wrong generation of code that has statements after `ReturnStatment` when `simplify` option is enabled

* Fixed generation of reserved identifier names like `Map` or `Set` for `mangled` and `mangled-shuffled` identifier names generators
Timofey Kachalov 3 年之前
父节点
当前提交
ec4b70f908

+ 5 - 0
CHANGELOG.md

@@ -1,5 +1,10 @@
 Change Log
 
+v3.2.3
+---
+* Fixed missing transformation of string array calls in some cases
+* Fixed generation of reserved identifier names like `Map` or `Set` for `mangled` and `mangled-shuffled` identifier names generators
+
 v3.2.2
 ---
 * Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1039

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "javascript-obfuscator",
-  "version": "3.2.2",
+  "version": "3.2.3",
   "description": "JavaScript obfuscator",
   "keywords": [
     "obfuscator",

+ 0 - 0
src/node-transformers/rename-properties-transformers/replacer/ReservedDomProperties.json → src/constants/ReservedDomProperties.json


+ 11 - 0
src/constants/ReservedIdentifierNames.ts

@@ -0,0 +1,11 @@
+export const reservedIdentifierNames = [
+    // reserved identifiers
+    'byte', 'case', 'char', 'do', 'else', 'enum', 'eval', 'for', 'goto',
+    'if', 'in', 'int', 'let', 'long', 'new', 'null', 'this', 'true', 'try',
+    'var', 'void', 'with',
+
+    // reserved global object identifiers
+    'Array', 'Attr', 'Audio', 'Blob', 'Cache', 'Date', 'Error', 'Event',
+    'Feed', 'File', 'Hz', 'Image', 'Intl', 'Lock', 'Map', 'Math', 'Node',
+    'Proxy', 'Range', 'Rect', 'Set', 'Table', 'Text', 'Touch'
+];

+ 5 - 4
src/generators/identifier-names-generators/AbstractIdentifierNamesGenerator.ts

@@ -79,7 +79,8 @@ export abstract class AbstractIdentifierNamesGenerator implements IIdentifierNam
      * @returns {boolean}
      */
     public isValidIdentifierName (name: string): boolean {
-        return this.notReservedName(name) && !this.preservedNamesSet.has(name);
+        return !this.isReservedName(name)
+            && !this.preservedNamesSet.has(name);
     }
 
     /**
@@ -112,12 +113,12 @@ export abstract class AbstractIdentifierNamesGenerator implements IIdentifierNam
      * @param {string} name
      * @returns {boolean}
      */
-    private notReservedName (name: string): boolean {
+    private isReservedName (name: string): boolean {
         return this.options.reservedNames.length
-            ? !this.options.reservedNames.some((reservedName: string) =>
+            ? this.options.reservedNames.some((reservedName: string) =>
                 new RegExp(reservedName, 'g').exec(name) !== null
             )
-            : true;
+            : false;
 
     }
 

+ 4 - 6
src/generators/identifier-names-generators/MangledIdentifierNamesGenerator.ts

@@ -7,9 +7,10 @@ import { IOptions } from '../../interfaces/options/IOptions';
 import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
 import { ISetUtils } from '../../interfaces/utils/ISetUtils';
 
-import { numbersString } from '../../constants/NumbersString';
 import { alphabetString } from '../../constants/AlphabetString';
 import { alphabetStringUppercase } from '../../constants/AlphabetStringUppercase';
+import { numbersString } from '../../constants/NumbersString';
+import { reservedIdentifierNames } from '../../constants/ReservedIdentifierNames';
 
 import { AbstractIdentifierNamesGenerator } from './AbstractIdentifierNamesGenerator';
 import { NodeLexicalScopeUtils } from '../../node/NodeLexicalScopeUtils';
@@ -40,14 +41,11 @@ export class MangledIdentifierNamesGenerator extends AbstractIdentifierNamesGene
 
     /**
      * Reserved JS words with length of 2-4 symbols that can be possible generated with this replacer
+     * + reserved DOM names like `Set`, `Map`, `Date`, etc
      *
      * @type {Set<string>}
      */
-    private static readonly reservedNamesSet: Set<string> = new Set([
-        'byte', 'case', 'char', 'do', 'else', 'enum', 'eval', 'for', 'goto',
-        'if', 'in', 'int', 'let', 'long', 'new', 'null', 'this', 'true', 'try',
-        'var', 'void', 'with'
-    ]);
+    private static readonly reservedNamesSet: Set<string> = new Set(reservedIdentifierNames);
 
     /**
      * @type {WeakMap<string, string>}

+ 10 - 2
src/node-transformers/control-flow-transformers/StringArrayControlFlowTransformer.ts

@@ -11,6 +11,7 @@ import {
 } from '../../types/container/node-transformers/TControlFlowStorageFactoryCreator';
 import { TNodeWithStatements } from '../../types/node/TNodeWithStatements';
 
+import { IControlFlowStorage } from '../../interfaces/storages/control-flow-transformers/IControlFlowStorage';
 import { IOptions } from '../../interfaces/options/IOptions';
 import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
 import { IVisitor } from '../../interfaces/node-transformers/IVisitor';
@@ -23,7 +24,6 @@ import { NodeTransformer } from '../../enums/node-transformers/NodeTransformer';
 
 import { FunctionControlFlowTransformer } from './FunctionControlFlowTransformer';
 import { NodeGuards } from '../../node/NodeGuards';
-import { IControlFlowStorage } from '../../interfaces/storages/control-flow-transformers/IControlFlowStorage';
 
 @injectable()
 export class StringArrayControlFlowTransformer extends FunctionControlFlowTransformer {
@@ -120,12 +120,20 @@ export class StringArrayControlFlowTransformer extends FunctionControlFlowTransf
             && this.controlFlowStorageNodes.has(node);
 
         if (isControlFlowStorageNode) {
-            return estraverse.VisitorOption.Break;
+            return estraverse.VisitorOption.Skip;
         }
 
         return super.transformFunctionBodyNode(node, parentNode, functionNode, controlFlowStorage);
     }
 
+    /**
+     * @param {TNodeWithStatements} hostNode
+     * @returns {TControlFlowStorage}
+     */
+    protected override getControlFlowStorage (hostNode: TNodeWithStatements): IControlFlowStorage {
+        return this.controlFlowStorageFactory();
+    }
+
     /**
      * @param {TNodeWithStatements} hostNode
      * @param {VariableDeclaration} controlFlowStorageNode

+ 1 - 1
src/node-transformers/rename-properties-transformers/replacer/RenamePropertiesReplacer.ts

@@ -12,7 +12,7 @@ import { IPropertyIdentifierNamesCacheStorage } from '../../../interfaces/storag
 import { IRenamePropertiesReplacer } from '../../../interfaces/node-transformers/rename-properties-transformers/replacer/IRenamePropertiesReplacer';
 
 // eslint-disable-next-line import/no-internal-modules
-import ReservedDomProperties from './ReservedDomProperties.json';
+import ReservedDomProperties from '../../../constants/ReservedDomProperties.json';
 
 import { NodeGuards } from '../../../node/NodeGuards';
 import { NodeFactory } from '../../../node/NodeFactory';

+ 39 - 10
test/dev/dev.ts

@@ -1,26 +1,55 @@
 'use strict';
 
+import { StringArrayWrappersType } from '../../src/enums/node-transformers/string-array-transformers/StringArrayWrappersType';
+
 (function () {
     const JavaScriptObfuscator: any = require('../../index');
 
     let obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
         `
-            async function xyzzy(a,b)
-            {
-                if (a) {
-                    return await foo(a) ;
-                    console.log(a) ;
-                } else {
-                    return await bar(b) ;
-                    console.log(b) ;
+            function foo () {
+                function bar() {
+                    var string1 = 'string1';
+                    var string2 = 'string2';
+                    var string3 = 'string3';
+                    var string4 = 'string4';
+                    var string5 = 'string5';
+                    var string6 = 'string6';
+                    
+                    function bark () {
+                        var string1 = 'string1';
+                        var string2 = 'string2';
+                        var string3 = 'string3';
+                        var string4 = 'string4';
+                        var string5 = 'string5';
+                        var string6 = 'string6';
+                    }
                 }
+                
+                bar()
             }
+            
+            console.log(foo());
         `,
         {
             identifierNamesGenerator: 'mangled',
             compact: false,
-            simplify: true,
-            stringArray: false
+            controlFlowFlattening: false,
+            controlFlowFlatteningThreshold: 1,
+            simplify: false,
+            stringArrayRotate: false,
+            stringArray: true,
+            stringArrayIndexesType: [
+                'hexadecimal-number',
+                'hexadecimal-numeric-string'
+            ],
+            stringArrayThreshold: 1,
+            stringArrayCallsTransform: true,
+            stringArrayCallsTransformThreshold: 1,
+            rotateStringArray: true,
+            stringArrayWrappersType: StringArrayWrappersType.Function,
+            transformObjectKeys: false,
+            seed: 1
         }
     ).getObfuscatedCode();
 

+ 38 - 1
test/functional-tests/node-transformers/control-flow-transformers/string-array-control-flow-transformer/StringArrayControlFlowTransformer.spec.ts

@@ -191,6 +191,43 @@ describe('StringArrayControlFlowTransformer', function () {
                         assert.match(obfuscatedCode, regexp);
                     });
                 });
+
+                describe('Variant #5 - multiple `control flow storages` on the same block scope', () => {
+                    const regexp: RegExp = new RegExp(
+                        `var ${hexadecimalVariableMatch} *= *\\{` +
+                            `${hexadecimalVariableMatch} *: *0x0, *` +
+                            `${hexadecimalVariableMatch} *: *0x1 *` +
+                        `\\}; *` +
+                        `var ${hexadecimalVariableMatch} *= *\\{` +
+
+                            `${hexadecimalVariableMatch} *: *0x2, *` +
+                            `${hexadecimalVariableMatch} *: *0x3 *` +
+                        `\\};`
+                    );
+
+                    let obfuscatedCode: string;
+
+                    before(() => {
+                        const code: string = readFileAsString(__dirname + '/fixtures/multiple-storages-1.js');
+
+                        obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                            code,
+                            {
+                                ...NO_ADDITIONAL_NODES_PRESET,
+                                stringArray: true,
+                                stringArrayThreshold: 1,
+                                stringArrayCallsTransform: true,
+                                stringArrayCallsTransformThreshold: 1
+                            }
+                        ).getObfuscatedCode();
+
+                        console.log(obfuscatedCode);
+                    });
+
+                    it('should add `control flow storage` node with multiple items to the obfuscated code', () => {
+                        assert.match(obfuscatedCode, regexp);
+                    });
+                });
             });
 
             describe('Variant #2 - negative cases', function () {
@@ -320,7 +357,7 @@ describe('StringArrayControlFlowTransformer', function () {
                 let obfuscatedCode: string;
 
                 before(() => {
-                    const code: string = readFileAsString(__dirname + '/fixtures/multiple-storages.js');
+                    const code: string = readFileAsString(__dirname + '/fixtures/multiple-storages-2.js');
 
                     obfuscatedCode = JavaScriptObfuscator.obfuscate(
                         code,

+ 7 - 0
test/functional-tests/node-transformers/control-flow-transformers/string-array-control-flow-transformer/fixtures/multiple-storages-1.js

@@ -0,0 +1,7 @@
+(function () {
+    var variable1 = 'foo' + 'bar';
+
+    function foo (arg) {
+        var variable2 = 'baz' + 'bark';
+    }
+})();

+ 0 - 0
test/functional-tests/node-transformers/control-flow-transformers/string-array-control-flow-transformer/fixtures/multiple-storages.js → test/functional-tests/node-transformers/control-flow-transformers/string-array-control-flow-transformer/fixtures/multiple-storages-2.js


+ 29 - 0
test/unit-tests/generators/identifier-names-generators/MangledShuffledlIdentifierNamesGenerator.spec.ts

@@ -186,4 +186,33 @@ describe('MangledShuffledIdentifierNamesGenerator', () => {
             assert.isTrue(isSuccessComparison);
         });
     });
+
+    describe('isValidIdentifierName', () => {
+        describe('Variant #1: reserved dom property name', () => {
+            let identifierNamesGenerator: IIdentifierNamesGenerator,
+                isValidName1: boolean,
+                isValidName2: boolean,
+                isValidName3: boolean;
+
+            beforeEach(() => {
+                const inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade();
+
+                inversifyContainerFacade.load('', '', {} );
+                identifierNamesGenerator = inversifyContainerFacade.getNamed<IIdentifierNamesGenerator>(
+                    ServiceIdentifiers.IIdentifierNamesGenerator,
+                    IdentifierNamesGenerator.MangledShuffledIdentifierNamesGenerator
+                );
+
+                isValidName1 = identifierNamesGenerator.isValidIdentifierName('Set');
+                isValidName2 = identifierNamesGenerator.isValidIdentifierName('Array');
+                isValidName3 = identifierNamesGenerator.isValidIdentifierName('WeakSet');
+            });
+
+            it('should generate first identifier', () => {
+                assert.isFalse(isValidName1);
+                assert.isFalse(isValidName2);
+                assert.isTrue(isValidName3);
+            });
+        });
+    });
 });

+ 27 - 0
test/unit-tests/generators/identifier-names-generators/MangledlIdentifierNamesGenerator.spec.ts

@@ -312,5 +312,32 @@ describe('MangledIdentifierNamesGenerator', () => {
                 assert.equal(secondMangledIdentifierName, expectedSecondIdentifier);
             });
         });
+
+        describe('Variant #3: reserved dom property name', () => {
+            let identifierNamesGenerator: IIdentifierNamesGenerator,
+                isValidName1: boolean,
+                isValidName2: boolean,
+                isValidName3: boolean;
+
+            beforeEach(() => {
+                const inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade();
+
+                inversifyContainerFacade.load('', '', {} );
+                identifierNamesGenerator = inversifyContainerFacade.getNamed<IIdentifierNamesGenerator>(
+                    ServiceIdentifiers.IIdentifierNamesGenerator,
+                    IdentifierNamesGenerator.MangledIdentifierNamesGenerator
+                );
+
+                isValidName1 = identifierNamesGenerator.isValidIdentifierName('Set');
+                isValidName2 = identifierNamesGenerator.isValidIdentifierName('Array');
+                isValidName3 = identifierNamesGenerator.isValidIdentifierName('WeakSet');
+            });
+
+            it('should generate first identifier', () => {
+                assert.isFalse(isValidName1);
+                assert.isFalse(isValidName2);
+                assert.isTrue(isValidName3);
+            });
+        });
     });
 });