Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 111 additions & 13 deletions src/custom-code-helpers/string-array/StringArrayCodeHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import { StringArrayTemplate } from './templates/string-array/StringArrayTemplat
import { AbstractCustomCodeHelper } from '../AbstractCustomCodeHelper';
import { NodeUtils } from '../../node/NodeUtils';
import { StringUtils } from '../../utils/StringUtils';
import { AtobTemplate } from './templates/string-array-calls-wrapper/AtobTemplate';
import { ICryptUtilsStringArray } from '../../interfaces/utils/ICryptUtilsStringArray';

@injectable()
export class StringArrayCodeHelper extends AbstractCustomCodeHelper {
Expand All @@ -32,21 +34,25 @@ export class StringArrayCodeHelper extends AbstractCustomCodeHelper {
*/
@initializable()
private stringArrayFunctionName!: string;
private readonly cryptUtilsStringArray: ICryptUtilsStringArray;
private prefixes: string[];

/**
* @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
* @param {ICustomCodeHelperFormatter} customCodeHelperFormatter
* @param {ICustomCodeHelperObfuscator} customCodeHelperObfuscator
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
* @param cryptUtilsStringArray
*/
public constructor(
@inject(ServiceIdentifiers.Factory__IIdentifierNamesGenerator)
identifierNamesGeneratorFactory: TIdentifierNamesGeneratorFactory,
@inject(ServiceIdentifiers.ICustomCodeHelperFormatter) customCodeHelperFormatter: ICustomCodeHelperFormatter,
@inject(ServiceIdentifiers.ICustomCodeHelperObfuscator) customCodeHelperObfuscator: ICustomCodeHelperObfuscator,
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IOptions) options: IOptions
@inject(ServiceIdentifiers.IOptions) options: IOptions,
@inject(ServiceIdentifiers.ICryptUtilsStringArray) cryptUtilsStringArray: ICryptUtilsStringArray
) {
super(
identifierNamesGeneratorFactory,
Expand All @@ -55,6 +61,9 @@ export class StringArrayCodeHelper extends AbstractCustomCodeHelper {
randomGenerator,
options
);

this.cryptUtilsStringArray = cryptUtilsStringArray;
this.prefixes = [];
}

/**
Expand All @@ -64,6 +73,12 @@ export class StringArrayCodeHelper extends AbstractCustomCodeHelper {
public initialize(stringArrayStorage: IStringArrayStorage, stringArrayFunctionName: string): void {
this.stringArrayStorage = stringArrayStorage;
this.stringArrayFunctionName = stringArrayFunctionName;
this.prefixes = [
this.generatePNGPrefix(),
this.generateJPGPrefix(),
this.generateWEBPPrefix(),
this.generateSVGPrefix()
];
}

/**
Expand All @@ -78,25 +93,108 @@ export class StringArrayCodeHelper extends AbstractCustomCodeHelper {
* @returns {string}
*/
protected override getCodeHelperTemplate(): string {
const stringArrayName: string = this.identifierNamesGenerator.generateNext();
const imageClassName: string = this.identifierNamesGenerator.generateNext();
const paramWidthName: string = this.identifierNamesGenerator.generateNext();
const paramHeightName: string = this.identifierNamesGenerator.generateNext();
const imageInstanceName: string = this.identifierNamesGenerator.generateNext();

const atobFunctionName: string = this.identifierNamesGenerator.generateNext();
const atobFunctionTemplate: string = this.identifierNamesGenerator.generateNext();

const atobPolyfill: string = this.customCodeHelperFormatter.formatTemplate(
AtobTemplate(this.options.selfDefending),
{
atobFunctionName
}
);

const imagePrefix: string = this.randomGenerator.getRandomGenerator().pickone(this.prefixes);
const payload = this.cryptUtilsStringArray.btoa(this.getStringArrayStorageItemsJSON());
const imageSrc: string = `'${StringUtils.escapeJsString(imagePrefix + payload)}'`;
const prefixLengthAkaWidth = imagePrefix.length;
const dummyHeight = Math.floor(
prefixLengthAkaWidth *
this.randomGenerator.getRandomGenerator().pickone([16 / 9, 9 / 16, 1, 3 / 4, 4 / 3, 1])
);

return this.customCodeHelperFormatter.formatTemplate(StringArrayTemplate(this.options.selfDefending), {
imageClassName: imageClassName,
paramWidthName: paramWidthName,
paramHeightName: paramHeightName,
imageInstanceName: imageInstanceName,

return this.customCodeHelperFormatter.formatTemplate(StringArrayTemplate(), {
stringArrayFunctionName: this.stringArrayFunctionName,
stringArrayName: stringArrayName,
stringArrayStorageItems: this.getEncodedStringArrayStorageItems()

atobPolyfill: atobPolyfill,
atobFunctionName: atobFunctionName,
atobFunctionTemplate: atobFunctionTemplate,
imageSrc: imageSrc,
imageWidth: prefixLengthAkaWidth,
imageHeight: dummyHeight
});
}

/**
* @returns {string}
*/
private getEncodedStringArrayStorageItems(): string {
return Array.from(this.stringArrayStorage.getStorage().values())
.map((stringArrayStorageItemData: IStringArrayStorageItemData): string => {
const escapedEncodedValue: string = StringUtils.escapeJsString(stringArrayStorageItemData.encodedValue);

return `'${escapedEncodedValue}'`;
})
.toString();
private getStringArrayStorageItemsJSON(): string {
return JSON.stringify(
Array.from(this.stringArrayStorage.getStorage().values()).map(
(stringArrayStorageItemData: IStringArrayStorageItemData): string =>
stringArrayStorageItemData.encodedValue
)
).toString();
}

private generatePNGPrefix(): string {
let imagePrefix: string = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA';
const iterations: number = this.randomGenerator.getRandomInteger(4, 8);
for (let i: number = 0; i < iterations; i++) {
imagePrefix += this.randomGenerator.getRandomString(this.randomGenerator.getRandomInteger(4, 8));
imagePrefix += 'A'.repeat(this.randomGenerator.getRandomInteger(2, 8));
}
imagePrefix += this.randomGenerator.getRandomString(this.randomGenerator.getRandomInteger(4, 64));
imagePrefix += 'A'.repeat(16 * this.randomGenerator.getRandomInteger(0, 1));
imagePrefix += this.randomGenerator.getRandomString(32 - (imagePrefix.length % 16));

return imagePrefix;
}

private generateJPGPrefix(): string {
let imagePrefix: string = 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAk';
const iterations: number = this.randomGenerator.getRandomInteger(4, 8);
for (let i: number = 0; i < iterations; i++) {
imagePrefix += this.randomGenerator.getRandomString(4 * this.randomGenerator.getRandomInteger(4, 8));
imagePrefix += '/';
}
imagePrefix += this.randomGenerator.getRandomString(this.randomGenerator.getRandomInteger(4, 64));
imagePrefix += 'A'.repeat(16 * this.randomGenerator.getRandomInteger(0, 1));
imagePrefix += this.randomGenerator.getRandomString(32 - (imagePrefix.length % 16));

return imagePrefix;
}

private generateWEBPPrefix(): string {
const randomThreeLetters = this.randomGenerator.getRandomString(3);
let imagePrefix: string = `data:image/webp;base64,UklGR${randomThreeLetters}AABXRUJQVlA4`;
const iterations: number = this.randomGenerator.getRandomInteger(4, 8);
for (let i: number = 0; i < iterations; i++) {
imagePrefix += this.randomGenerator.getRandomString(this.randomGenerator.getRandomInteger(8, 24));
imagePrefix += '/'.repeat(this.randomGenerator.getRandomInteger(1, 2));
}
imagePrefix += this.randomGenerator.getRandomString(this.randomGenerator.getRandomInteger(4, 64));
imagePrefix += 'A'.repeat(16 * this.randomGenerator.getRandomInteger(0, 1));
imagePrefix += this.randomGenerator.getRandomString(32 - (imagePrefix.length % 16));

return imagePrefix;
}

private generateSVGPrefix(): string {
let imagePrefix: string = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI';
imagePrefix += this.randomGenerator.getRandomString(this.randomGenerator.getRandomInteger(64, 256));
imagePrefix += 'A'.repeat(16 * this.randomGenerator.getRandomInteger(0, 1));
imagePrefix += this.randomGenerator.getRandomString(32 - (imagePrefix.length % 16));

return imagePrefix;
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,27 @@
/**
* @returns {string}
*/
export function StringArrayTemplate(): string {
export function StringArrayTemplate(selfDefending: boolean): string {
return `
function {imageClassName} ({paramWidthName}, {paramHeightName}) {
this.width = {paramWidthName};
this.height = {paramHeightName};
this.append = function(){
{atobPolyfill}
this.srcset = JSON.parse({atobFunctionName}(this.src.substr({paramWidthName})));
};
}

function {stringArrayFunctionName} () {
const {stringArrayName} = [{stringArrayStorageItems}];
const {imageInstanceName} = new {imageClassName}({imageWidth}, {imageHeight});
{imageInstanceName}.src = {imageSrc};
{imageInstanceName}.append();

{stringArrayFunctionName} = function () {
return {stringArrayName};
return {imageInstanceName}.srcset;
};

return {stringArrayFunctionName}();
return {imageInstanceName}.srcset;
}
`;
}
25 changes: 22 additions & 3 deletions test/dev/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,36 @@

let obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
`
(()=> {
var obj = {
foo: 1
};
console.log(obj['foo'], global.Math.random());
if(Math.random() < Date.now()){
for(let i=0; i<obj.foo; i++){
console.log(["Aeneas was a robust guy,",
"A kozak full of vim,",
"Full of the devil, lewd and spry,",
"There was no one like him.",
"And when the Greeks had burned down Troy",
"And made of it, to their great joy,",
"A heap of dung, he left that waste",
"Together with some Trojan tramps,",
"The sun-tanned scamps.",
"They all took to their heels in haste."].join("\\n"));
}
}
})();

`,
{
compact: false,
compact: true,
controlFlowFlattening: true,
controlFlowFlatteningThreshold: 1,
disableConsoleOutput: false,
identifierNamesGenerator: 'mangled',
log: true,
numbersToExpressions: true,
numbersToExpressions: false,
renameProperties: true,
renamePropertiesMode: 'safe',
simplify: false,
Expand All @@ -29,7 +47,8 @@
stringArrayWrappersChainedCalls: true,
stringArrayWrappersParametersMaxCount: 5,
stringArrayWrappersType: 'function',
stringArrayThreshold: 0,
stringArrayThreshold: 1,
stringArrayEncoding: ['rc4'],
transformObjectKeys: true,
unicodeEscapeSequence: false,
ignoreImports: false
Expand Down
Loading