Ver Fonte

Fixed invalid code generation for rest arguments when `controlFlowFlattening` option is enabled
Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/887

sanex há 4 anos atrás
pai
commit
dd328b3c22

+ 4 - 0
CHANGELOG.md

@@ -1,5 +1,9 @@
 Change Log
 Change Log
 
 
+v2.10.5
+---
+* Fixed invalid code generation for rest arguments when `controlFlowFlattening` option is enabled. Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/887
+
 v2.10.4
 v2.10.4
 ---
 ---
 * Fixed invalid behaviour of `numbersToExpressions` option for float numbers. Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/882
 * Fixed invalid behaviour of `numbersToExpressions` option for float numbers. Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/882

Diff do ficheiro suprimidas por serem muito extensas
+ 0 - 0
dist/index.browser.js


Diff do ficheiro suprimidas por serem muito extensas
+ 0 - 0
dist/index.cli.js


Diff do ficheiro suprimidas por serem muito extensas
+ 0 - 0
dist/index.js


+ 1 - 1
package.json

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

+ 19 - 3
src/custom-nodes/control-flow-flattening-nodes/CallExpressionFunctionNode.ts

@@ -15,6 +15,7 @@ import { initializable } from '../../decorators/Initializable';
 import { AbstractCustomNode } from '../AbstractCustomNode';
 import { AbstractCustomNode } from '../AbstractCustomNode';
 import { NodeFactory } from '../../node/NodeFactory';
 import { NodeFactory } from '../../node/NodeFactory';
 import { NodeUtils } from '../../node/NodeUtils';
 import { NodeUtils } from '../../node/NodeUtils';
+import { NodeGuards } from '../../node/NodeGuards';
 
 
 @injectable()
 @injectable()
 export class CallExpressionFunctionNode extends AbstractCustomNode {
 export class CallExpressionFunctionNode extends AbstractCustomNode {
@@ -57,11 +58,26 @@ export class CallExpressionFunctionNode extends AbstractCustomNode {
      */
      */
     protected getNodeStructure (): TStatement[] {
     protected getNodeStructure (): TStatement[] {
         const calleeIdentifier: ESTree.Identifier = NodeFactory.identifierNode('callee');
         const calleeIdentifier: ESTree.Identifier = NodeFactory.identifierNode('callee');
-        const params: ESTree.Identifier[] = [];
+        const params: (ESTree.Identifier | ESTree.RestElement)[] = [];
+        const callArguments: (ESTree.Identifier | ESTree.SpreadElement)[] = [];
         const argumentsLength: number = this.expressionArguments.length;
         const argumentsLength: number = this.expressionArguments.length;
 
 
         for (let i: number = 0; i < argumentsLength; i++) {
         for (let i: number = 0; i < argumentsLength; i++) {
-            params.push(NodeFactory.identifierNode(`param${i + 1}`));
+            const argument: ESTree.Expression | ESTree.SpreadElement = this.expressionArguments[i];
+            const isSpreadCallArgument: boolean = NodeGuards.isSpreadElementNode(argument);
+
+            const baseIdentifierNode: ESTree.Identifier = NodeFactory.identifierNode(`param${i + 1}`);
+
+            params.push(
+                isSpreadCallArgument
+                    ? NodeFactory.restElementNode(baseIdentifierNode)
+                    : baseIdentifierNode
+            );
+            callArguments.push(
+                isSpreadCallArgument
+                    ? NodeFactory.spreadElementNode(baseIdentifierNode)
+                    : baseIdentifierNode
+            );
         }
         }
 
 
         const structure: TStatement = NodeFactory.expressionStatementNode(
         const structure: TStatement = NodeFactory.expressionStatementNode(
@@ -74,7 +90,7 @@ export class CallExpressionFunctionNode extends AbstractCustomNode {
                     NodeFactory.returnStatementNode(
                     NodeFactory.returnStatementNode(
                         NodeFactory.callExpressionNode(
                         NodeFactory.callExpressionNode(
                             calleeIdentifier,
                             calleeIdentifier,
-                            params
+                            callArguments
                         )
                         )
                     )
                     )
                 ])
                 ])

+ 25 - 1
src/node/NodeFactory.ts

@@ -317,7 +317,7 @@ export class NodeFactory {
      * @returns {FunctionExpression}
      * @returns {FunctionExpression}
      */
      */
     public static functionExpressionNode (
     public static functionExpressionNode (
-        params: ESTree.Identifier[],
+        params: ESTree.Pattern[],
         body: ESTree.BlockStatement
         body: ESTree.BlockStatement
     ): ESTree.FunctionExpression {
     ): ESTree.FunctionExpression {
         return {
         return {
@@ -493,6 +493,18 @@ export class NodeFactory {
         };
         };
     }
     }
 
 
+    /**
+     * @param {Pattern} argument
+     * @returns {SpreadElement}
+     */
+    public static restElementNode (argument: ESTree.Pattern): ESTree.RestElement {
+        return {
+            type: NodeType.RestElement,
+            argument,
+            metadata: { ignoredNode: false }
+        };
+    }
+
     /**
     /**
      * @param {Expression} argument
      * @param {Expression} argument
      * @returns {ReturnStatement}
      * @returns {ReturnStatement}
@@ -517,6 +529,18 @@ export class NodeFactory {
         };
         };
     }
     }
 
 
+    /**
+     * @param {Expression} argument
+     * @returns {SpreadElement}
+     */
+    public static spreadElementNode (argument: ESTree.Expression): ESTree.SpreadElement {
+        return {
+            type: NodeType.SpreadElement,
+            argument,
+            metadata: { ignoredNode: false }
+        };
+    }
+
     /**
     /**
      * @param {Expression} discriminant
      * @param {Expression} discriminant
      * @param {SwitchCase[]} cases
      * @param {SwitchCase[]} cases

+ 9 - 7
test/dev/dev.ts

@@ -7,17 +7,19 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../src/options/presets/NoCustomNo
 
 
     let obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
     let obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
         `
         `
-            const epsilon = 500;
-            const number = 500000.0000001;
-             
-            if(epsilon > 0 && number > 500000.0000000 && number < 500000.0000002) {
-                console.log("math works!");
-            };
+            (function () {
+                const log = console.log;
+                const first = 'foo';
+                const rest = ['bar', 'baz', 'bark'];
+                log(first, ...rest);            
+            })();
 
 
         `,
         `,
         {
         {
             ...NO_ADDITIONAL_NODES_PRESET,
             ...NO_ADDITIONAL_NODES_PRESET,
-            numbersToExpressions: true
+            compact: false,
+            controlFlowFlattening: true,
+            controlFlowFlatteningThreshold: 1
         }
         }
     ).getObfuscatedCode();
     ).getObfuscatedCode();
 
 

+ 32 - 0
test/functional-tests/node-transformers/control-flow-transformers/control-flow-replacers/call-expression-control-flow-replacer/CallExpressionControlFlowReplacer.spec.ts

@@ -117,5 +117,37 @@ describe('CallExpressionControlFlowReplacer', function () {
                 assert.match(obfuscatedCode, regExp);
                 assert.match(obfuscatedCode, regExp);
             });
             });
         });
         });
+
+        describe('Variant #4 - rest call argument', () => {
+            const controlFlowStorageCallRegExp: RegExp = /_0x([a-f0-9]){4,6}\['\w{5}']\(_0x([a-f0-9]){4,6}, *_0x([a-f0-9]){4,6}, *\.\.\._0x([a-f0-9]){4,6}\);/;
+            const controlFlowStorageNodeRegExp: RegExp = new RegExp(`` +
+                `'\\w{5}' *: *function *\\(_0x([a-f0-9]){4,6}, *_0x([a-f0-9]){4,6}, *\.\.\._0x([a-f0-9]){4,6}\\) *\\{` +
+                   `return *_0x([a-f0-9]){4,6}\\(_0x([a-f0-9]){4,6}, *\.\.\._0x([a-f0-9]){4,6}\\);` +
+                `\\}` +
+            ``);
+
+            let obfuscatedCode: string;
+
+            before(() => {
+                const code: string = readFileAsString(__dirname + '/fixtures/rest-call-argument.js');
+
+                obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                    code,
+                    {
+                        ...NO_ADDITIONAL_NODES_PRESET,
+                        controlFlowFlattening: true,
+                        controlFlowFlatteningThreshold: 1
+                    }
+                ).getObfuscatedCode();
+            });
+
+            it('should replace call expression node with call to control flow storage node', () => {
+                assert.match(obfuscatedCode, controlFlowStorageCallRegExp);
+            });
+
+            it('should keep spread parameter and rest call argument inside control flow storage node function', () => {
+                assert.match(obfuscatedCode, controlFlowStorageNodeRegExp);
+            });
+        });
     });
     });
 });
 });

+ 6 - 0
test/functional-tests/node-transformers/control-flow-transformers/control-flow-replacers/call-expression-control-flow-replacer/fixtures/rest-call-argument.js

@@ -0,0 +1,6 @@
+(function () {
+    const log = console.log;
+    const first = 'foo';
+    const rest = ['bar', 'baz', 'bark'];
+    log(first, ...rest);
+})();

+ 2 - 2
test/functional-tests/node-transformers/control-flow-transformers/function-control-flow-transformer/FunctionControlFlowTransformer.spec.ts

@@ -221,7 +221,7 @@ describe('FunctionControlFlowTransformer', function () {
             });
             });
         });
         });
 
 
-        describe('arrow function expression', () => {
+        describe('Variant #7 - arrow function expression', () => {
             describe('Variant #1 - arrow function expression with body', () => {
             describe('Variant #1 - arrow function expression with body', () => {
                 const regexp: RegExp = new RegExp(rootControlFlowStorageNodeMatch);
                 const regexp: RegExp = new RegExp(rootControlFlowStorageNodeMatch);
 
 
@@ -269,7 +269,7 @@ describe('FunctionControlFlowTransformer', function () {
             });
             });
         });
         });
 
 
-        describe('prevailing kind of variables', () => {
+        describe('Variant #8 - prevailing kind of variables', () => {
             describe('Variant #1 - `var` kind', () => {
             describe('Variant #1 - `var` kind', () => {
                 const regexp: RegExp = new RegExp(`var ${variableMatch} *= *\\{`);
                 const regexp: RegExp = new RegExp(`var ${variableMatch} *= *\\{`);
 
 

Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff