mirror of
https://github.com/javascript-obfuscator/javascript-obfuscator
synced 2026-08-09 12:42:29 +00:00
315 lines
14 KiB
TypeScript
315 lines
14 KiB
TypeScript
import { inject, injectable } from 'inversify';
|
|
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
|
|
|
|
import * as ESTree from 'estree';
|
|
|
|
import { TInitialData } from '../../types/TInitialData';
|
|
import { TNodeWithLexicalScopeStatements } from '../../types/node/TNodeWithLexicalScopeStatements';
|
|
import { TStatement } from '../../types/node/TStatement';
|
|
import { TStringArrayScopeCallsWrappersDataByEncoding } from '../../types/node-transformers/string-array-transformers/TStringArrayScopeCallsWrappersDataByEncoding';
|
|
import { TStringArrayCustomNodeFactory } from '../../types/container/custom-nodes/TStringArrayCustomNodeFactory';
|
|
|
|
import { ICustomNode } from '../../interfaces/custom-nodes/ICustomNode';
|
|
import { IOptions } from '../../interfaces/options/IOptions';
|
|
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
|
|
import { IStringArrayScopeCallsWrapperData } from '../../interfaces/node-transformers/string-array-transformers/IStringArrayScopeCallsWrapperData';
|
|
import { IStringArrayScopeCallsWrappersData } from '../../interfaces/node-transformers/string-array-transformers/IStringArrayScopeCallsWrappersData';
|
|
import { IStringArrayScopeCallsWrappersDataStorage } from '../../interfaces/storages/string-array-transformers/IStringArrayScopeCallsWrappersDataStorage';
|
|
import { IStringArrayStorage } from '../../interfaces/storages/string-array-transformers/IStringArrayStorage';
|
|
import { IVisitedLexicalScopeNodesStackStorage } from '../../interfaces/storages/string-array-transformers/IVisitedLexicalScopeNodesStackStorage';
|
|
import { IVisitor } from '../../interfaces/node-transformers/IVisitor';
|
|
|
|
import { NodeTransformer } from '../../enums/node-transformers/NodeTransformer';
|
|
import { NodeTransformationStage } from '../../enums/node-transformers/NodeTransformationStage';
|
|
import { StringArrayCustomNode } from '../../enums/custom-nodes/StringArrayCustomNode';
|
|
import { StringArrayWrappersType } from '../../enums/node-transformers/string-array-transformers/StringArrayWrappersType';
|
|
|
|
import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
|
|
import { NodeAppender } from '../../node/NodeAppender';
|
|
import { NodeGuards } from '../../node/NodeGuards';
|
|
import { StringArrayScopeCallsWrapperFunctionNode } from '../../custom-nodes/string-array-nodes/StringArrayScopeCallsWrapperFunctionNode';
|
|
import { StringArrayScopeCallsWrapperVariableNode } from '../../custom-nodes/string-array-nodes/StringArrayScopeCallsWrapperVariableNode';
|
|
|
|
@injectable()
|
|
export class StringArrayScopeCallsWrapperTransformer extends AbstractNodeTransformer {
|
|
/**
|
|
* @type {NodeTransformer[]}
|
|
*/
|
|
public override readonly runAfter: NodeTransformer[] = [NodeTransformer.StringArrayRotateFunctionTransformer];
|
|
|
|
/**
|
|
* @type {IStringArrayStorage}
|
|
*/
|
|
private readonly stringArrayStorage: IStringArrayStorage;
|
|
|
|
/**
|
|
* @type {IStringArrayScopeCallsWrappersDataStorage}
|
|
*/
|
|
private readonly stringArrayScopeCallsWrappersDataStorage: IStringArrayScopeCallsWrappersDataStorage;
|
|
|
|
/**
|
|
* @type {TStringArrayCustomNodeFactory}
|
|
*/
|
|
private readonly stringArrayTransformerCustomNodeFactory: TStringArrayCustomNodeFactory;
|
|
|
|
/**
|
|
* @type {IVisitedLexicalScopeNodesStackStorage}
|
|
*/
|
|
private readonly visitedLexicalScopeNodesStackStorage: IVisitedLexicalScopeNodesStackStorage;
|
|
|
|
/**
|
|
* @param {IRandomGenerator} randomGenerator
|
|
* @param {IOptions} options
|
|
* @param {IVisitedLexicalScopeNodesStackStorage} visitedLexicalScopeNodesStackStorage
|
|
* @param {IStringArrayStorage} stringArrayStorage
|
|
* @param {IStringArrayScopeCallsWrappersDataStorage} stringArrayScopeCallsWrappersDataStorage
|
|
* @param {TStringArrayCustomNodeFactory} stringArrayTransformerCustomNodeFactory
|
|
*/
|
|
public constructor(
|
|
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
|
|
@inject(ServiceIdentifiers.IOptions) options: IOptions,
|
|
@inject(ServiceIdentifiers.IVisitedLexicalScopeNodesStackStorage)
|
|
visitedLexicalScopeNodesStackStorage: IVisitedLexicalScopeNodesStackStorage,
|
|
@inject(ServiceIdentifiers.IStringArrayStorage) stringArrayStorage: IStringArrayStorage,
|
|
@inject(ServiceIdentifiers.IStringArrayScopeCallsWrappersDataStorage)
|
|
stringArrayScopeCallsWrappersDataStorage: IStringArrayScopeCallsWrappersDataStorage,
|
|
@inject(ServiceIdentifiers.Factory__IStringArrayCustomNode)
|
|
stringArrayTransformerCustomNodeFactory: TStringArrayCustomNodeFactory
|
|
) {
|
|
super(randomGenerator, options);
|
|
|
|
this.visitedLexicalScopeNodesStackStorage = visitedLexicalScopeNodesStackStorage;
|
|
this.stringArrayStorage = stringArrayStorage;
|
|
this.stringArrayScopeCallsWrappersDataStorage = stringArrayScopeCallsWrappersDataStorage;
|
|
this.stringArrayTransformerCustomNodeFactory = stringArrayTransformerCustomNodeFactory;
|
|
}
|
|
|
|
/**
|
|
* @param {NodeTransformationStage} nodeTransformationStage
|
|
* @returns {IVisitor | null}
|
|
*/
|
|
public getVisitor(nodeTransformationStage: NodeTransformationStage): IVisitor | null {
|
|
if (!this.options.stringArrayWrappersCount) {
|
|
return null;
|
|
}
|
|
|
|
switch (nodeTransformationStage) {
|
|
case NodeTransformationStage.StringArray:
|
|
return {
|
|
enter: (node: ESTree.Node, parentNode: ESTree.Node | null): void => {
|
|
if (parentNode && NodeGuards.isNodeWithLexicalScopeStatements(node, parentNode)) {
|
|
this.onLexicalScopeNodeEnter(node);
|
|
}
|
|
},
|
|
leave: (node: ESTree.Node, parentNode: ESTree.Node | null): ESTree.Node | undefined => {
|
|
if (parentNode && NodeGuards.isNodeWithLexicalScopeStatements(node, parentNode)) {
|
|
this.onLexicalScopeNodeLeave();
|
|
|
|
return this.transformNode(node);
|
|
}
|
|
}
|
|
};
|
|
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {TNodeWithLexicalScopeStatements} lexicalScopeBodyNode
|
|
* @returns {TNodeWithLexicalScopeStatements}
|
|
*/
|
|
public transformNode(lexicalScopeBodyNode: TNodeWithLexicalScopeStatements): TNodeWithLexicalScopeStatements {
|
|
const stringArrayScopeCallsWrappersDataByEncoding: TStringArrayScopeCallsWrappersDataByEncoding | null =
|
|
this.stringArrayScopeCallsWrappersDataStorage.get(lexicalScopeBodyNode) ?? null;
|
|
|
|
if (!stringArrayScopeCallsWrappersDataByEncoding) {
|
|
return lexicalScopeBodyNode;
|
|
}
|
|
|
|
const stringArrayScopeCallsWrappersDataList: (IStringArrayScopeCallsWrappersData | undefined)[] = Object.values(
|
|
stringArrayScopeCallsWrappersDataByEncoding
|
|
);
|
|
|
|
// iterates over data for each encoding type
|
|
for (const stringArrayScopeCallsWrappersData of stringArrayScopeCallsWrappersDataList) {
|
|
if (!stringArrayScopeCallsWrappersData) {
|
|
continue;
|
|
}
|
|
|
|
const { scopeCallsWrappersData } = stringArrayScopeCallsWrappersData;
|
|
const scopeCallsWrappersDataLength: number = scopeCallsWrappersData.length;
|
|
|
|
const upperStringArrayCallsWrapperData = this.getUpperStringArrayCallsWrapperData(
|
|
stringArrayScopeCallsWrappersData
|
|
);
|
|
|
|
/**
|
|
* Iterates over each name of scope wrapper name
|
|
* Reverse iteration appends wrappers at index `0` at the correct order
|
|
*/
|
|
for (let i = scopeCallsWrappersDataLength - 1; i >= 0; i--) {
|
|
const stringArrayScopeCallsWrapperData = scopeCallsWrappersData[i];
|
|
|
|
this.getAndAppendStringArrayScopeCallsWrapperNode(
|
|
lexicalScopeBodyNode,
|
|
stringArrayScopeCallsWrapperData,
|
|
upperStringArrayCallsWrapperData
|
|
);
|
|
}
|
|
}
|
|
|
|
return lexicalScopeBodyNode;
|
|
}
|
|
|
|
/**
|
|
* @param {IStringArrayScopeCallsWrappersData} stringArrayScopeCallsWrappersData
|
|
* @returns {IStringArrayScopeCallsWrapperData}
|
|
*/
|
|
private getRootStringArrayCallsWrapperData(
|
|
stringArrayScopeCallsWrappersData: IStringArrayScopeCallsWrappersData
|
|
): IStringArrayScopeCallsWrapperData {
|
|
const { encoding } = stringArrayScopeCallsWrappersData;
|
|
|
|
return {
|
|
name: this.stringArrayStorage.getStorageCallsWrapperName(encoding),
|
|
index: 0,
|
|
parameterIndexesData: null
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @param {IStringArrayScopeCallsWrappersData} stringArrayScopeCallsWrappersData
|
|
* @returns {IStringArrayScopeCallsWrapperData}
|
|
*/
|
|
private getUpperStringArrayCallsWrapperData(
|
|
stringArrayScopeCallsWrappersData: IStringArrayScopeCallsWrappersData
|
|
): IStringArrayScopeCallsWrapperData {
|
|
const { encoding } = stringArrayScopeCallsWrappersData;
|
|
|
|
const rootStringArrayCallsWrapperData = this.getRootStringArrayCallsWrapperData(
|
|
stringArrayScopeCallsWrappersData
|
|
);
|
|
|
|
if (!this.options.stringArrayWrappersChainedCalls) {
|
|
return rootStringArrayCallsWrapperData;
|
|
}
|
|
|
|
const parentLexicalScopeBodyNode: TNodeWithLexicalScopeStatements | null =
|
|
this.visitedLexicalScopeNodesStackStorage.getLastElement() ?? null;
|
|
|
|
if (!parentLexicalScopeBodyNode) {
|
|
return rootStringArrayCallsWrapperData;
|
|
}
|
|
|
|
const parentLexicalScopeCallsWrappersDataByEncoding: TStringArrayScopeCallsWrappersDataByEncoding | null =
|
|
this.stringArrayScopeCallsWrappersDataStorage.get(parentLexicalScopeBodyNode) ?? null;
|
|
const parentScopeCallsWrappersData: IStringArrayScopeCallsWrapperData[] | null =
|
|
parentLexicalScopeCallsWrappersDataByEncoding?.[encoding]?.scopeCallsWrappersData ?? null;
|
|
|
|
if (!parentScopeCallsWrappersData?.length) {
|
|
return rootStringArrayCallsWrapperData;
|
|
}
|
|
|
|
return this.randomGenerator.getRandomGenerator().pickone(parentScopeCallsWrappersData);
|
|
}
|
|
|
|
/**
|
|
* @param {TNodeWithLexicalScopeStatements} lexicalScopeBodyNode
|
|
* @param {IStringArrayScopeCallsWrapperData} stringArrayScopeCallsWrapperData
|
|
* @param {IStringArrayScopeCallsWrapperData} upperStringArrayCallsWrapperData
|
|
*/
|
|
private getAndAppendStringArrayScopeCallsWrapperNode(
|
|
lexicalScopeBodyNode: TNodeWithLexicalScopeStatements,
|
|
stringArrayScopeCallsWrapperData: IStringArrayScopeCallsWrapperData,
|
|
upperStringArrayCallsWrapperData: IStringArrayScopeCallsWrapperData
|
|
): void {
|
|
let stringArrayScopeCallsWrapperNode: TStatement[];
|
|
|
|
switch (this.options.stringArrayWrappersType) {
|
|
case StringArrayWrappersType.Function: {
|
|
const randomIndex: number = this.randomGenerator.getRandomInteger(
|
|
0,
|
|
lexicalScopeBodyNode.body.length - 1
|
|
);
|
|
|
|
stringArrayScopeCallsWrapperNode = this.getStringArrayScopeCallsWrapperFunctionNode(
|
|
stringArrayScopeCallsWrapperData,
|
|
upperStringArrayCallsWrapperData
|
|
);
|
|
|
|
NodeAppender.insertAtIndex(lexicalScopeBodyNode, stringArrayScopeCallsWrapperNode, randomIndex);
|
|
|
|
break;
|
|
}
|
|
|
|
case StringArrayWrappersType.Variable:
|
|
default: {
|
|
stringArrayScopeCallsWrapperNode = this.getStringArrayScopeCallsWrapperVariableNode(
|
|
stringArrayScopeCallsWrapperData,
|
|
upperStringArrayCallsWrapperData
|
|
);
|
|
|
|
NodeAppender.prepend(lexicalScopeBodyNode, stringArrayScopeCallsWrapperNode);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {IStringArrayScopeCallsWrapperData} stringArrayScopeCallsWrapperData
|
|
* @param {IStringArrayScopeCallsWrapperData} upperStringArrayCallsWrapperData
|
|
* @returns {TStatement[]}
|
|
*/
|
|
private getStringArrayScopeCallsWrapperVariableNode(
|
|
stringArrayScopeCallsWrapperData: IStringArrayScopeCallsWrapperData,
|
|
upperStringArrayCallsWrapperData: IStringArrayScopeCallsWrapperData
|
|
): TStatement[] {
|
|
const stringArrayScopeCallsWrapperVariableNode: ICustomNode<
|
|
TInitialData<StringArrayScopeCallsWrapperVariableNode>
|
|
> = this.stringArrayTransformerCustomNodeFactory(
|
|
StringArrayCustomNode.StringArrayScopeCallsWrapperVariableNode
|
|
);
|
|
|
|
stringArrayScopeCallsWrapperVariableNode.initialize(
|
|
stringArrayScopeCallsWrapperData,
|
|
upperStringArrayCallsWrapperData
|
|
);
|
|
|
|
return stringArrayScopeCallsWrapperVariableNode.getNode();
|
|
}
|
|
|
|
/**
|
|
* @param {IStringArrayScopeCallsWrapperData} stringArrayScopeCallsWrapperData
|
|
* @param {IStringArrayScopeCallsWrapperData} upperStringArrayCallsWrapperData
|
|
* @returns {TStatement[]}
|
|
*/
|
|
private getStringArrayScopeCallsWrapperFunctionNode(
|
|
stringArrayScopeCallsWrapperData: IStringArrayScopeCallsWrapperData,
|
|
upperStringArrayCallsWrapperData: IStringArrayScopeCallsWrapperData
|
|
): TStatement[] {
|
|
const stringArrayScopeCallsWrapperFunctionNode: ICustomNode<
|
|
TInitialData<StringArrayScopeCallsWrapperFunctionNode>
|
|
> = this.stringArrayTransformerCustomNodeFactory(
|
|
StringArrayCustomNode.StringArrayScopeCallsWrapperFunctionNode
|
|
);
|
|
|
|
stringArrayScopeCallsWrapperFunctionNode.initialize(
|
|
stringArrayScopeCallsWrapperData,
|
|
upperStringArrayCallsWrapperData
|
|
);
|
|
|
|
return stringArrayScopeCallsWrapperFunctionNode.getNode();
|
|
}
|
|
|
|
/**
|
|
* @param {TNodeWithLexicalScopeStatements} lexicalScopeBodyNode
|
|
*/
|
|
private onLexicalScopeNodeEnter(lexicalScopeBodyNode: TNodeWithLexicalScopeStatements): void {
|
|
this.visitedLexicalScopeNodesStackStorage.push(lexicalScopeBodyNode);
|
|
}
|
|
|
|
private onLexicalScopeNodeLeave(): void {
|
|
this.visitedLexicalScopeNodesStackStorage.pop();
|
|
}
|
|
}
|