Mixed string array encoding: additional refactoring, validation and README.md update

This commit is contained in:
sanex
2020-08-30 18:19:09 +03:00
parent 752fa6baa2
commit aac5d1d007
14 changed files with 168 additions and 127 deletions
+12 -11
View File
@@ -355,7 +355,7 @@ Following options are available for the JS Obfuscator:
splitStrings: false,
splitStringsChunkLength: 10,
stringArray: true,
stringArrayEncoding: false,
stringArrayEncoding: [],
stringArrayThreshold: 0.75,
target: 'browser',
transformObjectKeys: false,
@@ -403,7 +403,7 @@ Following options are available for the JS Obfuscator:
--split-strings <boolean>
--split-strings-chunk-length <number>
--string-array <boolean>
--string-array-encoding <boolean|string> [true, false, base64, rc4]
--string-array-encoding '<list>' (comma separated) [none, base64, rc4]
--string-array-threshold <number>
--target <string> [browser, browser-no-eval, node]
--transform-object-keys <boolean>
@@ -919,7 +919,7 @@ Type: `boolean` Default: `true`
Removes string literals and place them in a special array. For instance, the string `"Hello World"` in `var m = "Hello World";` will be replaced with something like `var m = _0x12c456[0x1];`
### `stringArrayEncoding`
Type: `boolean|string` Default: `false`
Type: `string[]` Default: `[]`
##### :warning: `stringArray` option must be enabled
@@ -927,11 +927,12 @@ This option can slow down your script.
Encode all string literals of the [`stringArray`](#stringarray) using `base64` or `rc4` and inserts a special code that used to decode it back at runtime.
Each `stringArray` value will be encoded by the randomly picked encoding from the passed list.
Available values:
* `true` (`boolean`): encode `stringArray` values using `base64`
* `false` (`boolean`): don't encode `stringArray` values
* `'base64'` (`string`): encode `stringArray` values using `base64`
* `'rc4'` (`string`): encode `stringArray` values using `rc4`. **About 30-50% slower than `base64`, but more harder to get initial values.** It is recommended to disable [`unicodeEscapeSequence`](#unicodeescapesequence) option with `rc4` encoding to prevent very large size of obfuscated code.
* `'none'` (`boolean`): doesn't encode `stringArray` value
* `'base64'` (`string`): encodes `stringArray` value using `base64`
* `'rc4'` (`string`): encodes `stringArray` value using `rc4`. **About 30-50% slower than `base64`, but more harder to get initial values.** It's recommended to disable [`unicodeEscapeSequence`](#unicodeescapesequence) option when using `rc4` encoding to prevent very large size of obfuscated code.
### `stringArrayThreshold`
Type: `number` Default: `0.8` Min: `0` Max: `1`
@@ -1030,7 +1031,7 @@ Performance will 50-100% slower than without obfuscation
splitStrings: true,
splitStringsChunkLength: 5,
stringArray: true,
stringArrayEncoding: 'rc4',
stringArrayEncoding: ['rc4'],
stringArrayThreshold: 1,
transformObjectKeys: true,
unicodeEscapeSequence: false
@@ -1062,7 +1063,7 @@ Performance will 30-35% slower than without obfuscation
splitStrings: true,
splitStringsChunkLength: 10,
stringArray: true,
stringArrayEncoding: 'base64',
stringArrayEncoding: ['base64'],
stringArrayThreshold: 0.75,
transformObjectKeys: true,
unicodeEscapeSequence: false
@@ -1091,7 +1092,7 @@ Performance will slightly slower than without obfuscation
simplify: true,
splitStrings: false,
stringArray: true,
stringArrayEncoding: false,
stringArrayEncoding: [],
stringArrayThreshold: 0.75,
unicodeEscapeSequence: false
}
@@ -1117,7 +1118,7 @@ Performance will slightly slower than without obfuscation
simplify: true,
splitStrings: false,
stringArray: true,
stringArrayEncoding: false,
stringArrayEncoding: [],
stringArrayThreshold: 0.75,
unicodeEscapeSequence: false
}
+7 -7
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
@@ -26,6 +26,8 @@ import { DomainLockCodeHelper } from '../../../custom-code-helpers/domain-lock/D
import { CallsControllerFunctionCodeHelper } from '../../../custom-code-helpers/calls-controller/CallsControllerFunctionCodeHelper';
import { SelfDefendingUnicodeCodeHelper } from '../../../custom-code-helpers/self-defending/SelfDefendingUnicodeCodeHelper';
import { StringArrayCallsWrapperCodeHelper } from '../../../custom-code-helpers/string-array/StringArrayCallsWrapperCodeHelper';
import { StringArrayCallsWrapperBase64CodeHelper } from '../../../custom-code-helpers/string-array/StringArrayCallsWrapperBase64CodeHelper';
import { StringArrayCallsWrapperRc4CodeHelper } from '../../../custom-code-helpers/string-array/StringArrayCallsWrapperRc4CodeHelper';
import { StringArrayCodeHelper } from '../../../custom-code-helpers/string-array/StringArrayCodeHelper';
import { StringArrayRotateFunctionCodeHelper } from '../../../custom-code-helpers/string-array/StringArrayRotateFunctionCodeHelper';
@@ -63,6 +65,14 @@ export const customCodeHelpersModule: interfaces.ContainerModule = new Container
.to(StringArrayCallsWrapperCodeHelper)
.whenTargetNamed(CustomCodeHelper.StringArrayCallsWrapper);
bind<ICustomCodeHelper>(ServiceIdentifiers.ICustomCodeHelper)
.to(StringArrayCallsWrapperBase64CodeHelper)
.whenTargetNamed(CustomCodeHelper.StringArrayCallsWrapperBase64);
bind<ICustomCodeHelper>(ServiceIdentifiers.ICustomCodeHelper)
.to(StringArrayCallsWrapperRc4CodeHelper)
.whenTargetNamed(CustomCodeHelper.StringArrayCallsWrapperRc4);
bind<ICustomCodeHelper>(ServiceIdentifiers.ICustomCodeHelper)
.to(StringArrayCodeHelper)
.whenTargetNamed(CustomCodeHelper.StringArray);
@@ -0,0 +1,32 @@
import { injectable, } from 'inversify';
import { AtobTemplate } from './templates/string-array-calls-wrapper/AtobTemplate';
import { StringArrayCallsWrapperCodeHelper } from './StringArrayCallsWrapperCodeHelper';
import { StringArrayBase64DecodeTemplate } from './templates/string-array-calls-wrapper/StringArrayBase64DecodeTemplate';
@injectable()
export class StringArrayCallsWrapperBase64CodeHelper extends StringArrayCallsWrapperCodeHelper {
/**
* @returns {string}
*/
protected getDecodeStringArrayTemplate (): string {
const atobFunctionName: string = this.randomGenerator.getRandomString(6);
const atobPolyfill: string = this.customCodeHelperFormatter.formatTemplate(AtobTemplate(), {
atobFunctionName: atobFunctionName
});
const selfDefendingCode: string = this.getSelfDefendingTemplate();
return this.customCodeHelperFormatter.formatTemplate(
StringArrayBase64DecodeTemplate(this.randomGenerator),
{
atobPolyfill,
atobFunctionName,
selfDefendingCode,
stringArrayCallsWrapperName: this.stringArrayCallsWrapperName
}
);
}
}
@@ -3,7 +3,6 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import { TIdentifierNamesGeneratorFactory } from '../../types/container/generators/TIdentifierNamesGeneratorFactory';
import { TStatement } from '../../types/node/TStatement';
import { TStringArrayEncoding } from '../../types/options/TStringArrayEncoding';
import { ICustomCodeHelperFormatter } from '../../interfaces/custom-code-helpers/ICustomCodeHelperFormatter';
import { ICustomCodeHelperObfuscator } from '../../interfaces/custom-code-helpers/ICustomCodeHelperObfuscator';
@@ -11,16 +10,10 @@ import { IEscapeSequenceEncoder } from '../../interfaces/utils/IEscapeSequenceEn
import { IOptions } from '../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
import { StringArrayEncoding } from '../../enums/StringArrayEncoding';
import { initializable } from '../../decorators/Initializable';
import { AtobTemplate } from './templates/string-array-calls-wrapper/AtobTemplate';
import { Rc4Template } from './templates/string-array-calls-wrapper/Rc4Template';
import { SelfDefendingTemplate } from './templates/string-array-calls-wrapper/SelfDefendingTemplate';
import { StringArrayBase64DecodeTemplate } from './templates/string-array-calls-wrapper/StringArrayBase64DecodeTemplate';
import { StringArrayCallsWrapperTemplate } from './templates/string-array-calls-wrapper/StringArrayCallsWrapperTemplate';
import { StringArrayRC4DecodeTemplate } from './templates/string-array-calls-wrapper/StringArrayRC4DecodeTemplate';
import { AbstractCustomCodeHelper } from '../AbstractCustomCodeHelper';
import { NodeUtils } from '../../node/NodeUtils';
@@ -31,25 +24,13 @@ export class StringArrayCallsWrapperCodeHelper extends AbstractCustomCodeHelper
* @type {string}
*/
@initializable()
private atobFunctionName!: string;
protected stringArrayName!: string;
/**
* @type {string}
*/
@initializable()
private stringArrayName!: string;
/**
* @type {string}
*/
@initializable()
private stringArrayCallsWrapperName!: string;
/**
* @type {TStringArrayEncoding}
*/
@initializable()
private stringArrayEncoding!: TStringArrayEncoding;
protected stringArrayCallsWrapperName!: string;
/**
* @type {IEscapeSequenceEncoder}
@@ -87,19 +68,13 @@ export class StringArrayCallsWrapperCodeHelper extends AbstractCustomCodeHelper
/**
* @param {string} stringArrayName
* @param {string} stringArrayCallsWrapperName
* @param {TStringArrayEncoding} stringArrayEncoding
* @param {string} atobFunctionName
*/
public initialize (
stringArrayName: string,
stringArrayCallsWrapperName: string,
stringArrayEncoding: TStringArrayEncoding,
atobFunctionName: string
stringArrayCallsWrapperName: string
): void {
this.stringArrayName = stringArrayName;
this.stringArrayCallsWrapperName = stringArrayCallsWrapperName;
this.stringArrayEncoding = stringArrayEncoding;
this.atobFunctionName = atobFunctionName;
}
/**
@@ -133,56 +108,27 @@ export class StringArrayCallsWrapperCodeHelper extends AbstractCustomCodeHelper
/**
* @returns {string}
*/
private getDecodeStringArrayTemplate (): string {
const atobPolyfill: string = this.customCodeHelperFormatter.formatTemplate(AtobTemplate(), {
atobFunctionName: this.atobFunctionName
});
const rc4Polyfill: string = this.customCodeHelperFormatter.formatTemplate(Rc4Template(), {
atobFunctionName: this.atobFunctionName
});
protected getDecodeStringArrayTemplate (): string {
return '';
}
let decodeStringArrayTemplate: string = '';
let selfDefendingCode: string = '';
if (this.options.selfDefending) {
selfDefendingCode = this.customCodeHelperFormatter.formatTemplate(
SelfDefendingTemplate(
this.randomGenerator,
this.escapeSequenceEncoder
),
{
stringArrayCallsWrapperName: this.stringArrayCallsWrapperName,
stringArrayName: this.stringArrayName
}
);
/**
* @returns {string}
*/
protected getSelfDefendingTemplate (): string {
if (!this.options.selfDefending) {
return '';
}
switch (this.stringArrayEncoding) {
case StringArrayEncoding.Rc4:
decodeStringArrayTemplate = this.customCodeHelperFormatter.formatTemplate(
StringArrayRC4DecodeTemplate(this.randomGenerator),
{
atobPolyfill,
rc4Polyfill,
selfDefendingCode,
stringArrayCallsWrapperName: this.stringArrayCallsWrapperName
}
);
break;
case StringArrayEncoding.Base64:
decodeStringArrayTemplate = this.customCodeHelperFormatter.formatTemplate(
StringArrayBase64DecodeTemplate(this.randomGenerator),
{
atobPolyfill,
atobFunctionName: this.atobFunctionName,
selfDefendingCode,
stringArrayCallsWrapperName: this.stringArrayCallsWrapperName
}
);
}
return decodeStringArrayTemplate;
return this.customCodeHelperFormatter.formatTemplate(
SelfDefendingTemplate(
this.randomGenerator,
this.escapeSequenceEncoder
),
{
stringArrayCallsWrapperName: this.stringArrayCallsWrapperName,
stringArrayName: this.stringArrayName
}
);
}
}
@@ -0,0 +1,36 @@
import { injectable, } from 'inversify';
import { AtobTemplate } from './templates/string-array-calls-wrapper/AtobTemplate';
import { Rc4Template } from './templates/string-array-calls-wrapper/Rc4Template';
import { StringArrayRC4DecodeTemplate } from './templates/string-array-calls-wrapper/StringArrayRC4DecodeTemplate';
import { StringArrayCallsWrapperCodeHelper } from './StringArrayCallsWrapperCodeHelper';
@injectable()
export class StringArrayCallsWrapperRc4CodeHelper extends StringArrayCallsWrapperCodeHelper {
/**
* @returns {string}
*/
protected getDecodeStringArrayTemplate (): string {
const atobFunctionName: string = this.randomGenerator.getRandomString(6);
const atobPolyfill: string = this.customCodeHelperFormatter.formatTemplate(AtobTemplate(), {
atobFunctionName
});
const rc4Polyfill: string = this.customCodeHelperFormatter.formatTemplate(Rc4Template(), {
atobFunctionName
});
const selfDefendingCode: string = this.getSelfDefendingTemplate();
return this.customCodeHelperFormatter.formatTemplate(
StringArrayRC4DecodeTemplate(this.randomGenerator),
{
atobPolyfill,
rc4Polyfill,
selfDefendingCode,
stringArrayCallsWrapperName: this.stringArrayCallsWrapperName
}
);
}
}
@@ -5,6 +5,7 @@ import { TCustomCodeHelperFactory } from '../../../types/container/custom-code-h
import { TIdentifierNamesGeneratorFactory } from '../../../types/container/generators/TIdentifierNamesGeneratorFactory';
import { TInitialData } from '../../../types/TInitialData';
import { TNodeWithStatements } from '../../../types/node/TNodeWithStatements';
import { TStringArrayEncoding } from '../../../types/options/TStringArrayEncoding';
import { ICallsGraphData } from '../../../interfaces/analyzers/calls-graph-analyzer/ICallsGraphData';
import { ICustomCodeHelper } from '../../../interfaces/custom-code-helpers/ICustomCodeHelper';
@@ -16,15 +17,25 @@ import { initializable } from '../../../decorators/Initializable';
import { CustomCodeHelper } from '../../../enums/custom-code-helpers/CustomCodeHelper';
import { ObfuscationEvent } from '../../../enums/event-emitters/ObfuscationEvent';
import { StringArrayEncoding } from '../../../enums/StringArrayEncoding';
import { AbstractCustomCodeHelperGroup } from '../../AbstractCustomCodeHelperGroup';
import { NodeAppender } from '../../../node/NodeAppender';
import { StringArrayCodeHelper } from '../StringArrayCodeHelper';
import { StringArrayCallsWrapperCodeHelper } from '../StringArrayCallsWrapperCodeHelper';
import { StringArrayCodeHelper } from '../StringArrayCodeHelper';
import { StringArrayRotateFunctionCodeHelper } from '../StringArrayRotateFunctionCodeHelper';
@injectable()
export class StringArrayCodeHelperGroup extends AbstractCustomCodeHelperGroup {
/**
* @type {Map<TStringArrayEncoding, CustomCodeHelper>}
*/
private static readonly stringArrayCallsWrapperCodeHelperMap: Map<TStringArrayEncoding, CustomCodeHelper> = new Map([
[StringArrayEncoding.None, CustomCodeHelper.StringArrayCallsWrapper],
[StringArrayEncoding.Base64, CustomCodeHelper.StringArrayCallsWrapperBase64],
[StringArrayEncoding.Rc4, CustomCodeHelper.StringArrayCallsWrapperRc4]
]);
/**
* @type {Map<CustomCodeHelper, ICustomCodeHelper>}
*/
@@ -86,8 +97,10 @@ export class StringArrayCodeHelperGroup extends AbstractCustomCodeHelperGroup {
// stringArrayCallsWrapper helper nodes append
for (const stringArrayEncoding of this.options.stringArrayEncoding) {
const stringArrayCallsWrapperCodeHelperName: CustomCodeHelper = this.getStringArrayCallsWrapperCodeHelperName(stringArrayEncoding);
this.appendCustomNodeIfExist(
<any>`${CustomCodeHelper.StringArrayCallsWrapper}-${stringArrayEncoding}`,
stringArrayCallsWrapperCodeHelperName,
(customCodeHelper: ICustomCodeHelper<TInitialData<StringArrayCallsWrapperCodeHelper>>) => {
NodeAppender.insertAtIndex(nodeWithStatements, customCodeHelper.getNode(), 1);
}
@@ -110,9 +123,7 @@ export class StringArrayCodeHelperGroup extends AbstractCustomCodeHelperGroup {
return;
}
/**
* Stage 1: String Array code helper
*/
// stringArray helper initialize
const stringArrayCodeHelper: ICustomCodeHelper<TInitialData<StringArrayCodeHelper>> =
this.customCodeHelperFactory(CustomCodeHelper.StringArray);
const stringArrayName: string = this.stringArrayStorage.getStorageName();
@@ -120,29 +131,22 @@ export class StringArrayCodeHelperGroup extends AbstractCustomCodeHelperGroup {
stringArrayCodeHelper.initialize(this.stringArrayStorage, stringArrayName);
this.customCodeHelpers.set(CustomCodeHelper.StringArray, stringArrayCodeHelper);
/**
* Stage 2: String Array calls wrapper code helper
*/
const atobFunctionName: string = this.randomGenerator.getRandomString(6);
// stringArrayCallsWrapper helper initialize
for (const stringArrayEncoding of this.options.stringArrayEncoding) {
const stringArrayCallsWrapperCodeHelperName: CustomCodeHelper = this.getStringArrayCallsWrapperCodeHelperName(stringArrayEncoding);
const stringArrayCallsWrapperCodeHelper: ICustomCodeHelper<TInitialData<StringArrayCallsWrapperCodeHelper>> =
this.customCodeHelperFactory(CustomCodeHelper.StringArrayCallsWrapper);
this.customCodeHelperFactory(stringArrayCallsWrapperCodeHelperName);
const stringArrayCallsWrapperName: string = this.stringArrayStorage.getStorageCallsWrapperName(stringArrayEncoding);
stringArrayCallsWrapperCodeHelper.initialize(
stringArrayName,
stringArrayCallsWrapperName,
stringArrayEncoding,
atobFunctionName
stringArrayCallsWrapperName
);
this.customCodeHelpers.set(<any>`${CustomCodeHelper.StringArrayCallsWrapper}-${stringArrayEncoding}`, stringArrayCallsWrapperCodeHelper);
this.customCodeHelpers.set(stringArrayCallsWrapperCodeHelperName, stringArrayCallsWrapperCodeHelper);
}
/**
* Stage 3: String Array rotate function
*/
// stringArrayRotateFunction helper initialize
const stringArrayRotateFunctionCodeHelper: ICustomCodeHelper<TInitialData<StringArrayRotateFunctionCodeHelper>> =
this.customCodeHelperFactory(CustomCodeHelper.StringArrayRotateFunction);
const stringArrayRotationAmount: number = this.stringArrayStorage.getRotationAmount();
@@ -153,4 +157,14 @@ export class StringArrayCodeHelperGroup extends AbstractCustomCodeHelperGroup {
this.customCodeHelpers.set(CustomCodeHelper.StringArrayRotateFunction, stringArrayRotateFunctionCodeHelper);
}
}
/**
* @param {TStringArrayEncoding} stringArrayEncoding
* @returns {CustomCodeHelper}
*/
private getStringArrayCallsWrapperCodeHelperName (stringArrayEncoding: TStringArrayEncoding): CustomCodeHelper {
return StringArrayCodeHelperGroup
.stringArrayCallsWrapperCodeHelperMap.get(stringArrayEncoding)
?? CustomCodeHelper.StringArrayCallsWrapper;
}
}
@@ -6,7 +6,9 @@ export enum CustomCodeHelper {
DebugProtectionFunction = 'DebugProtectionFunction',
DomainLock = 'DomainLock',
SelfDefendingUnicode = 'SelfDefendingUnicode',
StringArrayCallsWrapper = 'StringArrayCallsWrapper',
StringArray = 'StringArray',
StringArrayCallsWrapper = 'StringArrayCallsWrapper',
StringArrayCallsWrapperBase64 = 'StringArrayCallsWrapperBase64',
StringArrayCallsWrapperRc4 = 'StringArrayCallsWrapperRc4',
StringArrayRotateFunction = 'StringArrayRotateFunction'
}
+2 -3
View File
@@ -30,6 +30,7 @@ import { IdentifierNamesGenerator } from '../enums/generators/identifier-names-g
import { ObfuscationTarget } from '../enums/ObfuscationTarget';
import { OptionsPreset } from '../enums/options/presets/OptionsPreset';
import { SourceMapMode } from '../enums/source-map/SourceMapMode';
import { StringArrayEncoding } from '../enums/StringArrayEncoding';
import { DEFAULT_PRESET } from './presets/Default';
import { LOW_OBFUSCATION_PRESET } from './presets/LowObfuscation';
@@ -292,9 +293,7 @@ export class Options implements IOptions {
*/
@IsArray()
@ArrayUnique()
@IsString({
each: true
})
@IsIn([StringArrayEncoding.None, StringArrayEncoding.Base64, StringArrayEncoding.Rc4], { each: true })
public readonly stringArrayEncoding!: TStringArrayEncoding[];
/**
+1 -7
View File
@@ -1,7 +1,5 @@
'use strict';
import { StringArrayEncoding } from '../../src/enums/StringArrayEncoding';
import { NO_ADDITIONAL_NODES_PRESET } from '../../src/options/presets/NoCustomNodes';
(function () {
@@ -21,11 +19,7 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../src/options/presets/NoCustomNo
compact: false,
stringArray: true,
stringArrayThreshold: 1,
stringArrayEncoding: [
StringArrayEncoding.Rc4,
StringArrayEncoding.Base64,
StringArrayEncoding.None
]
stringArrayEncoding: []
}
).getObfuscatedCode();
@@ -841,7 +841,10 @@ describe('JavaScriptObfuscator', () => {
renameProperties: true,
rotateStringArray: true,
stringArray: true,
stringArrayEncoding: [StringArrayEncoding.Rc4],
stringArrayEncoding: [
StringArrayEncoding.Base64,
StringArrayEncoding.Rc4
],
stringArrayThreshold: 1,
transformObjectKeys: true,
unicodeEscapeSequence: false
@@ -34,7 +34,11 @@ describe('JavaScriptObfuscator runtime eval', function () {
splitStrings: true,
splitStringsChunkLength: 5,
stringArray: true,
stringArrayEncoding: [StringArrayEncoding.Rc4],
stringArrayEncoding: [
StringArrayEncoding.None,
StringArrayEncoding.Base64,
StringArrayEncoding.Rc4
],
stringArrayThreshold: 1,
transformObjectKeys: true,
unicodeEscapeSequence: true