From 225bbfd6b448bc8564b362f10db54258614e609d Mon Sep 17 00:00:00 2001 From: sanex3339 Date: Tue, 1 Nov 2016 19:18:15 +0300 Subject: [PATCH] custom node templates rework --- dist/index.js | 15 ++++++--- .../ConsoleOutputDisableExpressionNode.ts | 7 +++- .../replacers/StringLiteralReplacer.ts | 10 +++++- .../ConsoleOutputDisableExpressionTemplate.ts | 16 ++++++---- .../DomainLockNodeTemplate.ts | 8 ++--- .../SelfDefendingTemplate.ts | 8 ++--- .../LiteralObfuscator.spec.ts | 32 +++++++++++++++++-- .../DomainLockNodeTemplate.spec.ts | 2 +- 8 files changed, 73 insertions(+), 25 deletions(-) diff --git a/dist/index.js b/dist/index.js index dd17c7da..08b64321 100644 --- a/dist/index.js +++ b/dist/index.js @@ -988,7 +988,7 @@ var StringLiteralReplacer = function (_AbstractReplacer_1$A) { _createClass(StringLiteralReplacer, [{ key: 'replace', value: function replace(nodeValue) { - var replaceWithUnicodeArrayFlag = Math.random() <= this.options.unicodeArrayThreshold; + var replaceWithUnicodeArrayFlag = nodeValue.length > StringLiteralReplacer.minimumLengthForUnicodeArray && Math.random() <= this.options.unicodeArrayThreshold; if (this.options.unicodeArray && replaceWithUnicodeArrayFlag) { return this.replaceStringLiteralWithUnicodeArrayCall(nodeValue); } @@ -1037,6 +1037,7 @@ var StringLiteralReplacer = function (_AbstractReplacer_1$A) { return StringLiteralReplacer; }(AbstractReplacer_1.AbstractReplacer); +StringLiteralReplacer.minimumLengthForUnicodeArray = 2; StringLiteralReplacer.rc4Keys = Utils_1.Utils.getRandomGenerator().n(function () { return Utils_1.Utils.getRandomGenerator().string({ length: 4 }); }, 50); @@ -1803,11 +1804,13 @@ function _possibleConstructorReturn(self, call) { if (!self) { throw new Referen 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; } +__webpack_require__(8); var AppendState_1 = __webpack_require__(4); var ConsoleOutputDisableExpressionTemplate_1 = __webpack_require__(64); var AbstractCustomNode_1 = __webpack_require__(6); var CustomNodeAppender_1 = __webpack_require__(15); var NodeUtils_1 = __webpack_require__(1); +var Utils_1 = __webpack_require__(0); var ConsoleOutputDisableExpressionNode = function (_AbstractCustomNode_) { _inherits(ConsoleOutputDisableExpressionNode, _AbstractCustomNode_); @@ -1829,7 +1832,9 @@ var ConsoleOutputDisableExpressionNode = function (_AbstractCustomNode_) { }, { key: 'getNodeStructure', value: function getNodeStructure() { - return NodeUtils_1.NodeUtils.convertCodeToStructure(ConsoleOutputDisableExpressionTemplate_1.ConsoleOutputDisableExpressionTemplate()); + return NodeUtils_1.NodeUtils.convertCodeToStructure(ConsoleOutputDisableExpressionTemplate_1.ConsoleOutputDisableExpressionTemplate().formatUnicorn({ + consoleLogDisableFunctionName: Utils_1.Utils.getRandomVariableName() + })); } }]); @@ -3941,7 +3946,7 @@ exports.Rc4Template = Rc4Template; "use strict"; function ConsoleOutputDisableExpressionTemplate() { - return "\n (function () {\n var getGlobal = function () {\n if (typeof self !== 'undefined') { return self; }\n if (typeof window !== 'undefined') { return window; }\n if (typeof global !== 'undefined') { return global; }\n };\n \n if (getGlobal().firstRun) {\n return false;\n }\n \n getGlobal().firstRun = true;\n \n var _ = '(\x04\x06\x03\x05[]' + '[\"filter\"][\"\x07tructor\"]' + '(\"return this\")()' + '.' + '\x03;\x06\x02\x05\x04};' + '_\x03.log\x01.in' + 'fo\x01.' + 'war' + 'n\x01.er' + 'r' + 'or\x01})();' + '\x01\x05_\x02;' + '_\x03\x02function' + '\x03\x07ole\x04\x02 ()' + '{\x05 = \x06var ' + '_\x07cons', \n Y, \n $;\n \n for (Y in $ = \"\x07\x06\x05\x04\x03\x02\x01\") {\n var arr = _.split($[Y]);\n _ = arr.join(arr.pop());\n }\n \n [][\"filter\"][\"constructor\"](_)();\n })()\n "; + return "\n var {consoleLogDisableFunctionName} = function () {\n var getGlobal = function () {\n if (typeof self !== 'undefined') { return self; }\n if (typeof window !== 'undefined') { return window; }\n if (typeof global !== 'undefined') { return global; }\n };\n \n if (getGlobal().fetchPolyfillDisabledFlag) {\n return;\n }\n \n getGlobal().fetchPolyfillDisabledFlag = true;\n \n var _ = '(\x04\x06\x03\x05[]' + '[\"filter\"][\"\x07tructor\"]' + '(\"return this\")()' + '.' + '\x03;\x06\x02\x05\x04};' + '_\x03.log\x01.in' + 'fo\x01.' + 'war' + 'n\x01.er' + 'r' + 'or\x01})();' + '\x01\x05_\x02;' + '_\x03\x02function' + '\x03\x07ole\x04\x02 ()' + '{\x05 = \x06var ' + '_\x07cons', \n Y, \n $;\n \n for (Y in $ = \"\x07\x06\x05\x04\x03\x02\x01\") {\n var arr = _.split($[Y]);\n _ = arr.join(arr.pop());\n }\n \n [][\"filter\"][\"constructor\"](_)();\n };\n \n {consoleLogDisableFunctionName}();\n "; } exports.ConsoleOutputDisableExpressionTemplate = ConsoleOutputDisableExpressionTemplate; @@ -3990,7 +3995,7 @@ exports.DebugProtectionFunctionTemplate = DebugProtectionFunctionTemplate; "use strict"; function DomainLockNodeTemplate() { - return "\n var {domainLockFunctionName} = function () {\n var getGlobal = function () {\n if (typeof self !== 'undefined') { return self; }\n if (typeof window !== 'undefined') { return window; }\n if (typeof global !== 'undefined') { return global; }\n };\n \n var func = function () { \n return {\n key: 'item',\n value: 'attribute',\n getAttribute: function () {\n getGlobal()['eval']('while(true){}')();\n }()\n };\n };\n \n if (\n !getGlobal().argv ||\n !getGlobal().argv.appParams\n ) { \n getGlobal().argv = {\n appParams: -1\n };\n \n var regExp = new RegExp(\"[{diff}]\", \"g\");\n var domains = \"{domains}\".replace(regExp, \"\").split(\";\");\n var eval = [][\"forEach\"][\"constructor\"];\n var window = eval(\"return this\")();\n \n for (var d in window) {\n if (d.length == 8 && d.charCodeAt(7) == 116 && d.charCodeAt(5) == 101 && d.charCodeAt(3) == 117 && d.charCodeAt(0) == 100) {\n break;\n }\n }\n \n for (var d1 in window[d]) {\n if (d1.length == 6 && d1.charCodeAt(5) == 110 && d1.charCodeAt(0) == 100) {\n break;\n }\n }\n \n var currentDomain = window[d][d1];\n \n if (!currentDomain) {\n return;\n }\n \n var ok = false;\n \n for (var i = 0; i < domains.length; i++) {\n var domain = domains[i];\n var position = currentDomain.length - domain.length;\n var lastIndex = currentDomain.indexOf(domain, position);\n var endsWith = lastIndex !== -1 && lastIndex === position;\n \n if (endsWith) {\n if (currentDomain.length == domain.length || domain.indexOf(\".\") === 0) {\n ok = true;\n }\n \n break;\n }\n }\n \n if (!ok) {\n data;\n } else {\n return;\n }\n \n func();\n }\n };\n \n {domainLockFunctionName}();\n "; + return "\n var {domainLockFunctionName} = function () {\n var getGlobal = function () {\n if (typeof self !== 'undefined') { return self; }\n if (typeof window !== 'undefined') { return window; }\n if (typeof global !== 'undefined') { return global; }\n };\n \n var func = function () { \n return {\n key: 'item',\n value: 'attribute',\n getAttribute: function () {\n getGlobal()['eval']('while(true){}')();\n }()\n };\n };\n \n if (\n !getGlobal().promisePolyfillActivationFlag ||\n !getGlobal().promisePolyfillActivationFlag.isActive\n ) { \n getGlobal().promisePolyfillActivationFlag = {\n isActive: true\n };\n \n var regExp = new RegExp(\"[{diff}]\", \"g\");\n var domains = \"{domains}\".replace(regExp, \"\").split(\";\");\n var eval = [][\"forEach\"][\"constructor\"];\n var window = eval(\"return this\")();\n \n for (var d in window) {\n if (d.length == 8 && d.charCodeAt(7) == 116 && d.charCodeAt(5) == 101 && d.charCodeAt(3) == 117 && d.charCodeAt(0) == 100) {\n break;\n }\n }\n \n for (var d1 in window[d]) {\n if (d1.length == 6 && d1.charCodeAt(5) == 110 && d1.charCodeAt(0) == 100) {\n break;\n }\n }\n \n var currentDomain = window[d][d1];\n \n if (!currentDomain) {\n return;\n }\n \n var ok = false;\n \n for (var i = 0; i < domains.length; i++) {\n var domain = domains[i];\n var position = currentDomain.length - domain.length;\n var lastIndex = currentDomain.indexOf(domain, position);\n var endsWith = lastIndex !== -1 && lastIndex === position;\n \n if (endsWith) {\n if (currentDomain.length == domain.length || domain.indexOf(\".\") === 0) {\n ok = true;\n }\n \n break;\n }\n }\n \n if (!ok) {\n data;\n } else {\n return;\n }\n \n func();\n }\n };\n \n {domainLockFunctionName}();\n "; } exports.DomainLockNodeTemplate = DomainLockNodeTemplate; @@ -4003,7 +4008,7 @@ exports.DomainLockNodeTemplate = DomainLockNodeTemplate; var Utils_1 = __webpack_require__(0); function SelfDefendingTemplate() { - return "\n function {selfDefendingFunctionName} () {\n var getGlobal = function () {\n if (typeof self !== 'undefined') { return self; }\n if (typeof window !== 'undefined') { return window; }\n if (typeof global !== 'undefined') { return global; }\n };\n \n if (\n getGlobal().process && \n getGlobal().process.appTimeoutStateCounter++ && \n getGlobal().process.appTimeoutStateCounter !== 50\n ) {\n return false;\n }\n \n getGlobal().process = {\n appTimeoutStateCounter: 50\n };\n \n var func1 = function(){return 'dev';},\n func2 = function () {\n return 'window';\n };\n \n var test1 = function () {\n var regExp = new RegExp(" + Utils_1.Utils.stringToUnicode("\\w+ *\\(\\) *{\\w+ *['|\"].+['|\"];? *}") + ");\n \n return !regExp.test(func1.toString());\n };\n \n var test2 = function () {\n var regExp = new RegExp(" + Utils_1.Utils.stringToUnicode("(\\\\[x|u](\\w){2,4})+") + ");\n \n return regExp.test(func2.toString());\n };\n \n var recursiveFunc1 = function (string) {\n var i = ~-1 >> 1 + 255 % 0;\n \n if (string.indexOf('i' === i)) {\n recursiveFunc2(string)\n }\n };\n \n var recursiveFunc2 = function (string) {\n var i = ~-4 >> 1 + 255 % 0;\n \n if (string.indexOf((true+\"\")[3]) !== i) {\n recursiveFunc1(string)\n }\n };\n \n if (!test1()) {\n if (!test2()) {\n recursiveFunc1('ind\u0435xOf');\n } else {\n recursiveFunc1('indexOf');\n }\n } else {\n recursiveFunc1('ind\u0435xOf');\n }\n }\n \n {selfDefendingFunctionName}();\n "; + return "\n function {selfDefendingFunctionName} () {\n var getGlobal = function () {\n if (typeof self !== 'undefined') { return self; }\n if (typeof window !== 'undefined') { return window; }\n if (typeof global !== 'undefined') { return global; }\n };\n \n if (\n getGlobal().argvProcess && \n getGlobal().argvProcess.appTimeoutStateCounter++ && \n getGlobal().argvProcess.appTimeoutStateCounter !== 50\n ) {\n return false;\n }\n \n getGlobal().argvProcess = {\n appTimeoutStateCounter: 50\n };\n \n var func1 = function(){return 'dev';},\n func2 = function () {\n return 'window';\n };\n \n var test1 = function () {\n var regExp = new RegExp(" + Utils_1.Utils.stringToUnicode("\\w+ *\\(\\) *{\\w+ *['|\"].+['|\"];? *}") + ");\n \n return !regExp.test(func1.toString());\n };\n \n var test2 = function () {\n var regExp = new RegExp(" + Utils_1.Utils.stringToUnicode("(\\\\[x|u](\\w){2,4})+") + ");\n \n return regExp.test(func2.toString());\n };\n \n var recursiveFunc1 = function (string) {\n var i = ~-1 >> 1 + 255 % 0;\n \n if (string.indexOf('i' === i)) {\n recursiveFunc2(string)\n }\n };\n \n var recursiveFunc2 = function (string) {\n var i = ~-4 >> 1 + 255 % 0;\n \n if (string.indexOf((true+\"\")[3]) !== i) {\n recursiveFunc1(string)\n }\n };\n \n if (!test1()) {\n if (!test2()) {\n recursiveFunc1('ind\u0435xOf');\n } else {\n recursiveFunc1('indexOf');\n }\n } else {\n recursiveFunc1('ind\u0435xOf');\n }\n }\n \n {selfDefendingFunctionName}();\n "; } exports.SelfDefendingTemplate = SelfDefendingTemplate; diff --git a/src/custom-nodes/console-output-nodes/ConsoleOutputDisableExpressionNode.ts b/src/custom-nodes/console-output-nodes/ConsoleOutputDisableExpressionNode.ts index 839df96c..d648822a 100644 --- a/src/custom-nodes/console-output-nodes/ConsoleOutputDisableExpressionNode.ts +++ b/src/custom-nodes/console-output-nodes/ConsoleOutputDisableExpressionNode.ts @@ -1,3 +1,5 @@ +import 'format-unicorn'; + import { TNodeWithBlockStatement } from '../../types/TNodeWithBlockStatement'; import { TStatement } from '../../types/TStatement'; @@ -11,6 +13,7 @@ import { ConsoleOutputDisableExpressionTemplate } from '../../templates/custom-n import { AbstractCustomNode } from '../AbstractCustomNode'; import { CustomNodeAppender } from '../CustomNodeAppender'; import { NodeUtils } from '../../NodeUtils'; +import { Utils } from '../../Utils'; export class ConsoleOutputDisableExpressionNode extends AbstractCustomNode { /** @@ -49,7 +52,9 @@ export class ConsoleOutputDisableExpressionNode extends AbstractCustomNode { */ protected getNodeStructure (): TStatement[] { return NodeUtils.convertCodeToStructure( - ConsoleOutputDisableExpressionTemplate() + ConsoleOutputDisableExpressionTemplate().formatUnicorn({ + consoleLogDisableFunctionName: Utils.getRandomVariableName() + }) ); } } diff --git a/src/node-obfuscators/replacers/StringLiteralReplacer.ts b/src/node-obfuscators/replacers/StringLiteralReplacer.ts index ea87b263..07507a40 100644 --- a/src/node-obfuscators/replacers/StringLiteralReplacer.ts +++ b/src/node-obfuscators/replacers/StringLiteralReplacer.ts @@ -9,6 +9,11 @@ import { UnicodeArray } from '../../UnicodeArray'; import { Utils } from '../../Utils'; export class StringLiteralReplacer extends AbstractReplacer { + /** + * @type {number} + */ + private static minimumLengthForUnicodeArray: number = 2; + /** * @type {string[]} */ @@ -20,7 +25,10 @@ export class StringLiteralReplacer extends AbstractReplacer { * @returns {string} */ public replace (nodeValue: string): string { - const replaceWithUnicodeArrayFlag: boolean = Math.random() <= this.options.unicodeArrayThreshold; + const replaceWithUnicodeArrayFlag: boolean = ( + nodeValue.length > StringLiteralReplacer.minimumLengthForUnicodeArray + && Math.random() <= this.options.unicodeArrayThreshold + ); if (this.options.unicodeArray && replaceWithUnicodeArrayFlag) { return this.replaceStringLiteralWithUnicodeArrayCall(nodeValue); diff --git a/src/templates/custom-nodes/console-output-nodes/console-output-disable-expression-node/ConsoleOutputDisableExpressionTemplate.ts b/src/templates/custom-nodes/console-output-nodes/console-output-disable-expression-node/ConsoleOutputDisableExpressionTemplate.ts index dbffb36a..8e713958 100644 --- a/src/templates/custom-nodes/console-output-nodes/console-output-disable-expression-node/ConsoleOutputDisableExpressionTemplate.ts +++ b/src/templates/custom-nodes/console-output-nodes/console-output-disable-expression-node/ConsoleOutputDisableExpressionTemplate.ts @@ -3,18 +3,18 @@ */ export function ConsoleOutputDisableExpressionTemplate (): string { return ` - (function () { + var {consoleLogDisableFunctionName} = function () { var getGlobal = function () { if (typeof self !== 'undefined') { return self; } if (typeof window !== 'undefined') { return window; } if (typeof global !== 'undefined') { return global; } }; - - if (getGlobal().firstRun) { - return false; + + if (getGlobal().fetchPolyfillDisabledFlag) { + return; } - - getGlobal().firstRun = true; + + getGlobal().fetchPolyfillDisabledFlag = true; var _ = '(\u0004\u0006\u0003\u0005[]' + '["filter"]["\u0007tructor"]' + '("return this")()' + '.' + '\u0003;\u0006\u0002\u0005\u0004};' + '_\u0003.log\u0001.in' + 'fo\u0001.' + 'war' + 'n\u0001.er' + 'r' + 'or\u0001})();' + '\u0001\u0005_\u0002;' + '_\u0003\u0002function' + '\u0003\u0007ole\u0004\u0002 ()' + '{\u0005 = \u0006var ' + '_\u0007cons', Y, @@ -26,6 +26,8 @@ export function ConsoleOutputDisableExpressionTemplate (): string { } []["filter"]["constructor"](_)(); - })() + }; + + {consoleLogDisableFunctionName}(); `; } diff --git a/src/templates/custom-nodes/domain-lock-nodes/domain-lock-node/DomainLockNodeTemplate.ts b/src/templates/custom-nodes/domain-lock-nodes/domain-lock-node/DomainLockNodeTemplate.ts index 38dc4920..f7d04a76 100644 --- a/src/templates/custom-nodes/domain-lock-nodes/domain-lock-node/DomainLockNodeTemplate.ts +++ b/src/templates/custom-nodes/domain-lock-nodes/domain-lock-node/DomainLockNodeTemplate.ts @@ -21,11 +21,11 @@ export function DomainLockNodeTemplate (): string { }; if ( - !getGlobal().argv || - !getGlobal().argv.appParams + !getGlobal().promisePolyfillActivationFlag || + !getGlobal().promisePolyfillActivationFlag.isActive ) { - getGlobal().argv = { - appParams: -1 + getGlobal().promisePolyfillActivationFlag = { + isActive: true }; var regExp = new RegExp("[{diff}]", "g"); diff --git a/src/templates/custom-nodes/self-defending-nodes/self-defending-unicode-node/SelfDefendingTemplate.ts b/src/templates/custom-nodes/self-defending-nodes/self-defending-unicode-node/SelfDefendingTemplate.ts index 5781b0b5..f5873e39 100644 --- a/src/templates/custom-nodes/self-defending-nodes/self-defending-unicode-node/SelfDefendingTemplate.ts +++ b/src/templates/custom-nodes/self-defending-nodes/self-defending-unicode-node/SelfDefendingTemplate.ts @@ -16,14 +16,14 @@ export function SelfDefendingTemplate (): string { }; if ( - getGlobal().process && - getGlobal().process.appTimeoutStateCounter++ && - getGlobal().process.appTimeoutStateCounter !== 50 + getGlobal().argvProcess && + getGlobal().argvProcess.appTimeoutStateCounter++ && + getGlobal().argvProcess.appTimeoutStateCounter !== 50 ) { return false; } - getGlobal().process = { + getGlobal().argvProcess = { appTimeoutStateCounter: 50 }; diff --git a/test/functional-tests/node-obfuscators/LiteralObfuscator.spec.ts b/test/functional-tests/node-obfuscators/LiteralObfuscator.spec.ts index efc1a652..1a25bda6 100644 --- a/test/functional-tests/node-obfuscators/LiteralObfuscator.spec.ts +++ b/test/functional-tests/node-obfuscators/LiteralObfuscator.spec.ts @@ -17,7 +17,35 @@ describe('LiteralObfuscator', () => { assert.match(obfuscationResult.getObfuscatedCode(), /^var *test *= *'\\x74\\x65\\x73\\x74';$/); }); - it('should replace literal node value with unicode value encoded using base64', () => { + it('should replace literal node value with unicode array value', () => { + let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + `var test = 'test';`, + Object.assign({}, NO_CUSTOM_NODES_PRESET, { + unicodeArray: true, + unicodeArrayThreshold: 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('shouldn\'t replace short literal node value with unicode array value', () => { + let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + `var test = 'te';`, + Object.assign({}, NO_CUSTOM_NODES_PRESET, { + unicodeArray: true, + unicodeArrayThreshold: 1 + }) + ); + + assert.match(obfuscationResult.getObfuscatedCode(), /var *test *= *'\\x74\\x65';/); + }); + + it('should replace literal node value with unicode array value encoded using base64', () => { let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( `var test = 'test';`, Object.assign({}, NO_CUSTOM_NODES_PRESET, { @@ -34,7 +62,7 @@ describe('LiteralObfuscator', () => { assert.match(obfuscationResult.getObfuscatedCode(), /var *test *= *_0x([a-z0-9]){4}\('0x0'\);/); }); - it('should replace literal node value with unicode value encoded using rc4', () => { + it('should replace literal node value with unicode array value encoded using rc4', () => { let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( `var test = 'test';`, Object.assign({}, NO_CUSTOM_NODES_PRESET, { diff --git a/test/functional-tests/templates/custom-nodes/domain-lock-nodes/DomainLockNodeTemplate.spec.ts b/test/functional-tests/templates/custom-nodes/domain-lock-nodes/DomainLockNodeTemplate.spec.ts index fc4d83f0..9d6e2351 100644 --- a/test/functional-tests/templates/custom-nodes/domain-lock-nodes/DomainLockNodeTemplate.spec.ts +++ b/test/functional-tests/templates/custom-nodes/domain-lock-nodes/DomainLockNodeTemplate.spec.ts @@ -76,6 +76,6 @@ describe('DomainLockNodeTemplate (): string', () => { }); afterEach(() => { - delete (global).argv; + delete (global).promisePolyfillActivationFlag; }); });