diff --git a/dist/index.js b/dist/index.js index ac6b7fc5..609beb7b 100644 --- a/dist/index.js +++ b/dist/index.js @@ -2435,7 +2435,9 @@ var Obfuscator = Obfuscator_1 = function () { if (this.options.controlFlowFlattening) { astTree = this.transformAstTree(astTree, VisitorDirection_1.VisitorDirection.leave, this.nodeTransformersFactory(Obfuscator_1.nodeControlFlowTransformersMap)); } + console.time(); astTree = this.transformAstTree(astTree, VisitorDirection_1.VisitorDirection.enter, this.nodeTransformersFactory(Obfuscator_1.nodeObfuscatorsMap)); + console.timeEnd(); this.obfuscationEventEmitter.emit(ObfuscationEvents_1.ObfuscationEvents.AfterObfuscation, astTree, stackTraceData); return astTree; } @@ -5757,7 +5759,6 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de var tslib_1 = __webpack_require__(3); var inversify_1 = __webpack_require__(2); var ServiceIdentifiers_1 = __webpack_require__(4); -var escodegen = __webpack_require__(26); var NodeObfuscatorsReplacers_1 = __webpack_require__(20); var NodeType_1 = __webpack_require__(15); var AbstractNodeTransformer_1 = __webpack_require__(18); @@ -5777,9 +5778,7 @@ var MemberExpressionObfuscator = function (_AbstractNodeTransfor) { (0, _createClass3.default)(MemberExpressionObfuscator, [{ key: "transformNode", value: function transformNode(memberExpressionNode) { - if (Node_1.Node.isLiteralNode(memberExpressionNode.property)) { - memberExpressionNode.property = this.obfuscateLiteralProperty(memberExpressionNode.property); - } else if (Node_1.Node.isIdentifierNode(memberExpressionNode.property)) { + if (Node_1.Node.isIdentifierNode(memberExpressionNode.property)) { if (memberExpressionNode.computed) { return memberExpressionNode; } @@ -5794,24 +5793,9 @@ var MemberExpressionObfuscator = function (_AbstractNodeTransfor) { return { type: NodeType_1.NodeType.Literal, value: node.name, - raw: "'" + node.name + "'", - 'x-verbatim-property': { - content: this.stringLiteralReplacer.replace(node.name), - precedence: escodegen.Precedence.Primary - } + raw: "'" + node.name + "'" }; } - }, { - key: "obfuscateLiteralProperty", - value: function obfuscateLiteralProperty(node) { - if (typeof node.value === 'string' && !node['x-verbatim-property']) { - node['x-verbatim-property'] = { - content: this.stringLiteralReplacer.replace(node.value), - precedence: escodegen.Precedence.Primary - }; - } - return node; - } }]); return MemberExpressionObfuscator; }(AbstractNodeTransformer_1.AbstractNodeTransformer); @@ -5851,6 +5835,7 @@ var tslib_1 = __webpack_require__(3); var inversify_1 = __webpack_require__(2); var ServiceIdentifiers_1 = __webpack_require__(4); var NodeObfuscatorsReplacers_1 = __webpack_require__(20); +var NodeType_1 = __webpack_require__(15); var AbstractNodeTransformer_1 = __webpack_require__(18); var Node_1 = __webpack_require__(12); var MethodDefinitionObfuscator = MethodDefinitionObfuscator_1 = function (_AbstractNodeTransfor) { @@ -5876,8 +5861,11 @@ var MethodDefinitionObfuscator = MethodDefinitionObfuscator_1 = function (_Abstr value: function replaceMethodName(methodDefinitionNode) { if (Node_1.Node.isIdentifierNode(methodDefinitionNode.key) && !MethodDefinitionObfuscator_1.ignoredNames.includes(methodDefinitionNode.key.name) && methodDefinitionNode.computed === false) { methodDefinitionNode.computed = true; - methodDefinitionNode.key.name = this.stringLiteralReplacer.replace(methodDefinitionNode.key.name); - return; + methodDefinitionNode.key = { + type: NodeType_1.NodeType.Literal, + value: methodDefinitionNode.key.name, + raw: "'" + methodDefinitionNode.key.name + "'" + }; } } }]); @@ -6402,15 +6390,9 @@ var StringLiteralReplacer = StringLiteralReplacer_1 = function (_AbstractReplace if (this.stringLiteralHexadecimalIndexCache.has(value)) { return this.stringLiteralHexadecimalIndexCache.get(value); } - var indexOfExistingValue = this.stringArrayStorage.getKeyOf(value); - var indexOfValue = void 0; - if (indexOfExistingValue >= 0) { - indexOfValue = indexOfExistingValue; - } else { - indexOfValue = this.stringArrayStorage.getLength(); - this.stringArrayStorage.set(null, value); - } + var indexOfValue = this.stringArrayStorage.getLength(); var hexadecimalIndex = "" + Utils_1.Utils.hexadecimalPrefix + Utils_1.Utils.decToHex(indexOfValue); + this.stringArrayStorage.set(null, value); this.stringLiteralHexadecimalIndexCache.set(value, hexadecimalIndex); return hexadecimalIndex; } @@ -7651,7 +7633,7 @@ exports.StringArrayCallsWrapperTemplate = StringArrayCallsWrapperTemplate; function StringArrayRc4DecodeNodeTemplate() { - return "\n if (!{stringArrayCallsWrapperName}.atobPolyfillAppended) { \n {atobPolyfill}\n \n {stringArrayCallsWrapperName}.atobPolyfillAppended = true;\n }\n \n if (!{stringArrayCallsWrapperName}.rc4) { \n {rc4Polyfill}\n \n {stringArrayCallsWrapperName}.rc4 = rc4;\n }\n \n if (!{stringArrayCallsWrapperName}.data) {\n {stringArrayCallsWrapperName}.data = {};\n }\n\n if ({stringArrayCallsWrapperName}.data[index] === undefined) {\n if (!{stringArrayCallsWrapperName}.once) {\n {selfDefendingCode}\n \n {stringArrayCallsWrapperName}.once = true;\n }\n \n value = {stringArrayCallsWrapperName}.rc4(value, key);\n {stringArrayCallsWrapperName}.data[index] = value;\n } else {\n value = {stringArrayCallsWrapperName}.data[index];\n }\n "; + return "\n if (!{stringArrayCallsWrapperName}.atobPolyfillAppended) { \n {atobPolyfill}\n \n {stringArrayCallsWrapperName}.atobPolyfillAppended = true;\n }\n \n if (!{stringArrayCallsWrapperName}.rc4) { \n {rc4Polyfill}\n \n {stringArrayCallsWrapperName}.rc4 = rc4;\n }\n \n if (!{stringArrayCallsWrapperName}.data) {\n {stringArrayCallsWrapperName}.data = {};\n }\n\n var cacheKey = index + key;\n\n if ({stringArrayCallsWrapperName}.data[cacheKey] === undefined) {\n if (!{stringArrayCallsWrapperName}.once) {\n {selfDefendingCode}\n \n {stringArrayCallsWrapperName}.once = true;\n }\n \n value = {stringArrayCallsWrapperName}.rc4(value, key);\n {stringArrayCallsWrapperName}.data[cacheKey] = value;\n } else {\n value = {stringArrayCallsWrapperName}.data[cacheKey];\n }\n "; } exports.StringArrayRc4DecodeNodeTemplate = StringArrayRc4DecodeNodeTemplate; diff --git a/src/Obfuscator.ts b/src/Obfuscator.ts index 1b550806..354c14da 100644 --- a/src/Obfuscator.ts +++ b/src/Obfuscator.ts @@ -137,11 +137,13 @@ export class Obfuscator implements IObfuscator { } // second pass: nodes obfuscation + console.time(); astTree = this.transformAstTree( astTree, VisitorDirection.enter, this.nodeTransformersFactory(Obfuscator.nodeObfuscatorsMap) ); + console.timeEnd(); this.obfuscationEventEmitter.emit(ObfuscationEvents.AfterObfuscation, astTree, stackTraceData); diff --git a/src/node-transformers/node-obfuscators/MemberExpressionObfuscator.ts b/src/node-transformers/node-obfuscators/MemberExpressionObfuscator.ts index 1874e676..d057cb07 100644 --- a/src/node-transformers/node-obfuscators/MemberExpressionObfuscator.ts +++ b/src/node-transformers/node-obfuscators/MemberExpressionObfuscator.ts @@ -1,7 +1,6 @@ import { injectable, inject } from 'inversify'; import { ServiceIdentifiers } from '../../container/ServiceIdentifiers'; -import * as escodegen from 'escodegen'; import * as ESTree from 'estree'; import { IOptions } from '../../interfaces/options/IOptions'; @@ -38,9 +37,7 @@ export class MemberExpressionObfuscator extends AbstractNodeTransformer { * @returns {ESTree.Node} */ public transformNode (memberExpressionNode: ESTree.MemberExpression): ESTree.Node { - if (Node.isLiteralNode(memberExpressionNode.property)) { - memberExpressionNode.property = this.obfuscateLiteralProperty(memberExpressionNode.property); - } else if (Node.isIdentifierNode(memberExpressionNode.property)) { + if (Node.isIdentifierNode(memberExpressionNode.property)) { if (memberExpressionNode.computed) { return memberExpressionNode; } @@ -57,11 +54,13 @@ export class MemberExpressionObfuscator extends AbstractNodeTransformer { * object.identifier = 1; * * on: - * object[_0x23d45[25]] = 1; + * object['identifier'] = 1; * * and skip: * object[identifier] = 1; * + * Literal node will be obfuscated by LiteralObfuscator + * * @param node * @returns {ESTree.Literal} */ @@ -69,32 +68,7 @@ export class MemberExpressionObfuscator extends AbstractNodeTransformer { return { type: NodeType.Literal, value: node.name, - raw: `'${node.name}'`, - 'x-verbatim-property': { - content: this.stringLiteralReplacer.replace(node.name), - precedence: escodegen.Precedence.Primary - } + raw: `'${node.name}'` }; } - - /** - * replaces: - * object['literal'] = 1; - * - * on: - * object[_0x23d45[25]] = 1; - * - * @param node - * @returns {ESTree.Literal} - */ - private obfuscateLiteralProperty (node: ESTree.Literal): ESTree.Literal { - if (typeof node.value === 'string' && !node['x-verbatim-property']) { - node['x-verbatim-property'] = { - content: this.stringLiteralReplacer.replace(node.value), - precedence: escodegen.Precedence.Primary - }; - } - - return node; - } } diff --git a/src/node-transformers/node-obfuscators/MethodDefinitionObfuscator.ts b/src/node-transformers/node-obfuscators/MethodDefinitionObfuscator.ts index 4e478301..1d99a3e3 100644 --- a/src/node-transformers/node-obfuscators/MethodDefinitionObfuscator.ts +++ b/src/node-transformers/node-obfuscators/MethodDefinitionObfuscator.ts @@ -7,6 +7,7 @@ import { IOptions } from '../../interfaces/options/IOptions'; import { IObfuscatorReplacer } from '../../interfaces/node-transformers/IObfuscatorReplacer'; import { NodeObfuscatorsReplacers } from '../../enums/container/NodeObfuscatorsReplacers'; +import { NodeType } from '../../enums/NodeType'; import { AbstractNodeTransformer } from '../AbstractNodeTransformer'; import { Node } from '../../node/Node'; @@ -16,7 +17,9 @@ import { Node } from '../../node/Node'; * foo () { //... }; * * on: - * [_0x9a4e('0x0')] { //... }; + * ['foo'] { //... }; + * + * Literal node will be obfuscated by LiteralObfuscator */ @injectable() export class MethodDefinitionObfuscator extends AbstractNodeTransformer { @@ -55,17 +58,30 @@ export class MethodDefinitionObfuscator extends AbstractNodeTransformer { } /** + * replaces: + * object.identifier = 1; + * + * on: + * object['identifier'] = 1; + * + * and skip: + * object[identifier] = 1; + * Literal node will be obfuscated by LiteralObfuscator + * * @param methodDefinitionNode */ private replaceMethodName (methodDefinitionNode: ESTree.MethodDefinition): void { if ( - Node.isIdentifierNode(methodDefinitionNode.key) && !MethodDefinitionObfuscator.ignoredNames.includes(methodDefinitionNode.key.name) && + Node.isIdentifierNode(methodDefinitionNode.key) && + !MethodDefinitionObfuscator.ignoredNames.includes(methodDefinitionNode.key.name) && methodDefinitionNode.computed === false ) { methodDefinitionNode.computed = true; - methodDefinitionNode.key.name = this.stringLiteralReplacer.replace(methodDefinitionNode.key.name); - - return; + methodDefinitionNode.key = { + type: NodeType.Literal, + value: methodDefinitionNode.key.name, + raw: `'${methodDefinitionNode.key.name}'` + }; } } } diff --git a/src/node-transformers/node-obfuscators/replacers/StringLiteralReplacer.ts b/src/node-transformers/node-obfuscators/replacers/StringLiteralReplacer.ts index c47d9a49..c7eebd25 100644 --- a/src/node-transformers/node-obfuscators/replacers/StringLiteralReplacer.ts +++ b/src/node-transformers/node-obfuscators/replacers/StringLiteralReplacer.ts @@ -100,19 +100,10 @@ export class StringLiteralReplacer extends AbstractReplacer { return this.stringLiteralHexadecimalIndexCache.get(value); } - const indexOfExistingValue: number = this.stringArrayStorage.getKeyOf(value); - - let indexOfValue: number; - - if (indexOfExistingValue >= 0) { - indexOfValue = indexOfExistingValue; - } else { - indexOfValue = this.stringArrayStorage.getLength(); - this.stringArrayStorage.set(null, value); - } - + const indexOfValue: number = this.stringArrayStorage.getLength(); const hexadecimalIndex: string = `${Utils.hexadecimalPrefix}${Utils.decToHex(indexOfValue)}`; + this.stringArrayStorage.set(null, value); this.stringLiteralHexadecimalIndexCache.set(value, hexadecimalIndex); return hexadecimalIndex; diff --git a/src/templates/custom-nodes/string-array-nodes/string-array-calls-wrapper/StringArrayRC4DecodeNodeTemplate.ts b/src/templates/custom-nodes/string-array-nodes/string-array-calls-wrapper/StringArrayRC4DecodeNodeTemplate.ts index 12bd11e2..9d649774 100644 --- a/src/templates/custom-nodes/string-array-nodes/string-array-calls-wrapper/StringArrayRC4DecodeNodeTemplate.ts +++ b/src/templates/custom-nodes/string-array-nodes/string-array-calls-wrapper/StringArrayRC4DecodeNodeTemplate.ts @@ -19,7 +19,9 @@ export function StringArrayRc4DecodeNodeTemplate (): string { {stringArrayCallsWrapperName}.data = {}; } - if ({stringArrayCallsWrapperName}.data[index] === undefined) { + var cacheKey = index + key; + + if ({stringArrayCallsWrapperName}.data[cacheKey] === undefined) { if (!{stringArrayCallsWrapperName}.once) { {selfDefendingCode} @@ -27,9 +29,9 @@ export function StringArrayRc4DecodeNodeTemplate (): string { } value = {stringArrayCallsWrapperName}.rc4(value, key); - {stringArrayCallsWrapperName}.data[index] = value; + {stringArrayCallsWrapperName}.data[cacheKey] = value; } else { - value = {stringArrayCallsWrapperName}.data[index]; + value = {stringArrayCallsWrapperName}.data[cacheKey]; } `; } diff --git a/test/dev/dev.ts b/test/dev/dev.ts index 82c756f6..250b8f6d 100644 --- a/test/dev/dev.ts +++ b/test/dev/dev.ts @@ -1,4 +1,5 @@ 'use strict'; +import { NO_CUSTOM_NODES_PRESET } from '../../src/options/presets/NoCustomNodes'; if (!(global)._babelPolyfill) { require('babel-polyfill'); @@ -9,53 +10,13 @@ if (!(global)._babelPolyfill) { let obfuscatedCode: string = JavaScriptObfuscator.obfuscate( ` - (function(){ - var result = 1, - term1 = 0, - term2 = 1, - i = 1; - while(i < 10) - { - var test = 10; - result = term1 + term2; - console.log(result); - term1 = term2; - term2 = result; - i++; - } - - console.log(test); - - var test = function (test) { - console.log(test); - - if (true) { - var test = 5 - } - - return test; - } - - console.log(test(1)); - - function test2 (abc) { - function test1 () { - console.log('inside', abc.item); - } - - console.log('ั‚ะตัั‚', abc); - - var abc = {}; - - return abc.item = 15, test1(); - }; - })(); + var test = console.log; `, { + ...NO_CUSTOM_NODES_PRESET, compact: false, - controlFlowFlattening: true, - controlFlowFlatteningThreshold: 1, - disableConsoleOutput: false + stringArray: true, + stringArrayThreshold: 1 } ).getObfuscatedCode(); diff --git a/test/functional-tests/node-transformers/node-obfuscators/LiteralObfuscator.spec.ts b/test/functional-tests/node-transformers/node-obfuscators/LiteralObfuscator.spec.ts index 2918065a..5c378bda 100644 --- a/test/functional-tests/node-transformers/node-obfuscators/LiteralObfuscator.spec.ts +++ b/test/functional-tests/node-transformers/node-obfuscators/LiteralObfuscator.spec.ts @@ -38,6 +38,27 @@ describe('LiteralObfuscator', () => { assert.match(obfuscationResult.getObfuscatedCode(), /var *test *= *_0x([a-z0-9]){4}\('0x0'\);/); }); + it('should create only one item in string array for same literal node values', () => { + let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + ` + var test = 'test'; + var test = 'test'; + object.test(); + `, + { + ...NO_CUSTOM_NODES_PRESET, + stringArray: true, + stringArrayThreshold: 1 + } + ); + + assert.match( + obfuscationResult.getObfuscatedCode(), + /^var *_0x([a-z0-9]){4} *= *\['\\x74\\x65\\x73\\x74'\];/ + ); + assert.match(obfuscationResult.getObfuscatedCode(), /var *test *= *_0x([a-z0-9]){4}\('0x0'\);/); + }); + it('should replace literal node value with raw value from string array if `unicodeEscapeSequence` is disabled', () => { let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( `var test = 'test';`,