소스 검색

ExpressionStatementsMergeTransformer + optimized AbstractStatementSimplifyTransformer logic

sanex3339 4 년 전
부모
커밋
37eb0aa745

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 0
dist/index.browser.js


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 0
dist/index.cli.js


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 0
dist/index.js


+ 1 - 0
src/JavaScriptObfuscator.ts

@@ -68,6 +68,7 @@ export class JavaScriptObfuscator implements IJavaScriptObfuscator {
         NodeTransformer.CustomCodeHelpersTransformer,
         NodeTransformer.DeadCodeInjectionTransformer,
         NodeTransformer.EvalCallExpressionTransformer,
+        NodeTransformer.ExpressionStatementsMergeTransformer,
         NodeTransformer.FunctionControlFlowTransformer,
         NodeTransformer.IfStatementSimplifyTransformer,
         NodeTransformer.LabeledStatementTransformer,

+ 5 - 0
src/container/modules/node-transformers/SimplifyingTransformersModule.ts

@@ -6,6 +6,7 @@ import { INodeTransformer } from '../../../interfaces/node-transformers/INodeTra
 import { NodeTransformer } from '../../../enums/node-transformers/NodeTransformer';
 
 import { BlockStatementSimplifyTransformer } from '../../../node-transformers/simplifying-transformers/BlockStatementSimplifyTransformer';
+import { ExpressionStatementsMergeTransformer } from '../../../node-transformers/simplifying-transformers/ExpressionStatementsMergeTransformer';
 import { IfStatementSimplifyTransformer } from '../../../node-transformers/simplifying-transformers/IfStatementSimplifyTransformer';
 import { VariableDeclarationsMergeTransformer } from '../../../node-transformers/simplifying-transformers/VariableDeclarationsMergeTransformer';
 
@@ -15,6 +16,10 @@ export const simplifyingTransformersModule: interfaces.ContainerModule = new Con
         .to(BlockStatementSimplifyTransformer)
         .whenTargetNamed(NodeTransformer.BlockStatementSimplifyTransformer);
 
+    bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
+        .to(ExpressionStatementsMergeTransformer)
+        .whenTargetNamed(NodeTransformer.ExpressionStatementsMergeTransformer);
+
     bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
         .to(IfStatementSimplifyTransformer)
         .whenTargetNamed(NodeTransformer.IfStatementSimplifyTransformer);

+ 1 - 0
src/enums/node-transformers/NodeTransformer.ts

@@ -5,6 +5,7 @@ export enum NodeTransformer {
     CustomCodeHelpersTransformer = 'CustomCodeHelpersTransformer',
     DeadCodeInjectionTransformer = 'DeadCodeInjectionTransformer',
     EvalCallExpressionTransformer = 'EvalCallExpressionTransformer',
+    ExpressionStatementsMergeTransformer = 'ExpressionStatementsMergeTransformer',
     FunctionControlFlowTransformer = 'FunctionControlFlowTransformer',
     IfStatementSimplifyTransformer = 'IfStatementSimplifyTransformer',
     LabeledStatementTransformer = 'LabeledStatementTransformer',

+ 13 - 10
src/node-transformers/simplifying-transformers/AbstractStatementSimplifyTransformer.ts

@@ -23,6 +23,7 @@ export abstract class AbstractStatementSimplifyTransformer extends AbstractNodeT
      * @type {NodeTransformer[]}
      */
     public readonly runAfter: NodeTransformer[] = [
+        NodeTransformer.ExpressionStatementsMergeTransformer,
         NodeTransformer.VariableDeclarationsMergeTransformer
     ];
 
@@ -110,17 +111,19 @@ export abstract class AbstractStatementSimplifyTransformer extends AbstractNodeT
         const unwrappedExpressions: ESTree.Expression[] = [];
 
         let hasReturnStatement: boolean = false;
-        let startIndex: number | null = 0;
+        let startIndex: number | null = null;
 
-        for (let i = 0; i < statementNodeBodyLength; i++) {
+        for (let i = statementNodeBodyLength - 1; i >= 0; i--) {
             const statementBodyStatementNode: ESTree.Statement = statementNode.body[i];
 
-            if (startIndex === null) {
-                startIndex = i;
-            }
-
             if (NodeGuards.isExpressionStatementNode(statementBodyStatementNode)) {
-                unwrappedExpressions.push(statementBodyStatementNode.expression);
+                if (NodeGuards.isSequenceExpressionNode(statementBodyStatementNode.expression)) {
+                    unwrappedExpressions.unshift(...statementBodyStatementNode.expression.expressions);
+                } else {
+                    unwrappedExpressions.unshift(statementBodyStatementNode.expression);
+                }
+
+                startIndex = i;
                 continue;
             }
 
@@ -128,13 +131,13 @@ export abstract class AbstractStatementSimplifyTransformer extends AbstractNodeT
                 NodeGuards.isReturnStatementNode(statementBodyStatementNode)
                 && statementBodyStatementNode.argument
             ) {
-                unwrappedExpressions.push(statementBodyStatementNode.argument);
+                unwrappedExpressions.unshift(statementBodyStatementNode.argument);
                 hasReturnStatement = true;
+                startIndex = i;
                 continue;
             }
 
-            startIndex = null;
-            unwrappedExpressions.length = 0;
+            break;
         }
 
         return {

+ 97 - 0
src/node-transformers/simplifying-transformers/ExpressionStatementsMergeTransformer.ts

@@ -0,0 +1,97 @@
+import { inject, injectable, } from 'inversify';
+import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
+
+import * as estraverse from 'estraverse';
+import * as ESTree from 'estree';
+
+import { TStatement } from '../../types/node/TStatement';
+
+import { IOptions } from '../../interfaces/options/IOptions';
+import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
+import { IVisitor } from '../../interfaces/node-transformers/IVisitor';
+
+import { NodeTransformationStage } from '../../enums/node-transformers/NodeTransformationStage';
+
+import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
+import { NodeFactory } from '../../node/NodeFactory';
+import { NodeGuards } from '../../node/NodeGuards';
+import { NodeStatementUtils } from '../../node/NodeStatementUtils';
+import { NodeUtils } from '../../node/NodeUtils';
+
+/**
+ * replaces:
+ *     console.log(1);
+ *     console.log(2);
+ *
+ * on:
+ *     (console.log(1), console.log(2));
+ */
+@injectable()
+export class ExpressionStatementsMergeTransformer extends AbstractNodeTransformer {
+    /**
+     * @param {IRandomGenerator} randomGenerator
+     * @param {IOptions} options
+     */
+    public constructor (
+        @inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
+        @inject(ServiceIdentifiers.IOptions) options: IOptions
+    ) {
+        super(randomGenerator, options);
+    }
+
+    /**
+     * @param {NodeTransformationStage} nodeTransformationStage
+     * @returns {IVisitor | null}
+     */
+    public getVisitor (nodeTransformationStage: NodeTransformationStage): IVisitor | null {
+        switch (nodeTransformationStage) {
+            case NodeTransformationStage.Simplifying:
+                return {
+                    leave: (
+                        node: ESTree.Node,
+                        parentNode: ESTree.Node | null
+                    ): ESTree.Node | estraverse.VisitorOption | undefined => {
+                        if (parentNode && NodeGuards.isExpressionStatementNode(node)) {
+                            return this.transformNode(node, parentNode);
+                        }
+                    }
+                };
+
+            default:
+                return null;
+        }
+    }
+
+    /**
+     * @param {ESTree.ExpressionStatement} expressionStatementNode
+     * @param {ESTree.Node} parentNode
+     * @returns {ESTree.ExpressionStatement | estraverse.VisitorOption}
+     */
+    public transformNode (
+        expressionStatementNode: ESTree.ExpressionStatement,
+        parentNode: ESTree.Node
+    ): ESTree.ExpressionStatement | estraverse.VisitorOption {
+        if (!NodeGuards.isNodeWithStatements(parentNode)) {
+            return expressionStatementNode;
+        }
+
+        const prevStatement: TStatement | null = NodeStatementUtils.getPreviousSiblingStatement(expressionStatementNode);
+
+        if (!prevStatement || !NodeGuards.isExpressionStatementNode(prevStatement)) {
+            return expressionStatementNode;
+        }
+
+        if (NodeGuards.isSequenceExpressionNode(prevStatement.expression)) {
+            prevStatement.expression.expressions.push(expressionStatementNode.expression);
+        } else {
+            prevStatement.expression = NodeFactory.sequenceExpressionNode([
+                prevStatement.expression,
+                expressionStatementNode.expression
+            ]);
+        }
+
+        NodeUtils.parentizeAst(prevStatement);
+
+        return estraverse.VisitorOption.Remove;
+    }
+}

+ 5 - 8
test/dev/dev.ts

@@ -7,14 +7,11 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../src/options/presets/NoCustomNo
 
     let obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
         `
-            var foo = function () {};
-            var bar = function () {
-                var baz = function () {};
-                var bark = function () {
-                    var hawk = 1;
-                    var dog = 2;
-                };
-            };
+            function foo () {
+                console.log(7);
+                
+                return 9;
+            }
         `,
         {
             ...NO_ADDITIONAL_NODES_PRESET,

+ 72 - 0
test/functional-tests/node-transformers/simplifying-transformers/expression-statements-merge-transformer/ExpressionStatementsMergeTransformer.spec.ts

@@ -0,0 +1,72 @@
+import { assert } from 'chai';
+
+import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes';
+
+import { readFileAsString } from '../../../../helpers/readFileAsString';
+
+import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade';
+
+describe('ExpressionStatementsMergeTransformer', () => {
+    describe('Variant #1: simple', () => {
+        const regExp: RegExp = new RegExp(
+            'function foo *\\(\\) *{ *' +
+                'bar\\(\\), *' +
+                'baz\\(\\), *' +
+                'bark\\(\\); *' +
+            '}'
+        );
+
+
+        let obfuscatedCode: string;
+
+        before(() => {
+            const code: string = readFileAsString(__dirname + '/fixtures/simple.js');
+
+            obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                code,
+                {
+                    ...NO_ADDITIONAL_NODES_PRESET,
+                    simplify: true
+                }
+            ).getObfuscatedCode();
+        });
+
+        it('should merge expression statements', () => {
+            assert.match(obfuscatedCode, regExp);
+        });
+    });
+
+    describe('Variant #2: complex', () => {
+        const regExp: RegExp = new RegExp(
+            'function foo *\\(\\) *{ *' +
+                'console\\[\'log\']\\(0x1\\), *' +
+                'console\\[\'log\']\\(0x2\\); *' +
+                'function _0x([a-f0-9]){4,6} *\\(\\) *{ *} *' +
+                'console\\[\'log\']\\(0x3\\), *' +
+                'console\\[\'log\']\\(0x4\\), *' +
+                'console\\[\'log\']\\(0x5\\); *' +
+                'const _0x([a-f0-9]){4,6} *= *0x6; *' +
+                'console\\[\'log\']\\(0x7\\); *' +
+            '}'
+        );
+
+
+        let obfuscatedCode: string;
+
+        before(() => {
+            const code: string = readFileAsString(__dirname + '/fixtures/complex.js');
+
+            obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                code,
+                {
+                    ...NO_ADDITIONAL_NODES_PRESET,
+                    simplify: true
+                }
+            ).getObfuscatedCode();
+        });
+
+        it('should merge expression statements', () => {
+            assert.match(obfuscatedCode, regExp);
+        });
+    });
+});

+ 14 - 0
test/functional-tests/node-transformers/simplifying-transformers/expression-statements-merge-transformer/fixtures/complex.js

@@ -0,0 +1,14 @@
+function foo () {
+    console.log(1);
+    console.log(2);
+
+    function bar () {}
+
+    console.log(3);
+    console.log(4);
+    console.log(5);
+
+    const baz = 6;
+
+    console.log(7);
+}

+ 5 - 0
test/functional-tests/node-transformers/simplifying-transformers/expression-statements-merge-transformer/fixtures/simple.js

@@ -0,0 +1,5 @@
+function foo () {
+    bar();
+    baz();
+    bark();
+}

+ 2 - 0
test/index.spec.ts

@@ -95,6 +95,8 @@ import './functional-tests/node-transformers/converting-transformers/split-strin
 import './functional-tests/node-transformers/converting-transformers/template-literal-transformer/TemplateLiteralTransformer.spec';
 import './functional-tests/node-transformers/dead-code-injection-transformers/DeadCodeInjectionTransformer.spec';
 import './functional-tests/node-transformers/initializing-transformers/comments-transformer/CommentsTransformer.spec';
+import './functional-tests/node-transformers/simplifying-transformers/block-statement-simplify-transformer/BlockStatementSimplifyTransformer.spec';
+import './functional-tests/node-transformers/simplifying-transformers/expression-statements-merge-transformer/ExpressionStatementsMergeTransformer.spec';
 import './functional-tests/node-transformers/simplifying-transformers/if-statement-simplify-transformer/IfStatementSimplifyTransformer.spec';
 import './functional-tests/node-transformers/simplifying-transformers/variable-declarations-merge-transformer/VariableDeclarationsMergeTransformer.spec';
 import './functional-tests/node-transformers/obfuscating-transformers/labeled-statement-transformer/LabeledStatementTransformer.spec';

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.