Explorar el Código

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

Timofey Kachalov hace 3 años
padre
commit
77f64bf5df
Se han modificado 17 ficheros con 311 adiciones y 49 borrados
  1. 4 0
      CHANGELOG.md
  2. 2 2
      package.json
  3. 0 4
      src/declarations/ESTree.d.ts
  4. 5 0
      src/interfaces/node-transformers/simplifying-transformers/IIteratedStatementsSimplifyData.ts
  5. 15 2
      src/node-transformers/simplifying-transformers/AbstractStatementSimplifyTransformer.ts
  6. 2 4
      src/node/NodeGuards.ts
  7. 10 27
      test/dev/dev.ts
  8. 3 1
      test/functional-tests/custom-code-helpers/string-array/group/StringArrayCodeHelperGroup.spec.ts
  9. 8 8
      test/functional-tests/node-transformers/preparing-transformers/obfuscating-guards/conditional-comment-obfuscating-guard/ConditionalCommentObfuscatingGuard.spec.ts
  10. 175 0
      test/functional-tests/node-transformers/simplifying-transformers/if-statement-simplify-transformer/IfStatementSimplifyTransformer.spec.ts
  11. 15 0
      test/functional-tests/node-transformers/simplifying-transformers/if-statement-simplify-transformer/fixtures/full-consequent-and-alternate-alternate-statements-after-return.js
  12. 15 0
      test/functional-tests/node-transformers/simplifying-transformers/if-statement-simplify-transformer/fixtures/full-consequent-and-alternate-consequent-statements-after-return.js
  13. 11 0
      test/functional-tests/node-transformers/simplifying-transformers/if-statement-simplify-transformer/fixtures/full-consequent-only-statements-after-return.js
  14. 15 0
      test/functional-tests/node-transformers/simplifying-transformers/if-statement-simplify-transformer/fixtures/partial-consequent-and-alternate-alternate-statements-after-return.js
  15. 15 0
      test/functional-tests/node-transformers/simplifying-transformers/if-statement-simplify-transformer/fixtures/partial-consequent-and-alternate-consequent-statements-after-return.js
  16. 10 0
      test/functional-tests/node-transformers/simplifying-transformers/if-statement-simplify-transformer/fixtures/partial-consequent-only-statements-after-return.js
  17. 6 1
      yarn.lock

+ 4 - 0
CHANGELOG.md

@@ -1,5 +1,9 @@
 Change Log
 
+v3.2.2
+---
+* Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1039
+
 v3.2.1
 ---
 * Updated copyright

+ 2 - 2
package.json

@@ -1,6 +1,6 @@
 {
   "name": "javascript-obfuscator",
-  "version": "3.2.1",
+  "version": "3.2.2",
   "description": "JavaScript obfuscator",
   "keywords": [
     "obfuscator",
@@ -53,7 +53,7 @@
     "@types/eslint-scope": "3.7.3",
     "@types/eslint-visitor-keys": "1.0.0",
     "@types/estraverse": "5.1.1",
-    "@types/estree": "0.0.50",
+    "@types/estree": "0.0.51",
     "@types/js-beautify": "1.13.3",
     "@types/js-string-escape": "1.0.1",
     "@types/md5": "2.3.1",

+ 0 - 4
src/declarations/ESTree.d.ts

@@ -54,8 +54,4 @@ declare module 'estree' {
         metadata?: LiteralNodeMetadata;
         'x-verbatim-property'?: escodegen.XVerbatimProperty;
     }
-
-    interface StaticBlock extends Omit<BlockStatement, 'type'> {
-        type: 'StaticBlock'
-    }
 }

+ 5 - 0
src/interfaces/node-transformers/simplifying-transformers/IIteratedStatementsSimplifyData.ts

@@ -15,4 +15,9 @@ export interface IIteratedStatementsSimplifyData {
      * @type {boolean}
      */
     hasReturnStatement: boolean;
+
+    /**
+     * @type {boolean}
+     */
+    hasStatementsAfterReturnStatement: boolean;
 }

+ 15 - 2
src/node-transformers/simplifying-transformers/AbstractStatementSimplifyTransformer.ts

@@ -63,9 +63,19 @@ export abstract class AbstractStatementSimplifyTransformer extends AbstractNodeT
         const {
             startIndex,
             unwrappedExpressions,
-            hasReturnStatement
+            hasReturnStatement,
+            hasStatementsAfterReturnStatement
         } = this.collectIteratedStatementsSimplifyData(statementNode);
 
+        if (hasStatementsAfterReturnStatement) {
+            return {
+                leadingStatements: statementNode.body,
+                trailingStatement: null,
+                hasReturnStatement: false,
+                hasSingleExpression: false
+            };
+        }
+
         const leadingStatements: ESTree.Statement[] = this.getLeadingStatements(statementNode, startIndex);
 
         if (!unwrappedExpressions.length) {
@@ -111,6 +121,7 @@ export abstract class AbstractStatementSimplifyTransformer extends AbstractNodeT
         const unwrappedExpressions: ESTree.Expression[] = [];
 
         let hasReturnStatement: boolean = false;
+        let hasStatementsAfterReturnStatement: boolean = false;
         let startIndex: number | null = null;
 
         for (let i = statementNodeBodyLength - 1; i >= 0; i--) {
@@ -133,6 +144,7 @@ export abstract class AbstractStatementSimplifyTransformer extends AbstractNodeT
             ) {
                 unwrappedExpressions.unshift(statementBodyStatementNode.argument);
                 hasReturnStatement = true;
+                hasStatementsAfterReturnStatement = i !== statementNodeBodyLength - 1;
                 startIndex = i;
                 continue;
             }
@@ -143,7 +155,8 @@ export abstract class AbstractStatementSimplifyTransformer extends AbstractNodeT
         return {
             startIndex,
             unwrappedExpressions,
-            hasReturnStatement
+            hasReturnStatement,
+            hasStatementsAfterReturnStatement
         };
     }
 

+ 2 - 4
src/node/NodeGuards.ts

@@ -507,10 +507,8 @@ export class NodeGuards {
      * @param {Node} node
      * @returns {boolean}
      */
-    // TODO: add type guard after @types/estree update
-    public static isStaticBlockNode (node: ESTree.Node): boolean {
-        // TODO: Update @types/estree
-        return (<any>node).type === NodeType.StaticBlock;
+    public static isStaticBlockNode (node: ESTree.Node): node is ESTree.StaticBlock {
+        return node.type === NodeType.StaticBlock;
     }
 
     /**

+ 10 - 27
test/dev/dev.ts

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

+ 3 - 1
test/functional-tests/custom-code-helpers/string-array/group/StringArrayCodeHelperGroup.spec.ts

@@ -20,7 +20,9 @@ describe('StringArrayCodeHelperGroup', () => {
         `function *(\\w) *\\(\\w, *\\w\\) *{.*return \\w;}.*`
     );
 
-    describe('StringArrayCallsWrapper code helper names', () => {
+    describe('StringArrayCallsWrapper code helper names', function () {
+        this.timeout(10000);
+
         const stringArrayCallsWrapperNames: Set<string> = new Set();
         const samplesCount: number = 30;
         let obfuscatedCode: string;

+ 8 - 8
test/functional-tests/node-transformers/preparing-transformers/obfuscating-guards/conditional-comment-obfuscating-guard/ConditionalCommentObfuscatingGuard.spec.ts

@@ -10,9 +10,9 @@ describe('ConditionalCommentObfuscatingGuard', () => {
     describe('check', () => {
         describe('Variant #1: `disable` conditional comment', () => {
             const disableConditionalCommentRegExp: RegExp = /\/\/ *javascript-obfuscator:disable/;
-            const obfuscatedVariableDeclarationRegExp: RegExp = /var _0x([a-f0-9]){5,6} *= *0x1;/;
+            const obfuscatedVariableDeclarationRegExp: RegExp = /var _0x([a-f0-9]){4,6} *= *0x1;/;
             const ignoredVariableDeclarationRegExp: RegExp = /var bar *= *2;/;
-            const consoleLogRegExp: RegExp = /console.log\(_0x([a-f0-9]){5,6}\);/;
+            const consoleLogRegExp: RegExp = /console.log\(_0x([a-f0-9]){4,6}\);/;
 
             let obfuscatedCode: string;
 
@@ -47,8 +47,8 @@ describe('ConditionalCommentObfuscatingGuard', () => {
         describe('Variant #2: `disable` and `enable` conditional comments #1', () => {
             const disableConditionalCommentRegExp: RegExp = /\/\/ *javascript-obfuscator:disable/;
             const enableConditionalCommentRegExp: RegExp = /\/\/ *javascript-obfuscator:enable/;
-            const obfuscatedVariableDeclaration1RegExp: RegExp = /var _0x([a-f0-9]){5,6} *= *0x1;/;
-            const obfuscatedVariableDeclaration2RegExp: RegExp = /var _0x([a-f0-9]){5,6} *= *0x3;/;
+            const obfuscatedVariableDeclaration1RegExp: RegExp = /var _0x([a-f0-9]){4,6} *= *0x1;/;
+            const obfuscatedVariableDeclaration2RegExp: RegExp = /var _0x([a-f0-9]){4,6} *= *0x3;/;
             const ignoredVariableDeclarationRegExp: RegExp = /var bar *= *2;/;
 
             let obfuscatedCode: string;
@@ -87,7 +87,7 @@ describe('ConditionalCommentObfuscatingGuard', () => {
 
         describe('Variant #3: `disable` and `enable` conditional comments #2', () => {
             const ignoredVariableDeclarationRegExp: RegExp = /var foo *= *1;/;
-            const obfuscatedVariableDeclarationRegExp: RegExp = /var _0x([a-f0-9]){5,6} *= *0x2;/;
+            const obfuscatedVariableDeclarationRegExp: RegExp = /var _0x([a-f0-9]){4,6} *= *0x2;/;
 
             let obfuscatedCode: string;
 
@@ -139,7 +139,7 @@ describe('ConditionalCommentObfuscatingGuard', () => {
         });
 
         describe('Variant #5: `disable` and `enable` conditional comments with dead code injection', () => {
-            const obfuscatedFunctionExpressionRegExp: RegExp = /var _0x([a-f0-9]){5,6} *= *function *\(_0x([a-f0-9]){5,6}, *_0x([a-f0-9]){5,6}, *_0x([a-f0-9]){5,6}\) *{/g;
+            const obfuscatedFunctionExpressionRegExp: RegExp = /var _0x([a-f0-9]){4,6} *= *function *\(_0x([a-f0-9]){4,6}, *_0x([a-f0-9]){4,6}, *_0x([a-f0-9]){4,6}\) *{/g;
             const expectedObfuscatedFunctionExpressionLength: number = 3;
 
             const ignoredFunctionExpression1RegExp: RegExp = /var bar *= *function *\(a, *b, *c\) *{/;
@@ -166,7 +166,7 @@ describe('ConditionalCommentObfuscatingGuard', () => {
                         deadCodeInjectionThreshold: 1
                     }
                 ).getObfuscatedCode();
-                
+
                 const obfuscatedFunctionExpressionMatches: RegExpMatchArray | null = obfuscatedCode.match(
                     obfuscatedFunctionExpressionRegExp
                 );
@@ -209,7 +209,7 @@ describe('ConditionalCommentObfuscatingGuard', () => {
         });
 
         describe('Variant #6: `disable` and `enable` conditional comments with control flow flattening', () => {
-            const obfuscatedVariableDeclarationRegExp: RegExp = /var _0x([a-f0-9]){5,6} *= *_0x([a-f0-9]){5,6}\['\w{5}'];/;
+            const obfuscatedVariableDeclarationRegExp: RegExp = /var _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\['\w{5}'];/;
             const ignoredVariableDeclarationRegExp: RegExp = /var bar *= *'bar';/;
 
             let obfuscatedCode: string;

+ 175 - 0
test/functional-tests/node-transformers/simplifying-transformers/if-statement-simplify-transformer/IfStatementSimplifyTransformer.spec.ts

@@ -113,6 +113,33 @@ describe('IfStatementSimplifyTransformer', () => {
                         assert.match(obfuscatedCode, regExp);
                     });
                 });
+
+                describe('Variant #3: statements after return', () => {
+                    const regExp: RegExp = new RegExp(
+                        'if *\\(!!\\[]\\) *\\{ *' +
+                            'bar\\(\\), *baz\\(\\); *return bark\\(\\); *hawk\\(\\), *eagle\\(\\);' +
+                        '}'
+                    );
+
+
+                    let obfuscatedCode: string;
+
+                    before(() => {
+                        const code: string = readFileAsString(__dirname + '/fixtures/full-consequent-only-statements-after-return.js');
+
+                        obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                            code,
+                            {
+                                ...NO_ADDITIONAL_NODES_PRESET,
+                                simplify: true
+                            }
+                        ).getObfuscatedCode();
+                    });
+
+                    it('should simplify if statement', () => {
+                        assert.match(obfuscatedCode, regExp);
+                    });
+                });
             });
         });
 
@@ -229,6 +256,33 @@ describe('IfStatementSimplifyTransformer', () => {
                         assert.match(obfuscatedCode, regExp);
                     });
                 });
+
+                describe('Variant #3: statements after return', () => {
+                    const regExp: RegExp = new RegExp(
+                        'if *\\(!!\\[]\\) *\\{ *' +
+                            'bar\\(\\), *baz\\(\\); *return bark\\(\\); *cat\\(\\), *dog\\(\\); *' +
+                        '\\} *else *' +
+                            'hawk\\(\\), *pork\\(\\), *eagle\\(\\);'
+                    );
+
+                    let obfuscatedCode: string;
+
+                    before(() => {
+                        const code: string = readFileAsString(__dirname + '/fixtures/full-consequent-and-alternate-consequent-statements-after-return.js');
+
+                        obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                            code,
+                            {
+                                ...NO_ADDITIONAL_NODES_PRESET,
+                                simplify: true
+                            }
+                        ).getObfuscatedCode();
+                    });
+
+                    it('should simplify if statement', () => {
+                        assert.match(obfuscatedCode, regExp);
+                    });
+                });
             });
 
             describe('With alternate `ReturnStatement`', () => {
@@ -287,6 +341,34 @@ describe('IfStatementSimplifyTransformer', () => {
                         assert.match(obfuscatedCode, regExp);
                     });
                 });
+
+                describe('Variant #3: statements after return', () => {
+                    const regExp: RegExp = new RegExp(
+                        'if *\\(!!\\[]\\) *' +
+                            'bar\\(\\), *baz\\(\\), *bark\\(\\); *' +
+                        'else *\\{ *' +
+                            'hawk\\(\\), *eagle\\(\\); *return cow\\(\\); *cat\\(\\), *dog\\(\\);' +
+                        '\\}'
+                    );
+
+                    let obfuscatedCode: string;
+
+                    before(() => {
+                        const code: string = readFileAsString(__dirname + '/fixtures/full-consequent-and-alternate-alternate-statements-after-return.js');
+
+                        obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                            code,
+                            {
+                                ...NO_ADDITIONAL_NODES_PRESET,
+                                simplify: true
+                            }
+                        ).getObfuscatedCode();
+                    });
+
+                    it('should simplify if statement', () => {
+                        assert.match(obfuscatedCode, regExp);
+                    });
+                });
             });
 
             describe('With consequent and alternate `ReturnStatement`', () => {
@@ -433,6 +515,35 @@ describe('IfStatementSimplifyTransformer', () => {
                         assert.match(obfuscatedCode, regExp);
                     });
                 });
+
+                describe('Variant #2: statements after return', () => {
+                    const regExp: RegExp = new RegExp(
+                        'if *\\(!!\\[]\\) *{ *' +
+                            'const _0x([a-f0-9]){4,6} *= *baz\\(\\); *' +
+                            'return bark\\(\\); *' +
+                            'hawk\\(\\), *eagle\\(\\); *' +
+                        '}'
+                    );
+
+
+                    let obfuscatedCode: string;
+
+                    before(() => {
+                        const code: string = readFileAsString(__dirname + '/fixtures/partial-consequent-only-statements-after-return.js');
+
+                        obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                            code,
+                            {
+                                ...NO_ADDITIONAL_NODES_PRESET,
+                                simplify: true
+                            }
+                        ).getObfuscatedCode();
+                    });
+
+                    it('should simplify if statement', () => {
+                        assert.match(obfuscatedCode, regExp);
+                    });
+                });
             });
         });
 
@@ -619,6 +730,38 @@ describe('IfStatementSimplifyTransformer', () => {
                         assert.match(obfuscatedCode, regExp);
                     });
                 });
+
+                describe('Variant #3: statements after return', () => {
+                    const regExp: RegExp = new RegExp(
+                        'if *\\(!!\\[]\\) *{ *' +
+                            'const *_0x([a-f0-9]){4,6} *= *baz\\(\\); *' +
+                            'return hawk\\(\\); *' +
+                            'eagle\\(\\), *cat\\(\\);' +
+                        '} *else *{ *' +
+                            'const *_0x([a-f0-9]){4,6} *= *pig\\(\\); *' +
+                            'lion\\(\\), *dog\\(\\);' +
+                        '}'
+                    );
+
+
+                    let obfuscatedCode: string;
+
+                    before(() => {
+                        const code: string = readFileAsString(__dirname + '/fixtures/partial-consequent-and-alternate-consequent-statements-after-return.js');
+
+                        obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                            code,
+                            {
+                                ...NO_ADDITIONAL_NODES_PRESET,
+                                simplify: true
+                            }
+                        ).getObfuscatedCode();
+                    });
+
+                    it('should simplify if statement', () => {
+                        assert.match(obfuscatedCode, regExp);
+                    });
+                });
             });
 
             describe('With alternate `ReturnStatement`', () => {
@@ -681,6 +824,38 @@ describe('IfStatementSimplifyTransformer', () => {
                         assert.match(obfuscatedCode, regExp);
                     });
                 });
+
+                describe('Variant #3: statements after return', () => {
+                    const regExp: RegExp = new RegExp(
+                        'if *\\(!!\\[]\\) *{ *' +
+                            'const *_0x([a-f0-9]){4,6} *= *baz\\(\\); *' +
+                            'bark\\(\\), *hawk\\(\\);' +
+                        '} *else *{ *' +
+                            'const *_0x([a-f0-9]){4,6} *= *pork\\(\\); *' +
+                            'return dog\\(\\); *' +
+                            'pig\\(\\), *lion\\(\\); *' +
+                        '}'
+                    );
+
+
+                    let obfuscatedCode: string;
+
+                    before(() => {
+                        const code: string = readFileAsString(__dirname + '/fixtures/partial-consequent-and-alternate-alternate-statements-after-return.js');
+
+                        obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                            code,
+                            {
+                                ...NO_ADDITIONAL_NODES_PRESET,
+                                simplify: true
+                            }
+                        ).getObfuscatedCode();
+                    });
+
+                    it('should simplify if statement', () => {
+                        assert.match(obfuscatedCode, regExp);
+                    });
+                });
             });
 
             describe('With consequent and alternate `ReturnStatement`', () => {

+ 15 - 0
test/functional-tests/node-transformers/simplifying-transformers/if-statement-simplify-transformer/fixtures/full-consequent-and-alternate-alternate-statements-after-return.js

@@ -0,0 +1,15 @@
+function foo () {
+    if (true) {
+        bar();
+        baz();
+        bark();
+    } else {
+        hawk();
+        eagle();
+
+        return cow();
+
+        cat();
+        dog();
+    }
+}

+ 15 - 0
test/functional-tests/node-transformers/simplifying-transformers/if-statement-simplify-transformer/fixtures/full-consequent-and-alternate-consequent-statements-after-return.js

@@ -0,0 +1,15 @@
+function foo () {
+    if (true) {
+        bar();
+        baz();
+
+        return bark();
+
+        cat();
+        dog();
+    } else {
+        hawk();
+        pork();
+        eagle();
+    }
+}

+ 11 - 0
test/functional-tests/node-transformers/simplifying-transformers/if-statement-simplify-transformer/fixtures/full-consequent-only-statements-after-return.js

@@ -0,0 +1,11 @@
+function foo () {
+    if (true) {
+        bar();
+        baz();
+
+        return bark();
+
+        hawk();
+        eagle();
+    }
+}

+ 15 - 0
test/functional-tests/node-transformers/simplifying-transformers/if-statement-simplify-transformer/fixtures/partial-consequent-and-alternate-alternate-statements-after-return.js

@@ -0,0 +1,15 @@
+function foo () {
+    if (true) {
+        const bar = baz();
+
+        bark();
+        hawk();
+    } else {
+        const eagle = pork();
+
+        return dog()
+
+        pig();
+        lion();
+    }
+}

+ 15 - 0
test/functional-tests/node-transformers/simplifying-transformers/if-statement-simplify-transformer/fixtures/partial-consequent-and-alternate-consequent-statements-after-return.js

@@ -0,0 +1,15 @@
+function foo () {
+    if (true) {
+        const bar = baz();
+
+        return hawk();
+
+        eagle();
+        cat();
+    } else {
+        const pork = pig();
+
+        lion();
+        dog();
+    }
+}

+ 10 - 0
test/functional-tests/node-transformers/simplifying-transformers/if-statement-simplify-transformer/fixtures/partial-consequent-only-statements-after-return.js

@@ -0,0 +1,10 @@
+function foo () {
+    if (true) {
+        const bar = baz();
+
+        return bark();
+
+        hawk();
+        eagle();
+    }
+}

+ 6 - 1
yarn.lock

@@ -460,7 +460,12 @@
   dependencies:
     "@types/estree" "*"
 
-"@types/estree@*", "@types/[email protected]", "@types/estree@^0.0.50":
+"@types/estree@*", "@types/[email protected]":
+  version "0.0.51"
+  resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.51.tgz#cfd70924a25a3fd32b218e5e420e6897e1ac4f40"
+  integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==
+
+"@types/estree@^0.0.50":
   version "0.0.50"
   resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.50.tgz#1e0caa9364d3fccd2931c3ed96fdbeaa5d4cca83"
   integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==