From 519ecbf0847f0914c325d0db3a1974ede2c27482 Mon Sep 17 00:00:00 2001 From: sanex3339 Date: Thu, 22 Dec 2016 00:44:01 +0300 Subject: [PATCH] fixed esprima crash when `unicodeEscapeSequence` is disabled --- dist/index.js | 12 +++++--- .../replacers/StringLiteralReplacer.ts | 6 ++-- src/utils/Utils.ts | 8 ++++- test/dev/dev.ts | 3 +- .../literal-obfuscator-unicode-sequence.js | 1 + .../LiteralObfuscator.spec.ts | 29 +++++++++++++++++++ test/unit-tests/utils/Utils.spec.ts | 11 +++++-- 7 files changed, 57 insertions(+), 13 deletions(-) create mode 100644 test/fixtures/node-transformers/node-obfuscators/literal-obfuscator/literal-obfuscator-unicode-sequence.js diff --git a/dist/index.js b/dist/index.js index 9d8a2a85..8634e79b 100644 --- a/dist/index.js +++ b/dist/index.js @@ -801,11 +801,17 @@ var Utils = function () { }, { key: "stringToUnicodeEscapeSequence", value: function stringToUnicodeEscapeSequence(string) { + var nonLatinAndNonDigitsOnly = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + var radix = 16; var regexp = new RegExp('[\x00-\x7F]'); + var escapeRegExp = new RegExp('[^a-zA-Z0-9]'); var prefix = void 0, template = void 0; return "" + string.replace(/[\s\S]/g, function (escape) { + if (nonLatinAndNonDigitsOnly && !escapeRegExp.test(escape)) { + return escape; + } if (regexp.test(escape)) { prefix = '\\x'; template = '0'.repeat(2); @@ -5755,7 +5761,7 @@ var StringLiteralReplacer = StringLiteralReplacer_1 = function (_AbstractReplace if (this.options.stringArray && replaceWithStringArrayFlag) { return this.replaceStringLiteralWithStringArrayCall(nodeValue); } - return "'" + Utils_1.Utils.stringToUnicodeEscapeSequence(nodeValue) + "'"; + return "'" + Utils_1.Utils.stringToUnicodeEscapeSequence(nodeValue, !this.options.unicodeEscapeSequence) + "'"; } }, { key: "replaceStringLiteralWithStringArrayCall", @@ -5770,9 +5776,7 @@ var StringLiteralReplacer = StringLiteralReplacer_1 = function (_AbstractReplace value = CryptUtils_1.CryptUtils.btoa(value); break; } - if (this.options.unicodeEscapeSequence) { - value = Utils_1.Utils.stringToUnicodeEscapeSequence(value); - } + value = Utils_1.Utils.stringToUnicodeEscapeSequence(value, !this.options.unicodeEscapeSequence); var indexOfExistingValue = this.stringArrayStorage.getKeyOf(value); var indexOfValue = void 0; if (indexOfExistingValue >= 0) { diff --git a/src/node-transformers/node-obfuscators/replacers/StringLiteralReplacer.ts b/src/node-transformers/node-obfuscators/replacers/StringLiteralReplacer.ts index f45c041c..9c53e556 100644 --- a/src/node-transformers/node-obfuscators/replacers/StringLiteralReplacer.ts +++ b/src/node-transformers/node-obfuscators/replacers/StringLiteralReplacer.ts @@ -65,7 +65,7 @@ export class StringLiteralReplacer extends AbstractReplacer { return this.replaceStringLiteralWithStringArrayCall(nodeValue); } - return `'${Utils.stringToUnicodeEscapeSequence(nodeValue)}'`; + return `'${Utils.stringToUnicodeEscapeSequence(nodeValue, !this.options.unicodeEscapeSequence)}'`; } /** @@ -88,9 +88,7 @@ export class StringLiteralReplacer extends AbstractReplacer { break; } - if (this.options.unicodeEscapeSequence) { - value = Utils.stringToUnicodeEscapeSequence(value); - } + value = Utils.stringToUnicodeEscapeSequence(value, !this.options.unicodeEscapeSequence); const indexOfExistingValue: number = this.stringArrayStorage.getKeyOf(value); diff --git a/src/utils/Utils.ts b/src/utils/Utils.ts index 09def620..56f292c4 100644 --- a/src/utils/Utils.ts +++ b/src/utils/Utils.ts @@ -124,16 +124,22 @@ export class Utils { /** * @param string + * @param nonLatinAndNonDigitsOnly * @returns {string} */ - public static stringToUnicodeEscapeSequence (string: string): string { + public static stringToUnicodeEscapeSequence (string: string, nonLatinAndNonDigitsOnly: boolean = false): string { const radix: number = 16; const regexp: RegExp = new RegExp('[\x00-\x7F]'); + const escapeRegExp: RegExp = new RegExp('[^a-zA-Z0-9]'); let prefix: string, template: string; return `${string.replace(/[\s\S]/g, (escape: string): string => { + if (nonLatinAndNonDigitsOnly && !escapeRegExp.test(escape)) { + return escape; + } + if (regexp.test(escape)) { prefix = '\\x'; template = '0'.repeat(2); diff --git a/test/dev/dev.ts b/test/dev/dev.ts index 5307d3d8..97436734 100644 --- a/test/dev/dev.ts +++ b/test/dev/dev.ts @@ -84,7 +84,8 @@ if (!(global)._babelPolyfill) { { compact: false, controlFlowFlattening: true, - disableConsoleOutput: false + disableConsoleOutput: false, + unicodeEscapeSequence: false } ).getObfuscatedCode(); diff --git a/test/fixtures/node-transformers/node-obfuscators/literal-obfuscator/literal-obfuscator-unicode-sequence.js b/test/fixtures/node-transformers/node-obfuscators/literal-obfuscator/literal-obfuscator-unicode-sequence.js new file mode 100644 index 00000000..2171774f --- /dev/null +++ b/test/fixtures/node-transformers/node-obfuscators/literal-obfuscator/literal-obfuscator-unicode-sequence.js @@ -0,0 +1 @@ +var test = '\nreturn \n//# sourceURL= there can only be \'^\' and \'!\' markers in a subscription marble diagram.'; 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 669a2601..b23a63dc 100644 --- a/test/functional-tests/node-transformers/node-obfuscators/LiteralObfuscator.spec.ts +++ b/test/functional-tests/node-transformers/node-obfuscators/LiteralObfuscator.spec.ts @@ -4,6 +4,8 @@ import { IObfuscationResult } from '../../../../src/interfaces/IObfuscationResul import { NO_CUSTOM_NODES_PRESET } from '../../../../src/options/presets/NoCustomNodes'; +import { readFileAsString } from '../../../helpers/readFileAsString'; + import { JavaScriptObfuscator } from '../../../../src/JavaScriptObfuscator'; describe('LiteralObfuscator', () => { @@ -54,6 +56,33 @@ 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', () => { + let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + `var test = 'test';`, + { + ...NO_CUSTOM_NODES_PRESET, + unicodeEscapeSequence: false + } + ); + + assert.match( + obfuscationResult.getObfuscatedCode(), + /^var *test *= *'test';/ + ); + }); + + it('should\'t throw an error when string contains non-latin and non-digit characters and `unicodeEscapeSequence` is disabled', () => { + assert.doesNotThrow(() => JavaScriptObfuscator.obfuscate( + readFileAsString('./test/fixtures/node-transformers/node-obfuscators/literal-obfuscator/literal-obfuscator-unicode-sequence.js'), + { + ...NO_CUSTOM_NODES_PRESET, + stringArray: true, + stringArrayThreshold: 1, + unicodeEscapeSequence: false + } + )); + }); + it('shouldn\'t replace short literal node value with unicode array value', () => { let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( `var test = 'te';`, diff --git a/test/unit-tests/utils/Utils.spec.ts b/test/unit-tests/utils/Utils.spec.ts index e0304b4d..990fe83f 100644 --- a/test/unit-tests/utils/Utils.spec.ts +++ b/test/unit-tests/utils/Utils.spec.ts @@ -111,11 +111,16 @@ describe('Utils', () => { }); }); - describe('stringToUnicodeEscapeSequence (string: string): string', () => { - let expected: string = '\\x73\\x74\\x72\\x69\\x6e\\x67'; + describe('stringToUnicodeEscapeSequence (string: string, nonLatinAndNonDigitsOnly: boolean = false): string', () => { + const expected1: string = '\\x73\\x74\\x72\\x69\\x6e\\x67'; + const expected2: string = 'abc\\x21\\u0434\\u0435'; it('should return a unicode escape sequence based on a given string', () => { - assert.equal(Utils.stringToUnicodeEscapeSequence('string'), expected); + assert.equal(Utils.stringToUnicodeEscapeSequence('string'), expected1); + }); + + it('should return a string where only non-digits and non-latin letters are escaped', () => { + assert.equal(Utils.stringToUnicodeEscapeSequence('abc!де', true), expected2); }); }); });