瀏覽代碼

rc4 encoding runtime error fix and performance boost

sanex3339 8 年之前
父節點
當前提交
8c5d323752

+ 13 - 31
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;
 

+ 2 - 0
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);
 

+ 5 - 31
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;
-    }
 }

+ 21 - 5
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}'`
+            };
         }
     }
 }

+ 2 - 11
src/node-transformers/node-obfuscators/replacers/StringLiteralReplacer.ts

@@ -100,19 +100,10 @@ export class StringLiteralReplacer extends AbstractReplacer {
             return <string>this.stringLiteralHexadecimalIndexCache.get(value);
         }
 
-        const indexOfExistingValue: number = <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;

+ 5 - 3
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];
         }
     `;
 }

+ 5 - 44
test/dev/dev.ts

@@ -1,4 +1,5 @@
 'use strict';
+import { NO_CUSTOM_NODES_PRESET } from '../../src/options/presets/NoCustomNodes';
 
 if (!(<any>global)._babelPolyfill) {
     require('babel-polyfill');
@@ -9,53 +10,13 @@ if (!(<any>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();
 

+ 21 - 0
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';`,