Browse Source

0.8.0-beta.2: fixed wrong obfuscation of labels

sanex3339 8 years ago
parent
commit
d444195cdb

+ 2 - 1
CHANGELOG.md

@@ -10,7 +10,8 @@ v0.8.0
 * New option `domainLock` locks the obfuscated source code so it only runs on specific domains and/or sub-domains.
 * New option `sourceMapBaseUrl` sets base url to the source map import url when `sourceMapMode: 'separate'`.
 * Custom nodes like `selfDefendingNode` or `consoleOutputNode` now inserted into deepest stack trace function call.
-* Fixed obfuscation of global variables and function names in some cases
+* Fixed obfuscation of global variables and function names in some cases.
+* Fixed wrong obfuscation of labels.
 * Rewrite of many custom nodes.
 
 v0.7.3

+ 103 - 4
dist/index.js

@@ -88,7 +88,7 @@ module.exports =
 /******/ 	__webpack_require__.p = "";
 /******/
 /******/ 	// Load entry module and return exports
-/******/ 	return __webpack_require__(__webpack_require__.s = 86);
+/******/ 	return __webpack_require__(__webpack_require__.s = 87);
 /******/ })
 /************************************************************************/
 /******/ ([
@@ -469,11 +469,21 @@ var Node = function () {
         value: function isBlockStatementNode(node) {
             return node.type === NodeType_1.NodeType.BlockStatement;
         }
+    }, {
+        key: 'isBreakStatementNode',
+        value: function isBreakStatementNode(node) {
+            return node.type === NodeType_1.NodeType.BreakStatement;
+        }
     }, {
         key: 'isCallExpressionNode',
         value: function isCallExpressionNode(node) {
             return node.type === NodeType_1.NodeType.CallExpression;
         }
+    }, {
+        key: 'isContinueStatementNode',
+        value: function isContinueStatementNode(node) {
+            return node.type === NodeType_1.NodeType.ContinueStatement;
+        }
     }, {
         key: 'isExpressionStatementNode',
         value: function isExpressionStatementNode(node) {
@@ -494,6 +504,19 @@ var Node = function () {
         value: function isIdentifierNode(node) {
             return node.type === NodeType_1.NodeType.Identifier;
         }
+    }, {
+        key: 'isLabelIdentifierNode',
+        value: function isLabelIdentifierNode(node, parentNode) {
+            var parentNodeIsLabeledStatementNode = Node.isLabeledStatementNode(parentNode) && parentNode.label === node;
+            var parentNodeIsContinueStatementNode = Node.isContinueStatementNode(parentNode) && parentNode.label === node;
+            var parentNodeIsBreakStatementNode = Node.isBreakStatementNode(parentNode) && parentNode.label === node;
+            return parentNodeIsLabeledStatementNode || parentNodeIsContinueStatementNode || parentNodeIsBreakStatementNode;
+        }
+    }, {
+        key: 'isLabeledStatementNode',
+        value: function isLabeledStatementNode(node) {
+            return node.type === NodeType_1.NodeType.LabeledStatement;
+        }
     }, {
         key: 'isLiteralNode',
         value: function isLiteralNode(node) {
@@ -527,7 +550,7 @@ var Node = function () {
             }
             var parentNodeIsPropertyNode = Node.isPropertyNode(parentNode) && parentNode.key === node;
             var parentNodeIsMemberExpressionNode = Node.isMemberExpressionNode(parentNode) && parentNode.computed === false && parentNode.property === node;
-            return !parentNodeIsPropertyNode && !parentNodeIsMemberExpressionNode;
+            return !parentNodeIsPropertyNode && !parentNodeIsMemberExpressionNode && !Node.isLabelIdentifierNode(node, parentNode);
         }
     }, {
         key: 'isVariableDeclarationNode',
@@ -738,14 +761,17 @@ exports.NodeType = Utils_1.Utils.strEnumify({
     AssignmentExpression: 'AssignmentExpression',
     BinaryExpression: 'BinaryExpression',
     BlockStatement: 'BlockStatement',
+    BreakStatement: 'BreakStatement',
     CallExpression: 'CallExpression',
     CatchClause: 'CatchClause',
     ClassDeclaration: 'ClassDeclaration',
+    ContinueStatement: 'ContinueStatement',
     ExpressionStatement: 'ExpressionStatement',
     FunctionDeclaration: 'FunctionDeclaration',
     FunctionExpression: 'FunctionExpression',
     Identifier: 'Identifier',
     IfStatement: 'IfStatement',
+    LabeledStatement: 'LabeledStatement',
     Literal: 'Literal',
     LogicalExpression: 'LogicalExpression',
     MemberExpression: 'MemberExpression',
@@ -1442,6 +1468,7 @@ var DebugProtectionNodesGroup_1 = __webpack_require__(43);
 var DomainLockNodesGroup_1 = __webpack_require__(44);
 var FunctionDeclarationObfuscator_1 = __webpack_require__(48);
 var FunctionObfuscator_1 = __webpack_require__(49);
+var LabeledStatementObfuscator_1 = __webpack_require__(88);
 var LiteralObfuscator_1 = __webpack_require__(50);
 var MemberExpressionObfuscator_1 = __webpack_require__(51);
 var MethodDefinitionObfuscator_1 = __webpack_require__(52);
@@ -1538,7 +1565,7 @@ var Obfuscator = function () {
 }();
 
 Obfuscator.nodeGroups = [DomainLockNodesGroup_1.DomainLockNodesGroup, SelfDefendingNodesGroup_1.SelfDefendingNodesGroup, ConsoleOutputNodesGroup_1.ConsoleOutputNodesGroup, DebugProtectionNodesGroup_1.DebugProtectionNodesGroup, StringArrayNodesGroup_1.StringArrayNodesGroup];
-Obfuscator.nodeObfuscators = new Map([[NodeType_1.NodeType.ArrowFunctionExpression, [FunctionObfuscator_1.FunctionObfuscator]], [NodeType_1.NodeType.ClassDeclaration, [FunctionDeclarationObfuscator_1.FunctionDeclarationObfuscator]], [NodeType_1.NodeType.CatchClause, [CatchClauseObfuscator_1.CatchClauseObfuscator]], [NodeType_1.NodeType.FunctionDeclaration, [FunctionDeclarationObfuscator_1.FunctionDeclarationObfuscator, FunctionObfuscator_1.FunctionObfuscator]], [NodeType_1.NodeType.FunctionExpression, [FunctionObfuscator_1.FunctionObfuscator]], [NodeType_1.NodeType.MemberExpression, [MemberExpressionObfuscator_1.MemberExpressionObfuscator]], [NodeType_1.NodeType.MethodDefinition, [MethodDefinitionObfuscator_1.MethodDefinitionObfuscator]], [NodeType_1.NodeType.ObjectExpression, [ObjectExpressionObfuscator_1.ObjectExpressionObfuscator]], [NodeType_1.NodeType.VariableDeclaration, [VariableDeclarationObfuscator_1.VariableDeclarationObfuscator]], [NodeType_1.NodeType.Literal, [LiteralObfuscator_1.LiteralObfuscator]]]);
+Obfuscator.nodeObfuscators = new Map([[NodeType_1.NodeType.ArrowFunctionExpression, [FunctionObfuscator_1.FunctionObfuscator]], [NodeType_1.NodeType.ClassDeclaration, [FunctionDeclarationObfuscator_1.FunctionDeclarationObfuscator]], [NodeType_1.NodeType.CatchClause, [CatchClauseObfuscator_1.CatchClauseObfuscator]], [NodeType_1.NodeType.FunctionDeclaration, [FunctionDeclarationObfuscator_1.FunctionDeclarationObfuscator, FunctionObfuscator_1.FunctionObfuscator]], [NodeType_1.NodeType.FunctionExpression, [FunctionObfuscator_1.FunctionObfuscator]], [NodeType_1.NodeType.MemberExpression, [MemberExpressionObfuscator_1.MemberExpressionObfuscator]], [NodeType_1.NodeType.MethodDefinition, [MethodDefinitionObfuscator_1.MethodDefinitionObfuscator]], [NodeType_1.NodeType.ObjectExpression, [ObjectExpressionObfuscator_1.ObjectExpressionObfuscator]], [NodeType_1.NodeType.VariableDeclaration, [VariableDeclarationObfuscator_1.VariableDeclarationObfuscator]], [NodeType_1.NodeType.LabeledStatement, [LabeledStatementObfuscator_1.LabeledStatementObfuscator]], [NodeType_1.NodeType.Literal, [LiteralObfuscator_1.LiteralObfuscator]]]);
 exports.Obfuscator = Obfuscator;
 
 /***/ },
@@ -4333,7 +4360,8 @@ module.exports = require("fs");
 module.exports = require("mkdirp");
 
 /***/ },
-/* 86 */
+/* 86 */,
+/* 87 */
 /***/ function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -4345,6 +4373,77 @@ if (!global._babelPolyfill) {
 }
 module.exports = JavaScriptObfuscator_1.JavaScriptObfuscator;
 
+/***/ },
+/* 88 */
+/***/ function(module, exports, __webpack_require__) {
+
+"use strict";
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+var estraverse = __webpack_require__(5);
+var NodeType_1 = __webpack_require__(7);
+var AbstractNodeObfuscator_1 = __webpack_require__(9);
+var IdentifierReplacer_1 = __webpack_require__(15);
+var Node_1 = __webpack_require__(3);
+var NodeUtils_1 = __webpack_require__(1);
+
+var LabeledStatementObfuscator = function (_AbstractNodeObfuscat) {
+    _inherits(LabeledStatementObfuscator, _AbstractNodeObfuscat);
+
+    function LabeledStatementObfuscator(nodes, options) {
+        _classCallCheck(this, LabeledStatementObfuscator);
+
+        var _this = _possibleConstructorReturn(this, (LabeledStatementObfuscator.__proto__ || Object.getPrototypeOf(LabeledStatementObfuscator)).call(this, nodes, options));
+
+        _this.identifierReplacer = new IdentifierReplacer_1.IdentifierReplacer(_this.nodes, _this.options);
+        return _this;
+    }
+
+    _createClass(LabeledStatementObfuscator, [{
+        key: 'obfuscateNode',
+        value: function obfuscateNode(labeledStatementNode) {
+            this.storeLabeledStatementName(labeledStatementNode);
+            this.replaceLabeledStatementName(labeledStatementNode);
+        }
+    }, {
+        key: 'storeLabeledStatementName',
+        value: function storeLabeledStatementName(labeledStatementNode) {
+            var _this2 = this;
+
+            NodeUtils_1.NodeUtils.typedReplace(labeledStatementNode.label, NodeType_1.NodeType.Identifier, {
+                enter: function enter(node) {
+                    return _this2.identifierReplacer.storeNames(node.name);
+                }
+            });
+        }
+    }, {
+        key: 'replaceLabeledStatementName',
+        value: function replaceLabeledStatementName(labeledStatementNode) {
+            var _this3 = this;
+
+            estraverse.replace(labeledStatementNode, {
+                enter: function enter(node, parentNode) {
+                    if (Node_1.Node.isLabelIdentifierNode(node, parentNode)) {
+                        node.name = _this3.identifierReplacer.replace(node.name);
+                    }
+                }
+            });
+        }
+    }]);
+
+    return LabeledStatementObfuscator;
+}(AbstractNodeObfuscator_1.AbstractNodeObfuscator);
+
+exports.LabeledStatementObfuscator = LabeledStatementObfuscator;
+
 /***/ }
 /******/ ]);
 //# sourceMappingURL=index.js.map

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "javascript-obfuscator",
-  "version": "0.8.0-beta.1",
+  "version": "0.8.0-beta.2",
   "description": "JavaScript obfuscator",
   "keywords": [
     "obfuscator",

+ 2 - 0
src/Obfuscator.ts

@@ -18,6 +18,7 @@ import { DebugProtectionNodesGroup } from './node-groups/DebugProtectionNodesGro
 import { DomainLockNodesGroup } from './node-groups/DomainLockNodesGroup';
 import { FunctionDeclarationObfuscator } from './node-obfuscators/FunctionDeclarationObfuscator';
 import { FunctionObfuscator } from './node-obfuscators/FunctionObfuscator';
+import { LabeledStatementObfuscator } from './node-obfuscators/LabeledStatementObfuscator';
 import { LiteralObfuscator } from './node-obfuscators/LiteralObfuscator';
 import { MemberExpressionObfuscator } from './node-obfuscators/MemberExpressionObfuscator';
 import { MethodDefinitionObfuscator } from './node-obfuscators/MethodDefinitionObfuscator';
@@ -57,6 +58,7 @@ export class Obfuscator implements IObfuscator {
         [NodeType.MethodDefinition, [MethodDefinitionObfuscator]],
         [NodeType.ObjectExpression, [ObjectExpressionObfuscator]],
         [NodeType.VariableDeclaration, [VariableDeclarationObfuscator]],
+        [NodeType.LabeledStatement, [LabeledStatementObfuscator]],
         [NodeType.Literal, [LiteralObfuscator]]
     ]);
 

+ 3 - 0
src/enums/NodeType.ts

@@ -6,14 +6,17 @@ export const NodeType: any = Utils.strEnumify({
     AssignmentExpression: 'AssignmentExpression',
     BinaryExpression: 'BinaryExpression',
     BlockStatement: 'BlockStatement',
+    BreakStatement: 'BreakStatement',
     CallExpression: 'CallExpression',
     CatchClause: 'CatchClause',
     ClassDeclaration: 'ClassDeclaration',
+    ContinueStatement: 'ContinueStatement',
     ExpressionStatement: 'ExpressionStatement',
     FunctionDeclaration: 'FunctionDeclaration',
     FunctionExpression: 'FunctionExpression',
     Identifier:  'Identifier',
     IfStatement:  'IfStatement',
+    LabeledStatement: 'LabeledStatement',
     Literal: 'Literal',
     LogicalExpression: 'LogicalExpression',
     MemberExpression: 'MemberExpression',

+ 67 - 0
src/node-obfuscators/LabeledStatementObfuscator.ts

@@ -0,0 +1,67 @@
+import * as estraverse from 'estraverse';
+import * as ESTree from 'estree';
+
+import { ICustomNode } from '../interfaces/custom-nodes/ICustomNode';
+import { IOptions } from '../interfaces/IOptions';
+
+import { NodeType } from '../enums/NodeType';
+
+import { AbstractNodeObfuscator } from './AbstractNodeObfuscator';
+import { IdentifierReplacer } from './replacers/IdentifierReplacer';
+import { Node } from '../node/Node';
+import { NodeUtils } from '../node/NodeUtils';
+
+/**
+ * replaces:
+ *     try {} catch (e) { console.log(e); };
+ *
+ * on:
+ *     try {} catch (_0x12d45f) { console.log(_0x12d45f); };
+ *
+ */
+export class LabeledStatementObfuscator extends AbstractNodeObfuscator {
+    /**
+     * @type {IdentifierReplacer}
+     */
+    private identifierReplacer: IdentifierReplacer;
+
+    /**
+     * @param nodes
+     * @param options
+     */
+    constructor(nodes: Map <string, ICustomNode>, options: IOptions) {
+        super(nodes, options);
+
+        this.identifierReplacer = new IdentifierReplacer(this.nodes, this.options);
+    }
+
+    /**
+     * @param labeledStatementNode
+     */
+    public obfuscateNode (labeledStatementNode: ESTree.LabeledStatement): void {
+        this.storeLabeledStatementName(labeledStatementNode);
+        this.replaceLabeledStatementName(labeledStatementNode);
+    }
+
+    /**
+     * @param labeledStatementNode
+     */
+    private storeLabeledStatementName (labeledStatementNode: ESTree.LabeledStatement): void {
+        NodeUtils.typedReplace(labeledStatementNode.label, NodeType.Identifier, {
+            enter: (node: ESTree.Identifier) => this.identifierReplacer.storeNames(node.name)
+        });
+    }
+
+    /**
+     * @param labeledStatementNode
+     */
+    private replaceLabeledStatementName (labeledStatementNode: ESTree.LabeledStatement): void {
+        estraverse.replace(labeledStatementNode, {
+            enter: (node: ESTree.Node, parentNode: ESTree.Node): any => {
+                if (Node.isLabelIdentifierNode(node, parentNode)) {
+                    node.name = this.identifierReplacer.replace(node.name);
+                }
+            }
+        });
+    }
+}

+ 42 - 1
src/node/Node.ts

@@ -35,6 +35,14 @@ export class Node {
         return node.type === NodeType.BlockStatement;
     }
 
+    /**
+     * @param node
+     * @returns {boolean}
+     */
+    public static isBreakStatementNode (node: ESTree.Node): node is ESTree.BreakStatement {
+        return node.type === NodeType.BreakStatement;
+    }
+
     /**
      * @param node
      * @returns {boolean}
@@ -43,6 +51,14 @@ export class Node {
         return node.type === NodeType.CallExpression;
     }
 
+    /**
+     * @param node
+     * @returns {boolean}
+     */
+    public static isContinueStatementNode (node: ESTree.Node): node is ESTree.ContinueStatement {
+        return node.type === NodeType.ContinueStatement;
+    }
+
     /**
      * @param node
      * @returns {boolean}
@@ -75,6 +91,29 @@ export class Node {
         return node.type === NodeType.Identifier;
     }
 
+    /**
+     * @param node
+     * @param parentNode
+     * @returns {boolean}
+     */
+    public static isLabelIdentifierNode (node: ESTree.Node, parentNode: ESTree.Node): node is ESTree.Identifier {
+        const parentNodeIsLabeledStatementNode: boolean = Node.isLabeledStatementNode(parentNode) && parentNode.label === node;
+        const parentNodeIsContinueStatementNode: boolean = Node.isContinueStatementNode(parentNode) && parentNode.label === node;
+        const parentNodeIsBreakStatementNode: boolean = Node.isBreakStatementNode(parentNode) && parentNode.label === node;
+
+        return parentNodeIsLabeledStatementNode ||
+            parentNodeIsContinueStatementNode ||
+            parentNodeIsBreakStatementNode;
+    }
+
+    /**
+     * @param node
+     * @returns {boolean}
+     */
+    public static isLabeledStatementNode (node: ESTree.Node): node is ESTree.LabeledStatement {
+        return node.type === NodeType.LabeledStatement;
+    }
+
     /**
      * @param node
      * @returns {boolean}
@@ -134,7 +173,9 @@ export class Node {
             parentNode.property === node
         );
 
-        return !parentNodeIsPropertyNode && !parentNodeIsMemberExpressionNode;
+        return !parentNodeIsPropertyNode &&
+            !parentNodeIsMemberExpressionNode &&
+            !Node.isLabelIdentifierNode(node, parentNode);
     }
 
     /**

+ 8 - 0
test/fixtures/node-obfuscators/labeled-statement-obfuscator/labeled-statement-obfuscator.js

@@ -0,0 +1,8 @@
+function foo (label) {
+    label: {
+        for (var i = 0; i < 1000; i++) {
+            break label;
+            continue label;
+        }
+    }
+}

+ 1 - 1
test/functional-tests/node-obfuscators/CatchClauseObfuscator.spec.ts

@@ -9,7 +9,7 @@ import { JavaScriptObfuscator } from '../../../src/JavaScriptObfuscator';
 const assert: Chai.AssertStatic = require('chai').assert;
 
 describe('CatchClauseObfuscator', () => {
-    describe('obfuscateNode (catchClauseNode: ICatchClauseNode): void', () => {
+    describe('obfuscateNode (catchClauseNode: ESTree.CatchClause): void', () => {
         const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
             readFileAsString('./test/fixtures/node-obfuscators/catch-clause-obfuscator/catch-clause-obfuscator.js'),
             Object.assign({}, NO_CUSTOM_NODES_PRESET)

+ 50 - 0
test/functional-tests/node-obfuscators/LabeledStatementObfuscator.spec.ts

@@ -0,0 +1,50 @@
+import { IObfuscationResult } from '../../../src/interfaces/IObfuscationResult';
+
+import { NO_CUSTOM_NODES_PRESET } from '../../../src/preset-options/NoCustomNodesPreset';
+
+import { readFileAsString } from '../../helpers/readFileAsString';
+
+import { JavaScriptObfuscator } from '../../../src/JavaScriptObfuscator';
+
+const assert: Chai.AssertStatic = require('chai').assert;
+
+describe('LabeledStatementObfuscator', () => {
+    describe('obfuscateNode (labeledStatementNode: ESTree.LabeledStatement): void', () => {
+        const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
+            readFileAsString('./test/fixtures/node-obfuscators/labeled-statement-obfuscator/labeled-statement-obfuscator.js'),
+            Object.assign({}, NO_CUSTOM_NODES_PRESET)
+        );
+        const obfuscatedCode: string = obfuscationResult.getObfuscatedCode();
+        const labeledStatementRegExp: RegExp = /(_0x([a-z0-9]){4,6}): *\{/;
+        const continueStatementRegExp: RegExp = /continue *(_0x([a-z0-9]){4,6});/;
+        const breakStatementRegExp: RegExp = /break *(_0x([a-z0-9]){4,6});/;
+
+        it('should obfuscate `labeledStatement` identifier', () => {
+            assert.match(obfuscatedCode, labeledStatementRegExp);
+        });
+
+        it('should obfuscate `continueStatement` identifier', () => {
+            assert.match(obfuscatedCode, continueStatementRegExp);
+        });
+
+        it('should obfuscate `breakStatement` identifier', () => {
+            assert.match(obfuscatedCode, breakStatementRegExp);
+        });
+
+        it('`labeledStatement` identifier name and `labeledStatement` body `breakStatement` should be same', () => {
+            const firstMatchArray: RegExpMatchArray|null = obfuscatedCode.match(labeledStatementRegExp);
+            const secondMatchArray: RegExpMatchArray|null = obfuscatedCode.match(continueStatementRegExp);
+            const thirdMatchArray: RegExpMatchArray|null = obfuscatedCode.match(breakStatementRegExp);
+
+            const firstMatch: string|undefined = firstMatchArray ? firstMatchArray[1] : undefined;
+            const secondMatch: string|undefined = secondMatchArray ? secondMatchArray[1] : undefined;
+            const thirdMatch: string|undefined = thirdMatchArray ? thirdMatchArray[1] : undefined;
+
+            assert.isOk(firstMatch);
+            assert.isOk(secondMatch);
+            assert.isOk(thirdMatchArray);
+            assert.equal(firstMatch, secondMatch);
+            assert.equal(secondMatch, thirdMatch);
+        });
+    });
+});

+ 1 - 0
test/index.spec.ts

@@ -31,6 +31,7 @@ import './functional-tests/custom-nodes/string-array-nodes/StringArrayRotateFunc
 import './functional-tests/custom-nodes/string-array-nodes/StringArrayNode.spec';
 import './functional-tests/node-obfuscators/CatchClauseObfuscator.spec';
 import './functional-tests/node-obfuscators/FunctionObfuscator.spec';
+import './functional-tests/node-obfuscators/LabeledStatementObfuscator.spec';
 import './functional-tests/node-obfuscators/LiteralObfuscator.spec';
 import './functional-tests/node-obfuscators/MemberExpressionObfuscator.spec';
 import './functional-tests/node-obfuscators/MethodDefinitionObfuscator.spec';