diff --git a/dist/index.js b/dist/index.js index 312da0df..5b666854 100644 --- a/dist/index.js +++ b/dist/index.js @@ -198,8 +198,8 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de var escodegen = __webpack_require__(25); var esprima = __webpack_require__(48); -var estraverse = __webpack_require__(15); -var NodeType_1 = __webpack_require__(16); +var estraverse = __webpack_require__(16); +var NodeType_1 = __webpack_require__(15); var Node_1 = __webpack_require__(12); var NodeUtils = function () { @@ -530,7 +530,7 @@ var _createClass3 = _interopRequireDefault(_createClass2); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -var NodeType_1 = __webpack_require__(16); +var NodeType_1 = __webpack_require__(15); var Node = function () { function Node() { @@ -895,12 +895,6 @@ exports.AbstractCustomNode = AbstractCustomNode; /***/ }, /* 15 */ -/***/ function(module, exports) { - -module.exports = require("estraverse"); - -/***/ }, -/* 16 */ /***/ function(module, exports, __webpack_require__) { "use strict"; @@ -942,6 +936,12 @@ exports.NodeType = Utils_1.Utils.strEnumify({ WhileStatement: 'WhileStatement' }); +/***/ }, +/* 16 */ +/***/ function(module, exports) { + +module.exports = require("estraverse"); + /***/ }, /* 17 */ /***/ function(module, exports, __webpack_require__) { @@ -1382,7 +1382,7 @@ var _createClass3 = _interopRequireDefault(_createClass2); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var escodegen = __webpack_require__(25); -var NodeType_1 = __webpack_require__(16); +var NodeType_1 = __webpack_require__(15); var Nodes = function () { function Nodes() { @@ -2176,9 +2176,9 @@ 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 estraverse = __webpack_require__(15); +var estraverse = __webpack_require__(16); var NodeTransformers_1 = __webpack_require__(40); -var NodeType_1 = __webpack_require__(16); +var NodeType_1 = __webpack_require__(15); var ObfuscationEvents_1 = __webpack_require__(22); var VisitorDirection_1 = __webpack_require__(81); var Node_1 = __webpack_require__(12); @@ -4490,9 +4490,9 @@ 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 estraverse = __webpack_require__(15); +var estraverse = __webpack_require__(16); var CustomNodes_1 = __webpack_require__(20); -var NodeType_1 = __webpack_require__(16); +var NodeType_1 = __webpack_require__(15); var AbstractNodeTransformer_1 = __webpack_require__(17); var Node_1 = __webpack_require__(12); var NodeAppender_1 = __webpack_require__(24); @@ -4740,9 +4740,9 @@ 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 estraverse = __webpack_require__(15); +var estraverse = __webpack_require__(16); var NodeObfuscatorsReplacers_1 = __webpack_require__(19); -var NodeType_1 = __webpack_require__(16); +var NodeType_1 = __webpack_require__(15); var AbstractNodeTransformer_1 = __webpack_require__(17); var Node_1 = __webpack_require__(12); var NodeUtils_1 = __webpack_require__(8); @@ -4836,9 +4836,9 @@ 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 estraverse = __webpack_require__(15); +var estraverse = __webpack_require__(16); var NodeObfuscatorsReplacers_1 = __webpack_require__(19); -var NodeType_1 = __webpack_require__(16); +var NodeType_1 = __webpack_require__(15); var AbstractNodeTransformer_1 = __webpack_require__(17); var Node_1 = __webpack_require__(12); var NodeUtils_1 = __webpack_require__(8); @@ -4966,9 +4966,9 @@ 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 estraverse = __webpack_require__(15); +var estraverse = __webpack_require__(16); var NodeObfuscatorsReplacers_1 = __webpack_require__(19); -var NodeType_1 = __webpack_require__(16); +var NodeType_1 = __webpack_require__(15); var AbstractNodeTransformer_1 = __webpack_require__(17); var Node_1 = __webpack_require__(12); var NodeUtils_1 = __webpack_require__(8); @@ -5064,9 +5064,9 @@ 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 estraverse = __webpack_require__(15); +var estraverse = __webpack_require__(16); var NodeObfuscatorsReplacers_1 = __webpack_require__(19); -var NodeType_1 = __webpack_require__(16); +var NodeType_1 = __webpack_require__(15); var AbstractNodeTransformer_1 = __webpack_require__(17); var Node_1 = __webpack_require__(12); var NodeUtils_1 = __webpack_require__(8); @@ -5238,7 +5238,7 @@ var inversify_1 = __webpack_require__(2); var ServiceIdentifiers_1 = __webpack_require__(4); var escodegen = __webpack_require__(25); var NodeObfuscatorsReplacers_1 = __webpack_require__(19); -var NodeType_1 = __webpack_require__(16); +var NodeType_1 = __webpack_require__(15); var AbstractNodeTransformer_1 = __webpack_require__(17); var Node_1 = __webpack_require__(12); var MemberExpressionObfuscator = function (_AbstractNodeTransfor) { @@ -5400,7 +5400,7 @@ var tslib_1 = __webpack_require__(3); var inversify_1 = __webpack_require__(2); var ServiceIdentifiers_1 = __webpack_require__(4); var escodegen = __webpack_require__(25); -var NodeType_1 = __webpack_require__(16); +var NodeType_1 = __webpack_require__(15); var AbstractNodeTransformer_1 = __webpack_require__(17); var Node_1 = __webpack_require__(12); var Utils_1 = __webpack_require__(13); @@ -5498,9 +5498,9 @@ 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 estraverse = __webpack_require__(15); +var estraverse = __webpack_require__(16); var NodeObfuscatorsReplacers_1 = __webpack_require__(19); -var NodeType_1 = __webpack_require__(16); +var NodeType_1 = __webpack_require__(15); var AbstractNodeTransformer_1 = __webpack_require__(17); var Node_1 = __webpack_require__(12); var NodeUtils_1 = __webpack_require__(8); @@ -5861,20 +5861,18 @@ var StringLiteralReplacer = StringLiteralReplacer_1 = function (_AbstractReplace (0, _createClass3.default)(StringLiteralReplacer, [{ key: "replace", value: function replace(nodeValue) { - var replaceWithStringArrayFlag = nodeValue.length >= StringLiteralReplacer_1.minimumLengthForStringArray && RandomGeneratorUtils_1.RandomGeneratorUtils.getRandomFloat(0, 1) <= this.options.stringArrayThreshold; + var usingStringArray = this.options.stringArray && nodeValue.length >= StringLiteralReplacer_1.minimumLengthForStringArray && RandomGeneratorUtils_1.RandomGeneratorUtils.getRandomFloat(0, 1) <= this.options.stringArrayThreshold; + var cacheKey = nodeValue + "-" + String(usingStringArray); + if (this.stringLiteralCache.has(cacheKey) && this.options.stringArrayEncoding !== StringArrayEncoding_1.StringArrayEncoding.rc4) { + return this.stringLiteralCache.get(cacheKey); + } var result = void 0; - if (this.options.stringArray && replaceWithStringArrayFlag) { - if (this.stringLiteralCache.has(nodeValue) && this.options.stringArrayEncoding !== StringArrayEncoding_1.StringArrayEncoding.rc4) { - return this.stringLiteralCache.get(nodeValue); - } + if (usingStringArray) { result = this.replaceStringLiteralWithStringArrayCall(nodeValue); } else { - if (this.stringLiteralCache.has(nodeValue)) { - return this.stringLiteralCache.get(nodeValue); - } result = "'" + Utils_1.Utils.stringToUnicodeEscapeSequence(nodeValue, !this.options.unicodeEscapeSequence) + "'"; } - this.stringLiteralCache.set(nodeValue, result); + this.stringLiteralCache.set(cacheKey, result); return result; } }, { @@ -5896,24 +5894,36 @@ var StringLiteralReplacer = StringLiteralReplacer_1 = function (_AbstractReplace return hexadecimalIndex; } }, { - key: "replaceStringLiteralWithStringArrayCall", - value: function replaceStringLiteralWithStringArrayCall(value) { - var rc4Key = ''; + key: "getEncodedValue", + value: function getEncodedValue(value) { + var encodedValue = void 0, + key = void 0; switch (this.options.stringArrayEncoding) { case StringArrayEncoding_1.StringArrayEncoding.rc4: - rc4Key = RandomGeneratorUtils_1.RandomGeneratorUtils.getRandomGenerator().pickone(StringLiteralReplacer_1.rc4Keys); - value = CryptUtils_1.CryptUtils.btoa(CryptUtils_1.CryptUtils.rc4(value, rc4Key)); + key = RandomGeneratorUtils_1.RandomGeneratorUtils.getRandomGenerator().pickone(StringLiteralReplacer_1.rc4Keys); + encodedValue = CryptUtils_1.CryptUtils.btoa(CryptUtils_1.CryptUtils.rc4(value, key)); break; case StringArrayEncoding_1.StringArrayEncoding.base64: - value = CryptUtils_1.CryptUtils.btoa(value); + encodedValue = CryptUtils_1.CryptUtils.btoa(value); break; + default: + encodedValue = value; } - value = Utils_1.Utils.stringToUnicodeEscapeSequence(value, !this.options.unicodeEscapeSequence); - var hexadecimalIndex = this.getArrayHexadecimalIndex(value); + encodedValue = Utils_1.Utils.stringToUnicodeEscapeSequence(encodedValue, !this.options.unicodeEscapeSequence); + return { encodedValue: encodedValue, key: key }; + } + }, { + key: "replaceStringLiteralWithStringArrayCall", + value: function replaceStringLiteralWithStringArrayCall(value) { + var _getEncodedValue = this.getEncodedValue(value), + encodedValue = _getEncodedValue.encodedValue, + key = _getEncodedValue.key; + + var hexadecimalIndex = this.getArrayHexadecimalIndex(encodedValue); var rotatedStringArrayStorageId = Utils_1.Utils.stringRotate(this.stringArrayStorage.getStorageId(), 1); var stringArrayStorageCallsWrapperName = "_" + Utils_1.Utils.hexadecimalPrefix + rotatedStringArrayStorageId; - if (this.options.stringArrayEncoding === StringArrayEncoding_1.StringArrayEncoding.rc4) { - return stringArrayStorageCallsWrapperName + "('" + hexadecimalIndex + "', '" + Utils_1.Utils.stringToUnicodeEscapeSequence(rc4Key, !this.options.unicodeEscapeSequence) + "')"; + if (key) { + return stringArrayStorageCallsWrapperName + "('" + hexadecimalIndex + "', '" + Utils_1.Utils.stringToUnicodeEscapeSequence(key, !this.options.unicodeEscapeSequence) + "')"; } return stringArrayStorageCallsWrapperName + "('" + hexadecimalIndex + "')"; } @@ -6279,7 +6289,7 @@ 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 estraverse = __webpack_require__(15); +var estraverse = __webpack_require__(16); var CalleeDataExtractors_1 = __webpack_require__(37); var Node_1 = __webpack_require__(12); var NodeUtils_1 = __webpack_require__(8); @@ -6397,7 +6407,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de var tslib_1 = __webpack_require__(3); var inversify_1 = __webpack_require__(2); -var estraverse = __webpack_require__(15); +var estraverse = __webpack_require__(16); var AbstractCalleeDataExtractor_1 = __webpack_require__(32); var Node_1 = __webpack_require__(12); var NodeUtils_1 = __webpack_require__(8); @@ -6475,7 +6485,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de var tslib_1 = __webpack_require__(3); var inversify_1 = __webpack_require__(2); -var estraverse = __webpack_require__(15); +var estraverse = __webpack_require__(16); var AbstractCalleeDataExtractor_1 = __webpack_require__(32); var Node_1 = __webpack_require__(12); var NodeUtils_1 = __webpack_require__(8); @@ -6560,7 +6570,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de var tslib_1 = __webpack_require__(3); var inversify_1 = __webpack_require__(2); -var estraverse = __webpack_require__(15); +var estraverse = __webpack_require__(16); var Node_1 = __webpack_require__(12); var NodeUtils_1 = __webpack_require__(8); var AbstractCalleeDataExtractor_1 = __webpack_require__(32); diff --git a/package.json b/package.json index aa23cc50..7bb33c41 100644 --- a/package.json +++ b/package.json @@ -29,10 +29,10 @@ "esprima": "3.1.3", "estraverse": "4.2.0", "inversify": "^3.0.0-rc.2", - "lodash": "^4.17.2", + "lodash": "^4.17.3", "mkdirp": "0.5.1", "reflect-metadata": "^0.1.9", - "source-map-support": "0.4.7", + "source-map-support": "0.4.8", "string-template": "^1.0.0", "tslib": "^1.4.0" }, diff --git a/src/interfaces/node-transformers/IEncodedValue.d.ts b/src/interfaces/node-transformers/IEncodedValue.d.ts new file mode 100644 index 00000000..f6e925cf --- /dev/null +++ b/src/interfaces/node-transformers/IEncodedValue.d.ts @@ -0,0 +1,4 @@ +export interface IEncodedValue { + encodedValue: string; + key?: string; +} diff --git a/src/node-transformers/node-obfuscators/replacers/StringLiteralReplacer.ts b/src/node-transformers/node-obfuscators/replacers/StringLiteralReplacer.ts index b88f7aad..c47d9a49 100644 --- a/src/node-transformers/node-obfuscators/replacers/StringLiteralReplacer.ts +++ b/src/node-transformers/node-obfuscators/replacers/StringLiteralReplacer.ts @@ -2,6 +2,7 @@ import { injectable, inject } from 'inversify'; import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers'; import { ICustomNodeGroup } from '../../../interfaces/custom-nodes/ICustomNodeGroup'; +import { IEncodedValue } from '../../../interfaces/node-transformers/IEncodedValue'; import { IOptions } from '../../../interfaces/options/IOptions'; import { IStorage } from '../../../interfaces/storages/IStorage'; @@ -66,32 +67,26 @@ export class StringLiteralReplacer extends AbstractReplacer { * @returns {string} */ public replace (nodeValue: string): string { - const replaceWithStringArrayFlag: boolean = ( - nodeValue.length >= StringLiteralReplacer.minimumLengthForStringArray - && RandomGeneratorUtils.getRandomFloat(0, 1) <= this.options.stringArrayThreshold + const usingStringArray: boolean = ( + this.options.stringArray && + nodeValue.length >= StringLiteralReplacer.minimumLengthForStringArray && + RandomGeneratorUtils.getRandomFloat(0, 1) <= this.options.stringArrayThreshold ); + const cacheKey: string = `${nodeValue}-${String(usingStringArray)}`; + + if (this.stringLiteralCache.has(cacheKey) && this.options.stringArrayEncoding !== StringArrayEncoding.rc4) { + return this.stringLiteralCache.get(cacheKey); + } let result: string; - if (this.options.stringArray && replaceWithStringArrayFlag) { - /** - * we can't use values from cache with `stringArrayEncoding: rc4` - * because rc4 key will be the same for same values - */ - if (this.stringLiteralCache.has(nodeValue) && this.options.stringArrayEncoding !== StringArrayEncoding.rc4) { - return this.stringLiteralCache.get(nodeValue); - } - + if (usingStringArray) { result = this.replaceStringLiteralWithStringArrayCall(nodeValue); } else { - if (this.stringLiteralCache.has(nodeValue)) { - return this.stringLiteralCache.get(nodeValue); - } - result = `'${Utils.stringToUnicodeEscapeSequence(nodeValue, !this.options.unicodeEscapeSequence)}'`; } - this.stringLiteralCache.set(nodeValue, result); + this.stringLiteralCache.set(cacheKey, result); return result; } @@ -125,32 +120,45 @@ export class StringLiteralReplacer extends AbstractReplacer { /** * @param value - * @returns {string} + * @returns {IEncodedValue} */ - private replaceStringLiteralWithStringArrayCall (value: string): string { - let rc4Key: string = ''; + private getEncodedValue (value: string): IEncodedValue { + let encodedValue: string, + key: string | undefined; switch (this.options.stringArrayEncoding) { case StringArrayEncoding.rc4: - rc4Key = RandomGeneratorUtils.getRandomGenerator().pickone(StringLiteralReplacer.rc4Keys); - value = CryptUtils.btoa(CryptUtils.rc4(value, rc4Key)); + key = RandomGeneratorUtils.getRandomGenerator().pickone(StringLiteralReplacer.rc4Keys); + encodedValue = CryptUtils.btoa(CryptUtils.rc4(value, key)); break; case StringArrayEncoding.base64: - value = CryptUtils.btoa(value); + encodedValue = CryptUtils.btoa(value); break; + + default: + encodedValue = value; } - value = Utils.stringToUnicodeEscapeSequence(value, !this.options.unicodeEscapeSequence); + encodedValue = Utils.stringToUnicodeEscapeSequence(encodedValue, !this.options.unicodeEscapeSequence); - const hexadecimalIndex: string = this.getArrayHexadecimalIndex(value); + return { encodedValue, key }; + } + + /** + * @param value + * @returns {string} + */ + private replaceStringLiteralWithStringArrayCall (value: string): string { + const { encodedValue, key }: IEncodedValue = this.getEncodedValue(value); + const hexadecimalIndex: string = this.getArrayHexadecimalIndex(encodedValue); const rotatedStringArrayStorageId: string = Utils.stringRotate(this.stringArrayStorage.getStorageId(), 1); const stringArrayStorageCallsWrapperName: string = `_${Utils.hexadecimalPrefix}${rotatedStringArrayStorageId}`; - if (this.options.stringArrayEncoding === StringArrayEncoding.rc4) { - return `${stringArrayStorageCallsWrapperName}('${hexadecimalIndex}', '${Utils.stringToUnicodeEscapeSequence(rc4Key, !this.options.unicodeEscapeSequence)}')`; + if (key) { + return `${stringArrayStorageCallsWrapperName}('${hexadecimalIndex}', '${Utils.stringToUnicodeEscapeSequence(key, !this.options.unicodeEscapeSequence)}')`; } return `${stringArrayStorageCallsWrapperName}('${hexadecimalIndex}')`; 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 b23a63dc..2918065a 100644 --- a/test/functional-tests/node-transformers/node-obfuscators/LiteralObfuscator.spec.ts +++ b/test/functional-tests/node-transformers/node-obfuscators/LiteralObfuscator.spec.ts @@ -21,7 +21,7 @@ describe('LiteralObfuscator', () => { assert.match(obfuscationResult.getObfuscatedCode(), /^var *test *= *'\\x74\\x65\\x73\\x74';$/); }); - it('should replace literal node value with unicode escape sequence from unicode array', () => { + it('should replace literal node value with unicode escape sequence from string array', () => { let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( `var test = 'test';`, { @@ -38,7 +38,7 @@ describe('LiteralObfuscator', () => { assert.match(obfuscationResult.getObfuscatedCode(), /var *test *= *_0x([a-z0-9]){4}\('0x0'\);/); }); - it('should replace literal node value with raw value from unicode array if `unicodeEscapeSequence` is disabled', () => { + it('should replace literal node value with raw value from string array if `unicodeEscapeSequence` is disabled', () => { let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( `var test = 'test';`, { @@ -56,7 +56,7 @@ describe('LiteralObfuscator', () => { assert.match(obfuscationResult.getObfuscatedCode(), /var *test *= *_0x([a-z0-9]){4}\('0x0'\);/); }); - it('should replace literal node value with raw value from unicode array if `unicodeEscapeSequence` and `stringArray` are disabled', () => { + it('should replace literal node value with raw value from string array if `unicodeEscapeSequence` and `stringArray` are disabled', () => { let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( `var test = 'test';`, { @@ -83,7 +83,7 @@ describe('LiteralObfuscator', () => { )); }); - it('shouldn\'t replace short literal node value with unicode array value', () => { + it('shouldn\'t replace short literal node value with value from string array', () => { let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( `var test = 'te';`, { @@ -96,7 +96,7 @@ describe('LiteralObfuscator', () => { assert.match(obfuscationResult.getObfuscatedCode(), /var *test *= *'\\x74\\x65';/); }); - it('should replace literal node value with unicode array value encoded using base64', () => { + it('should replace literal node value with value from string array encoded using base64', () => { let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( `var test = 'test';`, { @@ -114,7 +114,7 @@ describe('LiteralObfuscator', () => { assert.match(obfuscationResult.getObfuscatedCode(), /var *test *= *_0x([a-z0-9]){4}\('0x0'\);/); }); - it('should replace literal node value with unicode array value encoded using rc4', () => { + it('should replace literal node value with value from string array encoded using rc4', () => { let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( `var test = 'test';`, { @@ -130,6 +130,28 @@ describe('LiteralObfuscator', () => { /var *test *= *_0x([a-z0-9]){4}\('0x0', '(\\x[a-f0-9]*){4}'\);/ ); }); + + it('should replace literal node value with value from string array with `stringArrayThreshold` chance', () => { + const samples: number = 1000; + const stringArrayThreshold: number = 0.5; + const delta: number = 0.1; + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + `var test = 'test';\n`.repeat(samples), + { + ...NO_CUSTOM_NODES_PRESET, + stringArray: true, + stringArrayThreshold: stringArrayThreshold + } + ); + + const regExp1: RegExp = /var *test *= *_0x([a-z0-9]){4}\('0x0'\);/g; + const regExp2: RegExp = /var *test *= *'\\x74\\x65\\x73\\x74';/g; + const stringArrayMatchesLength = obfuscationResult.getObfuscatedCode().match(regExp1)!.length; + const noStringArrayMatchesLength = obfuscationResult.getObfuscatedCode().match(regExp2)!.length; + + assert.closeTo(stringArrayMatchesLength / samples, stringArrayThreshold, delta); + assert.closeTo(noStringArrayMatchesLength / samples, stringArrayThreshold, delta); + }); }); it('should obfuscate literal node with boolean value', () => {