From c364415a1351825ee9ea12cfcc110762327d64d9 Mon Sep 17 00:00:00 2001 From: sanex Date: Sun, 1 Aug 2021 22:00:23 +0300 Subject: [PATCH] Updated logic for random string array function position --- .../string-array/StringArrayCodeHelper.ts | 15 ++- .../group/StringArrayCodeHelperGroup.ts | 13 +- .../AtobTemplate.ts | 4 +- .../StringArrayCallsWrapperCodeHelper.spec.ts | 51 +++++++- .../StringArrayCodeHelper.spec.ts | 42 +++++-- .../StringArrayCallsWrapperTemplate.spec.ts | 112 +++++++++++++++++- 6 files changed, 207 insertions(+), 30 deletions(-) diff --git a/src/custom-code-helpers/string-array/StringArrayCodeHelper.ts b/src/custom-code-helpers/string-array/StringArrayCodeHelper.ts index e1c97f75..5f491b60 100644 --- a/src/custom-code-helpers/string-array/StringArrayCodeHelper.ts +++ b/src/custom-code-helpers/string-array/StringArrayCodeHelper.ts @@ -33,6 +33,12 @@ export class StringArrayCodeHelper extends AbstractCustomCodeHelper { @initializable() private stringArrayFunctionName!: string; + /** + * @type {string} + */ + @initializable() + private stringArrayName!: string; + /** * @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory * @param {ICustomCodeHelperFormatter} customCodeHelperFormatter @@ -60,13 +66,16 @@ export class StringArrayCodeHelper extends AbstractCustomCodeHelper { /** * @param {IStringArrayStorage} stringArrayStorage * @param {string} stringArrayFunctionName + * @param {string} stringArrayName */ public initialize ( stringArrayStorage: IStringArrayStorage, - stringArrayFunctionName: string + stringArrayFunctionName: string, + stringArrayName: string ): void { this.stringArrayStorage = stringArrayStorage; this.stringArrayFunctionName = stringArrayFunctionName; + this.stringArrayName = stringArrayName; } /** @@ -81,11 +90,9 @@ export class StringArrayCodeHelper extends AbstractCustomCodeHelper { * @returns {string} */ protected override getCodeHelperTemplate (): string { - const stringArrayName: string = this.identifierNamesGenerator.generateNext(); - return this.customCodeHelperFormatter.formatTemplate(StringArrayTemplate(), { stringArrayFunctionName: this.stringArrayFunctionName, - stringArrayName: stringArrayName, + stringArrayName: this.stringArrayName, stringArrayStorageItems: this.getEncodedStringArrayStorageItems() }); } diff --git a/src/custom-code-helpers/string-array/group/StringArrayCodeHelperGroup.ts b/src/custom-code-helpers/string-array/group/StringArrayCodeHelperGroup.ts index bb91b317..d97c1b1c 100644 --- a/src/custom-code-helpers/string-array/group/StringArrayCodeHelperGroup.ts +++ b/src/custom-code-helpers/string-array/group/StringArrayCodeHelperGroup.ts @@ -119,12 +119,18 @@ export class StringArrayCodeHelperGroup extends AbstractCustomCodeHelperGroup { return; } + const stringArrayFunctionName: string = this.stringArrayStorage.getStorageName(); + // stringArray helper initialize const stringArrayCodeHelper: ICustomCodeHelper> = this.customCodeHelperFactory(CustomCodeHelper.StringArray); - const stringArrayFunctionName: string = this.stringArrayStorage.getStorageName(); + const stringArrayName: string = this.identifierNamesGenerator.generateNext(); - stringArrayCodeHelper.initialize(this.stringArrayStorage, stringArrayFunctionName); + stringArrayCodeHelper.initialize( + this.stringArrayStorage, + stringArrayFunctionName, + stringArrayName + ); this.customCodeHelpers.set(CustomCodeHelper.StringArray, stringArrayCodeHelper); // stringArrayCallsWrapper helper initialize @@ -133,6 +139,7 @@ export class StringArrayCodeHelperGroup extends AbstractCustomCodeHelperGroup { const stringArrayCallsWrapperCodeHelper: ICustomCodeHelper> = this.customCodeHelperFactory(stringArrayCallsWrapperCodeHelperName); const stringArrayCallsWrapperName: string = this.stringArrayStorage.getStorageCallsWrapperName(stringArrayEncoding); + stringArrayCallsWrapperCodeHelper.initialize( stringArrayFunctionName, stringArrayCallsWrapperName, @@ -160,7 +167,7 @@ export class StringArrayCodeHelperGroup extends AbstractCustomCodeHelperGroup { private getScopeStatementRandomIndex (scopeStatements: TStatement[]): number { return this.randomGenerator.getRandomInteger( 0, - Math.max(0, scopeStatements.length - 1) + Math.max(0, scopeStatements.length) ); } } diff --git a/src/custom-code-helpers/string-array/templates/string-array-calls-wrapper/AtobTemplate.ts b/src/custom-code-helpers/string-array/templates/string-array-calls-wrapper/AtobTemplate.ts index a9c265c8..bedeec5f 100644 --- a/src/custom-code-helpers/string-array/templates/string-array-calls-wrapper/AtobTemplate.ts +++ b/src/custom-code-helpers/string-array/templates/string-array-calls-wrapper/AtobTemplate.ts @@ -17,12 +17,12 @@ export function AtobTemplate (selfDefending: boolean): string { for ( let bc = 0, bs, buffer, idx = 0; buffer = input.charAt(idx++); - ~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer, bc++ % 4) + ~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer, bc++ % 4) ? output += ${((): string => { const basePart: string = 'String.fromCharCode(255 & bs >> (-2 * bc & 6))'; return selfDefending - ? `(func.charCodeAt(idx + 10) - 10 ? ${basePart} : bc)` + ? `((func.charCodeAt(idx + 10) - 10 !== 0) ? ${basePart} : bc)` : basePart; })()} : 0 diff --git a/test/functional-tests/custom-code-helpers/string-array/StringArrayCallsWrapperCodeHelper.spec.ts b/test/functional-tests/custom-code-helpers/string-array/StringArrayCallsWrapperCodeHelper.spec.ts index 20a03ca3..22bb0a6a 100644 --- a/test/functional-tests/custom-code-helpers/string-array/StringArrayCallsWrapperCodeHelper.spec.ts +++ b/test/functional-tests/custom-code-helpers/string-array/StringArrayCallsWrapperCodeHelper.spec.ts @@ -10,7 +10,48 @@ import { readFileAsString } from '../../../helpers/readFileAsString'; import { JavaScriptObfuscator } from '../../../../src/JavaScriptObfuscatorFacade'; describe('StringArrayCallsWrapperCodeHelper', () => { - const regExp: RegExp = /_0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6} *- *0x0\;/; + const stringCallsWrapperRegExp: RegExp = /function _0x([a-f0-9]){4} *\(_0x([a-f0-9]){4,6} *,_0x([a-f0-9]){4,6}\)/; + + describe('`stringArray` option is set', () => { + const samplesCount: number = 100; + const stringArrayCallsWrapperAtFirstPositionRegExp: RegExp = new RegExp(`^${stringCallsWrapperRegExp.source}`); + const variableDeclarationAtFirstPositionRegExp: RegExp = /^var test *= *_0x([a-f0-9]){4}\(0x0\);/; + + let obfuscatedCode: string; + let stringArrayCallsWrapperAtFirstPositionMatchesCount: number = 0; + let variableDeclarationAtFirstPositionMatchesCount: number = 0; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/simple-input.js'); + + for (let i = 0; i < samplesCount; i++) { + obfuscatedCode = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_ADDITIONAL_NODES_PRESET, + stringArray: true, + stringArrayThreshold: 1 + } + ).getObfuscatedCode(); + + if (obfuscatedCode.match(stringArrayCallsWrapperAtFirstPositionRegExp)) { + stringArrayCallsWrapperAtFirstPositionMatchesCount++; + } + + if (obfuscatedCode.match(variableDeclarationAtFirstPositionRegExp)) { + variableDeclarationAtFirstPositionMatchesCount++; + } + } + }); + + it('Match #1: should correctly append code helper into the obfuscated code at random index', () => { + assert.isAbove(stringArrayCallsWrapperAtFirstPositionMatchesCount, 1); + }); + + it('Match #2: should correctly append code helper into the obfuscated code at random index', () => { + assert.isAbove(variableDeclarationAtFirstPositionMatchesCount, 1); + }); + }); describe('`stringArray` option is set', () => { let obfuscatedCode: string; @@ -29,7 +70,7 @@ describe('StringArrayCallsWrapperCodeHelper', () => { }); it('should correctly append code helper into the obfuscated code', () => { - assert.match(obfuscatedCode, regExp); + assert.match(obfuscatedCode, stringCallsWrapperRegExp); }); }); @@ -49,15 +90,15 @@ describe('StringArrayCallsWrapperCodeHelper', () => { }); it('shouldn\'t append code helper into the obfuscated code', () => { - assert.notMatch(obfuscatedCode, regExp); + assert.notMatch(obfuscatedCode, stringCallsWrapperRegExp); }); }); describe('Preserve string array name', () => { const callsWrapperRegExp: RegExp = new RegExp(`` + - `function *b *\\(c, *d\\) *{ *` + + `function *c *\\(b, *d\\) *{ *` + `var e *= *a\\(\\); *` + - `b *= *function *\\(f, *g\\) *{` + + `c *= *function *\\(f, *g\\) *{` + `f *= *f *- *0x0; *` + `var h *= *e\\[f]; *` + ``); diff --git a/test/functional-tests/custom-code-helpers/string-array/StringArrayCodeHelper.spec.ts b/test/functional-tests/custom-code-helpers/string-array/StringArrayCodeHelper.spec.ts index c189ce75..3b4fa970 100644 --- a/test/functional-tests/custom-code-helpers/string-array/StringArrayCodeHelper.spec.ts +++ b/test/functional-tests/custom-code-helpers/string-array/StringArrayCodeHelper.spec.ts @@ -8,26 +8,46 @@ import { readFileAsString } from '../../../helpers/readFileAsString'; import { JavaScriptObfuscator } from '../../../../src/JavaScriptObfuscatorFacade'; describe('StringArrayCodeHelper', () => { - const regExp: RegExp = getStringArrayRegExp(['test']); + const stringArrayRegExp: RegExp = getStringArrayRegExp(['test']); describe('`stringArray` option is set', () => { + const samplesCount: number = 100; + const stringArrayAtFirstPositionRegExp: RegExp = new RegExp(`^${stringArrayRegExp.source}`); + const variableDeclarationAtFirstPositionRegExp: RegExp = /^var test *= *_0x([a-f0-9]){4}\(0x0\);/; + let obfuscatedCode: string; + let stringArrayAtFirstPositionMatchesCount: number = 0; + let variableDeclarationAtFirstPositionMatchesCount: number = 0; before(() => { const code: string = readFileAsString(__dirname + '/fixtures/simple-input.js'); - obfuscatedCode = JavaScriptObfuscator.obfuscate( - code, - { - ...NO_ADDITIONAL_NODES_PRESET, - stringArray: true, - stringArrayThreshold: 1 + for (let i = 0; i < samplesCount; i++) { + obfuscatedCode = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_ADDITIONAL_NODES_PRESET, + stringArray: true, + stringArrayThreshold: 1 + } + ).getObfuscatedCode(); + + if (obfuscatedCode.match(stringArrayAtFirstPositionRegExp)) { + stringArrayAtFirstPositionMatchesCount++; } - ).getObfuscatedCode(); + + if (obfuscatedCode.match(variableDeclarationAtFirstPositionRegExp)) { + variableDeclarationAtFirstPositionMatchesCount++; + } + } }); - it('should correctly append code helper into the obfuscated code', () => { - assert.match(obfuscatedCode, regExp); + it('Match #1: should correctly append code helper into the obfuscated code at random index', () => { + assert.isAbove(stringArrayAtFirstPositionMatchesCount, 1); + }); + + it('Match #2: should correctly append code helper into the obfuscated code at random index', () => { + assert.isAbove(variableDeclarationAtFirstPositionMatchesCount, 1); }); }); @@ -47,7 +67,7 @@ describe('StringArrayCodeHelper', () => { }); it('shouldn\'t append code helper into the obfuscated code', () => { - assert.notMatch(obfuscatedCode, regExp); + assert.notMatch(obfuscatedCode, stringArrayRegExp); }); }); }); diff --git a/test/functional-tests/custom-code-helpers/string-array/templates/string-array-calls-wrapper-node-template/StringArrayCallsWrapperTemplate.spec.ts b/test/functional-tests/custom-code-helpers/string-array/templates/string-array-calls-wrapper-node-template/StringArrayCallsWrapperTemplate.spec.ts index 49af7017..31f74032 100644 --- a/test/functional-tests/custom-code-helpers/string-array/templates/string-array-calls-wrapper-node-template/StringArrayCallsWrapperTemplate.spec.ts +++ b/test/functional-tests/custom-code-helpers/string-array/templates/string-array-calls-wrapper-node-template/StringArrayCallsWrapperTemplate.spec.ts @@ -207,7 +207,7 @@ describe('StringArrayCallsWrapperTemplate', () => { const selfDefendingEnabled: boolean = true; describe('Variant #1: correct code evaluation for single-line code', () => { - describe('Variant #1: index shift amount is `0`', () => { + describe('Variant #1: long decoded string', () => { const index: string = '0x0'; const indexShiftAmount: number = 0; @@ -258,10 +258,62 @@ describe('StringArrayCallsWrapperTemplate', () => { assert.deepEqual(decodedValue, expectedDecodedValue); }); }); + + describe('Variant #2: 3-characters decoded string', () => { + const index: string = '0x0'; + + const indexShiftAmount: number = 0; + + const expectedDecodedValue: string = 'foo'; + + let decodedValue: string; + + before(async() => { + const stringArrayTemplate = format(StringArrayTemplate(), { + stringArrayName, + stringArrayFunctionName, + stringArrayStorageItems: `'${cryptUtilsSwappedAlphabet.btoa('foo')}'` + }); + const atobPolyfill = format(AtobTemplate(selfDefendingEnabled), { + atobFunctionName + }); + const atobDecodeTemplate: string = format( + StringArrayBase64DecodeTemplate(randomGenerator), + { + atobPolyfill, + atobFunctionName, + selfDefendingCode: '', + stringArrayCacheName, + stringArrayCallsWrapperName + } + ); + const stringArrayCallsWrapperTemplate: string = await minimizeCode( + format(StringArrayCallsWrapperTemplate(), { + decodeCodeHelperTemplate: atobDecodeTemplate, + indexShiftAmount, + stringArrayCacheName, + stringArrayCallsWrapperName, + stringArrayFunctionName + }) + ); + + decodedValue = Function(` + ${stringArrayTemplate} + + ${stringArrayCallsWrapperTemplate} + + return ${stringArrayCallsWrapperName}(${index}); + `)(); + }); + + it('should correctly return decoded value', () => { + assert.deepEqual(decodedValue, expectedDecodedValue); + }); + }); }); describe('Variant #2: invalid code evaluation for multi-line code', () => { - describe('Variant #1: index shift amount is `0`', () => { + describe('Variant #1: long decoded string', () => { const index: string = '0x0'; const indexShiftAmount: number = 0; @@ -306,7 +358,57 @@ describe('StringArrayCallsWrapperTemplate', () => { `)(); }); - it('should correctly return decoded value', () => { + it('should return invalid decoded value', () => { + assert.deepEqual(decodedValue, expectedDecodedValue); + }); + }); + + describe('Variant #2: 3-characters decoded string', () => { + const index: string = '0x0'; + + const indexShiftAmount: number = 0; + + const expectedDecodedValue: string = 'foo'; + + let decodedValue: string; + + before(() => { + const stringArrayTemplate = format(StringArrayTemplate(), { + stringArrayName, + stringArrayFunctionName, + stringArrayStorageItems: `'${cryptUtilsSwappedAlphabet.btoa('foo')}'` + }); + const atobPolyfill = format(AtobTemplate(selfDefendingEnabled), { + atobFunctionName + }); + const atobDecodeTemplate: string = format( + StringArrayBase64DecodeTemplate(randomGenerator), + { + atobPolyfill, + atobFunctionName, + selfDefendingCode: '', + stringArrayCacheName, + stringArrayCallsWrapperName + } + ); + const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), { + decodeCodeHelperTemplate: atobDecodeTemplate, + indexShiftAmount, + stringArrayCacheName, + stringArrayCallsWrapperName, + stringArrayFunctionName + }); + + decodedValue = Function(` + ${stringArrayTemplate} + + ${stringArrayCallsWrapperTemplate} + + return ${stringArrayCallsWrapperName}(${index}); + `)(); + }); + + it('should return invalid decoded value', () => { assert.deepEqual(decodedValue, expectedDecodedValue); }); }); @@ -435,7 +537,7 @@ describe('StringArrayCallsWrapperTemplate', () => { const selfDefendingEnabled: boolean = true; describe('Variant #1: correct code evaluation for single-line code', () => { - describe('Variant #1: index shift amount is `0`', () => { + describe('Variant #1: long decoded string', () => { const index: string = '0x0'; const key: string = 'key'; @@ -497,7 +599,7 @@ describe('StringArrayCallsWrapperTemplate', () => { }); describe('Variant #2: invalid code evaluation for multi-line code', () => { - describe('Variant #1: index shift amount is `0`', () => { + describe('Variant #1: long decoded string', () => { const index: string = '0x0'; const key: string = 'key';