diff --git a/dist/index.js b/dist/index.js index 16947d40..2fbe118c 100644 --- a/dist/index.js +++ b/dist/index.js @@ -361,6 +361,7 @@ var NodeUtils = function () { value = parentNode || node; } node['parentNode'] = value; + node['obfuscated'] = false; } }); } @@ -383,14 +384,14 @@ var NodeUtils = function () { var traverseType = arguments.length <= 3 || arguments[3] === undefined ? 'traverse' : arguments[3]; estraverse[traverseType](node, { - enter: function enter(node) { + enter: function enter(node, parentNode) { if (node.type === nodeType && visitor.enter) { - visitor.enter(node); + visitor.enter(node, parentNode); } }, - leave: function leave(node) { + leave: function leave(node, parentNode) { if (node.type === nodeType && visitor.leave) { - visitor.leave(node); + visitor.leave(node, parentNode); } } }); @@ -445,7 +446,8 @@ var Nodes = function () { return { 'type': NodeType_1.NodeType.Program, 'body': bodyNode, - 'sourceType': 'script' + 'sourceType': 'script', + 'obfuscated': false }; } }, { @@ -458,6 +460,11 @@ var Nodes = function () { value: function isBlockStatementNode(node) { return node.type === NodeType_1.NodeType.BlockStatement; } + }, { + key: "isCallExpressionNode", + value: function isCallExpressionNode(node) { + return node.type === NodeType_1.NodeType.CallExpression; + } }, { key: "isFunctionDeclarationNode", value: function isFunctionDeclarationNode(node) { @@ -757,15 +764,9 @@ var IdentifierReplacer = function (_AbstractReplacer_1$A) { _inherits(IdentifierReplacer, _AbstractReplacer_1$A); function IdentifierReplacer() { - var _ref; - _classCallCheck(this, IdentifierReplacer); - for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; - } - - var _this = _possibleConstructorReturn(this, (_ref = IdentifierReplacer.__proto__ || Object.getPrototypeOf(IdentifierReplacer)).call.apply(_ref, [this].concat(args))); + var _this = _possibleConstructorReturn(this, (IdentifierReplacer.__proto__ || Object.getPrototypeOf(IdentifierReplacer)).apply(this, arguments)); _this.namesMap = new Map(); return _this; @@ -1631,15 +1632,9 @@ var ConsoleOutputDisableExpressionNode = function (_AbstractCustomNode_) { _inherits(ConsoleOutputDisableExpressionNode, _AbstractCustomNode_); function ConsoleOutputDisableExpressionNode() { - var _ref; - _classCallCheck(this, ConsoleOutputDisableExpressionNode); - for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; - } - - var _this = _possibleConstructorReturn(this, (_ref = ConsoleOutputDisableExpressionNode.__proto__ || Object.getPrototypeOf(ConsoleOutputDisableExpressionNode)).call.apply(_ref, [this].concat(args))); + var _this = _possibleConstructorReturn(this, (ConsoleOutputDisableExpressionNode.__proto__ || Object.getPrototypeOf(ConsoleOutputDisableExpressionNode)).apply(this, arguments)); _this.appendState = AppendState_1.AppendState.BeforeObfuscation; return _this; @@ -1860,15 +1855,9 @@ var DomainLockNode = function (_AbstractCustomNode_) { _inherits(DomainLockNode, _AbstractCustomNode_); function DomainLockNode() { - var _ref; - _classCallCheck(this, DomainLockNode); - for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; - } - - var _this = _possibleConstructorReturn(this, (_ref = DomainLockNode.__proto__ || Object.getPrototypeOf(DomainLockNode)).call.apply(_ref, [this].concat(args))); + var _this = _possibleConstructorReturn(this, (DomainLockNode.__proto__ || Object.getPrototypeOf(DomainLockNode)).apply(this, arguments)); _this.appendState = AppendState_1.AppendState.BeforeObfuscation; return _this; @@ -1929,15 +1918,9 @@ var SelfDefendingUnicodeNode = function (_AbstractCustomNode_) { _inherits(SelfDefendingUnicodeNode, _AbstractCustomNode_); function SelfDefendingUnicodeNode() { - var _ref; - _classCallCheck(this, SelfDefendingUnicodeNode); - for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; - } - - var _this = _possibleConstructorReturn(this, (_ref = SelfDefendingUnicodeNode.__proto__ || Object.getPrototypeOf(SelfDefendingUnicodeNode)).call.apply(_ref, [this].concat(args))); + var _this = _possibleConstructorReturn(this, (SelfDefendingUnicodeNode.__proto__ || Object.getPrototypeOf(SelfDefendingUnicodeNode)).apply(this, arguments)); _this.appendState = AppendState_1.AppendState.AfterObfuscation; return _this; @@ -2712,9 +2695,13 @@ var FunctionObfuscator = function (_AbstractNodeObfuscat) { var _this3 = this; var replaceVisitor = { - leave: function leave(node, parentNode) { + enter: function enter(node, parentNode) { if (Nodes_1.Nodes.isReplaceableIdentifierNode(node, parentNode)) { - node.name = _this3.identifierReplacer.replace(node.name); + var newNodeName = _this3.identifierReplacer.replace(node.name); + if (node.name !== newNodeName) { + node.name = newNodeName; + node.obfuscated = true; + } } } }; @@ -2905,15 +2892,9 @@ var MethodDefinitionObfuscator = function (_AbstractNodeObfuscat) { _inherits(MethodDefinitionObfuscator, _AbstractNodeObfuscat); function MethodDefinitionObfuscator() { - var _ref; - _classCallCheck(this, MethodDefinitionObfuscator); - for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; - } - - var _this = _possibleConstructorReturn(this, (_ref = MethodDefinitionObfuscator.__proto__ || Object.getPrototypeOf(MethodDefinitionObfuscator)).call.apply(_ref, [this].concat(args))); + var _this = _possibleConstructorReturn(this, (MethodDefinitionObfuscator.__proto__ || Object.getPrototypeOf(MethodDefinitionObfuscator)).apply(this, arguments)); _this.ignoredNames = ['constructor']; return _this; @@ -3091,23 +3072,10 @@ var VariableDeclarationObfuscator = function (_AbstractNodeObfuscat) { value: function replaceVariableNames(variableDeclarationNode, variableParentNode) { var _this3 = this; - var scopeNode = variableDeclarationNode.kind === 'var' ? NodeUtils_1.NodeUtils.getBlockScopeOfNode(variableDeclarationNode) : variableParentNode, - isNodeAfterVariableDeclaratorFlag = false; + var scopeNode = variableDeclarationNode.kind === 'var' ? NodeUtils_1.NodeUtils.getBlockScopeOfNode(variableDeclarationNode) : variableParentNode; estraverse.replace(scopeNode, { enter: function enter(node, parentNode) { - if (Nodes_1.Nodes.isArrowFunctionExpressionNode(node) || Nodes_1.Nodes.isFunctionDeclarationNode(node) || Nodes_1.Nodes.isFunctionExpressionNode(node)) { - estraverse.replace(node, { - enter: function enter(node, parentNode) { - if (Nodes_1.Nodes.isReplaceableIdentifierNode(node, parentNode)) { - node.name = _this3.identifierReplacer.replace(node.name); - } - } - }); - } - if (Nodes_1.Nodes.isVariableDeclarationNode(node) && node === variableDeclarationNode) { - isNodeAfterVariableDeclaratorFlag = true; - } - if (Nodes_1.Nodes.isReplaceableIdentifierNode(node, parentNode) && isNodeAfterVariableDeclaratorFlag) { + if (!node.obfuscated && Nodes_1.Nodes.isReplaceableIdentifierNode(node, parentNode)) { node.name = _this3.identifierReplacer.replace(node.name); } } diff --git a/src/NodeUtils.ts b/src/NodeUtils.ts index cf83cecf..c0dc25e4 100644 --- a/src/NodeUtils.ts +++ b/src/NodeUtils.ts @@ -148,6 +148,7 @@ export class NodeUtils { } node['parentNode'] = value; + node['obfuscated'] = false; } }); } @@ -186,18 +187,18 @@ export class NodeUtils { public static typedTraverse ( node: ESTree.Node, nodeType: string, - visitor: {enter?: (node: ESTree.Node) => void, leave?: (node: ESTree.Node) => void}, + visitor: estraverse.Visitor, traverseType: string = 'traverse' ): void { (estraverse)[traverseType](node, { - enter: (node: ESTree.Node): any => { + enter: (node: ESTree.Node, parentNode: ESTree.Node): any => { if (node.type === nodeType && visitor.enter) { - visitor.enter(node); + visitor.enter(node, parentNode); } }, - leave: (node: ESTree.Node): any => { + leave: (node: ESTree.Node, parentNode: ESTree.Node): any => { if (node.type === nodeType && visitor.leave) { - visitor.leave(node); + visitor.leave(node, parentNode); } } }); diff --git a/src/Nodes.ts b/src/Nodes.ts index 930e6063..c1fea144 100644 --- a/src/Nodes.ts +++ b/src/Nodes.ts @@ -13,7 +13,8 @@ export class Nodes { return { 'type': NodeType.Program, 'body': bodyNode, - 'sourceType': 'script' + 'sourceType': 'script', + 'obfuscated': false }; } @@ -33,6 +34,14 @@ export class Nodes { return node.type === NodeType.BlockStatement; } + /** + * @param node + * @returns {boolean} + */ + public static isCallExpressionNode (node: ESTree.Node): node is ESTree.CallExpression { + return node.type === NodeType.CallExpression; + } + /** * @param node * @returns {boolean} diff --git a/src/declarations/ESTree.d.ts b/src/declarations/ESTree.d.ts index 3fa92514..8671ff59 100644 --- a/src/declarations/ESTree.d.ts +++ b/src/declarations/ESTree.d.ts @@ -5,6 +5,7 @@ import * as ESTree from 'estree'; declare module 'estree' { interface BaseNode { parentNode?: ESTree.Node; + obfuscated?: boolean; } interface SimpleLiteral extends ESTree.BaseNode, ESTree.BaseExpression { diff --git a/src/node-obfuscators/FunctionObfuscator.ts b/src/node-obfuscators/FunctionObfuscator.ts index 84c10816..3f046e2f 100644 --- a/src/node-obfuscators/FunctionObfuscator.ts +++ b/src/node-obfuscators/FunctionObfuscator.ts @@ -60,9 +60,14 @@ export class FunctionObfuscator extends AbstractNodeObfuscator { */ private replaceFunctionParams (functionNode: ESTree.Function): void { let replaceVisitor: estraverse.Visitor = { - leave: (node: ESTree.Node, parentNode: ESTree.Node): any => { + enter: (node: ESTree.Node, parentNode: ESTree.Node): any => { if (Nodes.isReplaceableIdentifierNode(node, parentNode)) { - node.name = this.identifierReplacer.replace(node.name); + const newNodeName: string = this.identifierReplacer.replace(node.name); + + if (node.name !== newNodeName) { + node.name = newNodeName; + node.obfuscated = true; + } } } }; diff --git a/src/node-obfuscators/VariableDeclarationObfuscator.ts b/src/node-obfuscators/VariableDeclarationObfuscator.ts index 6e79a47f..7540b477 100644 --- a/src/node-obfuscators/VariableDeclarationObfuscator.ts +++ b/src/node-obfuscators/VariableDeclarationObfuscator.ts @@ -69,30 +69,11 @@ export class VariableDeclarationObfuscator extends AbstractNodeObfuscator { private replaceVariableNames (variableDeclarationNode: ESTree.VariableDeclaration, variableParentNode: ESTree.Node): void { let scopeNode: ESTree.Node = variableDeclarationNode.kind === 'var' ? NodeUtils.getBlockScopeOfNode( variableDeclarationNode - ) : variableParentNode, - isNodeAfterVariableDeclaratorFlag: boolean = false; + ) : variableParentNode; estraverse.replace(scopeNode, { enter: (node: ESTree.Node, parentNode: ESTree.Node): any => { - if ( - Nodes.isArrowFunctionExpressionNode(node) || - Nodes.isFunctionDeclarationNode(node) || - Nodes.isFunctionExpressionNode(node) - ) { - estraverse.replace(node, { - enter: (node: ESTree.Node, parentNode: ESTree.Node): any => { - if (Nodes.isReplaceableIdentifierNode(node, parentNode)) { - node.name = this.identifierReplacer.replace(node.name); - } - } - }); - } - - if (Nodes.isVariableDeclarationNode(node) && node === variableDeclarationNode) { - isNodeAfterVariableDeclaratorFlag = true; - } - - if (Nodes.isReplaceableIdentifierNode(node, parentNode) && isNodeAfterVariableDeclaratorFlag) { + if (!node.obfuscated && Nodes.isReplaceableIdentifierNode(node, parentNode)) { node.name = this.identifierReplacer.replace(node.name); } } diff --git a/test/functional-tests/node-obfuscators/FunctionObfuscator.spec.ts b/test/functional-tests/node-obfuscators/FunctionObfuscator.spec.ts new file mode 100644 index 00000000..fa05728d --- /dev/null +++ b/test/functional-tests/node-obfuscators/FunctionObfuscator.spec.ts @@ -0,0 +1,20 @@ +import { IObfuscationResult } from "../../../src/interfaces/IObfuscationResult"; + +import { NO_CUSTOM_NODES_PRESET } from "../../../src/preset-options/NoCustomNodesPreset"; + +import { JavaScriptObfuscator } from "../../../src/JavaScriptObfuscator"; + +const assert: Chai.AssertStatic = require('chai').assert; + +describe('FunctionObfuscator', () => { + describe('obfuscation of identifiers of FunctionDeclaration and FunctionExpression node body', () => { + it('should replace identifier name with obfuscated one', () => { + let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + `var test = 'test';`, + Object.assign({}, NO_CUSTOM_NODES_PRESET) + ); + + assert.match(obfuscationResult.getObfuscatedCode(), /^var *test *= *'\\x74\\x65\\x73\\x74';$/); + }); + }); +}); diff --git a/test/functional-tests/node-obfuscators/VariableDeclarationObfuscator.spec.ts b/test/functional-tests/node-obfuscators/VariableDeclarationObfuscator.spec.ts index cfbf7d10..2a850310 100644 --- a/test/functional-tests/node-obfuscators/VariableDeclarationObfuscator.spec.ts +++ b/test/functional-tests/node-obfuscators/VariableDeclarationObfuscator.spec.ts @@ -82,7 +82,65 @@ describe('VariableDeclarationObfuscator', () => { }); it('should not obfuscate variable call (`identifier` node) before variable declaration', () => { - assert.match(obfuscationResult.getObfuscatedCode(), /console\['\\x6c\\x6f\\x67'\]\(abc\);/); + assert.match(obfuscationResult.getObfuscatedCode(), /console\['\\x6c\\x6f\\x67'\]\(_0x([a-z0-9]){5,6}\);/); + }); + }); + + describe(`variable calls before variable declaration when function param has the same name as variables name`, () => { + let obfuscationResult: IObfuscationResult, + functionParamIdentifierName: string|null, + innerFunctionParamIdentifierName: string|null, + constructorIdentifierName: string|null, + objectIdentifierName: string|null, + variableDeclarationIdentifierName: string|null; + + beforeEach(() => { + obfuscationResult = JavaScriptObfuscator.obfuscate( + ` + (function () { + function foo (t, e) { + return function () { + function baz (t) { + console.log(t); + } + + return {t: t}; + var t; + }(); + } + })(); + `, + Object.assign({}, NO_CUSTOM_NODES_PRESET) + ); + }); + + it('blablabla', () => { + const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); + const functionParamIdentifierMatch: RegExpMatchArray|null = obfuscatedCode + .match(/function *_0x[a-z0-9]{5,6} *\((_0x[a-z0-9]{5,6})\,(_0x[a-z0-9]{5,6})\) *\{/); + const innerFunctionParamIdentifierMatch: RegExpMatchArray|null = obfuscatedCode + .match(/function _0x[a-z0-9]{5,6} *\((_0x[a-z0-9]{5,6})\) *\{/); + const constructorIdentifierMatch: RegExpMatchArray|null = obfuscatedCode + .match(/console\['\\x6c\\x6f\\x67'\]\((_0x[a-z0-9]{5,6})\)/); + const objectIdentifierMatch: RegExpMatchArray|null = obfuscatedCode + .match(/return\{'\\x74':(_0x[a-z0-9]{5,6})\}/); + const variableDeclarationIdentifierMatch: RegExpMatchArray|null = obfuscatedCode + .match(/var *(_0x[a-z0-9]{5,6});/); + + functionParamIdentifierName = (functionParamIdentifierMatch)[1]; + innerFunctionParamIdentifierName = (innerFunctionParamIdentifierMatch)[1]; + constructorIdentifierName = (constructorIdentifierMatch)[1]; + objectIdentifierName = (objectIdentifierMatch)[1]; + variableDeclarationIdentifierName = (variableDeclarationIdentifierMatch)[1]; + + assert.notEqual(functionParamIdentifierName, constructorIdentifierName); + assert.notEqual(functionParamIdentifierName, innerFunctionParamIdentifierName); + + assert.notEqual(functionParamIdentifierName, objectIdentifierName); + assert.notEqual(functionParamIdentifierName, variableDeclarationIdentifierName); + + assert.equal(innerFunctionParamIdentifierName, constructorIdentifierName); + assert.equal(variableDeclarationIdentifierName, objectIdentifierName); }); }); diff --git a/test/mocks/NodeMocks.ts b/test/mocks/NodeMocks.ts index 499b52c2..916b8f8b 100644 --- a/test/mocks/NodeMocks.ts +++ b/test/mocks/NodeMocks.ts @@ -12,7 +12,8 @@ export class NodeMocks { return { type: NodeType.Program, body: bodyNodes, - sourceType: 'script' + sourceType: 'script', + obfuscated: false }; } @@ -23,7 +24,8 @@ export class NodeMocks { public static getBlockStatementNode (bodyNodes: ESTree.Statement[] = []): ESTree.BlockStatement { return { type: NodeType.BlockStatement, - body: bodyNodes + body: bodyNodes, + obfuscated: false }; } @@ -35,7 +37,8 @@ export class NodeMocks { return { type: NodeType.CatchClause, param: NodeMocks.getIdentifierNode('err'), - body: NodeMocks.getBlockStatementNode(bodyNodes) + body: NodeMocks.getBlockStatementNode(bodyNodes), + obfuscated: false }; } @@ -51,7 +54,8 @@ export class NodeMocks { return { type: NodeType.CallExpression, callee: callee, - arguments: args + arguments: args, + obfuscated: false }; } @@ -64,7 +68,8 @@ export class NodeMocks { ): ESTree.ExpressionStatement { return { type: NodeType.ExpressionStatement, - expression: expression + expression: expression, + obfuscated: false }; } @@ -84,7 +89,8 @@ export class NodeMocks { id: NodeMocks.getIdentifierNode(functionName), params: params, body: blockStatementNode, - generator: false + generator: false, + obfuscated: false }; } @@ -98,9 +104,11 @@ export class NodeMocks { test: { type: 'Literal', value: true, - raw: 'true' + raw: 'true', + obfuscated: false }, - consequent: blockStatementNode + consequent: blockStatementNode, + obfuscated: false }; } @@ -112,6 +120,7 @@ export class NodeMocks { return { type: NodeType.Identifier, name: identifierName, + obfuscated: false }; } @@ -127,7 +136,8 @@ export class NodeMocks { 'x-verbatim-property': { content: `'${value}'`, precedence: escodegen.Precedence.Primary - } + }, + obfuscated: false }; } @@ -144,7 +154,8 @@ export class NodeMocks { type: NodeType.MemberExpression, computed: false, object: object, - property: property + property: property, + obfuscated: false }; } @@ -160,7 +171,8 @@ export class NodeMocks { return { type: NodeType.VariableDeclaration, declarations: declarations, - kind: kind + kind: kind, + obfuscated: false }; } @@ -173,7 +185,8 @@ export class NodeMocks { return { type: NodeType.VariableDeclarator, id: id, - init: init + init: init, + obfuscated: false }; } } diff --git a/webpack.config.js b/webpack.config.js index c0fab5f2..7403c637 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -5,7 +5,8 @@ var fs = require("fs"), webpack = require('webpack'); function getLicenseText () { - return "/*\nCopyright (C) 2016 Timofey Kachalov \n\n" + fs.readFileSync('./LICENSE.BSD', 'utf8') + "\n*/"; + return "/*\nCopyright (C) 2016 Timofey Kachalov \n\n" + + fs.readFileSync('./LICENSE.BSD', 'utf8') + "\n*/"; } module.exports = {