callExpression control flow replacer

This commit is contained in:
sanex3339
2017-01-03 01:52:44 +03:00
parent 6eefcdcb67
commit 610c35b9fd
37 changed files with 1809 additions and 1012 deletions
+1245 -922
View File
File diff suppressed because it is too large Load Diff
@@ -15,13 +15,15 @@ import { SelfDefendingCustomNodeGroup } from '../../../custom-nodes/self-defendi
import { StringArrayCustomNodeGroup } from '../../../custom-nodes/string-array-nodes/group/StringArrayCustomNodeGroup';
import { BinaryExpressionFunctionNode } from '../../../custom-nodes/control-flow-replacers-nodes/binary-expression-control-flow-replacer-nodes/BinaryExpressionFunctionNode';
import { ControlFlowStorageCallNode } from '../../../custom-nodes/control-flow-storage-nodes/ControlFlowStorageCallNode';
import { CallExpressionControlFlowStorageCallNode } from '../../../custom-nodes/control-flow-storage-nodes/CallExpressionControlFlowStorageCallNode';
import { CallExpressionFunctionNode } from '../../../custom-nodes/control-flow-replacers-nodes/call-expression-control-flow-replacer-nodes/CallExpressionFunctionNode';
import { ControlFlowStorageNode } from '../../../custom-nodes/control-flow-storage-nodes/ControlFlowStorageNode';
import { ConsoleOutputDisableExpressionNode } from '../../../custom-nodes/console-output-nodes/ConsoleOutputDisableExpressionNode';
import { DebugProtectionFunctionCallNode } from '../../../custom-nodes/debug-protection-nodes/DebugProtectionFunctionCallNode';
import { DebugProtectionFunctionIntervalNode } from '../../../custom-nodes/debug-protection-nodes/DebugProtectionFunctionIntervalNode';
import { DebugProtectionFunctionNode } from '../../../custom-nodes/debug-protection-nodes/DebugProtectionFunctionNode';
import { DomainLockNode } from '../../../custom-nodes/domain-lock-nodes/DomainLockNode';
import { ExpressionWithOperatorControlFlowStorageCallNode } from '../../../custom-nodes/control-flow-storage-nodes/ExpressionWithOperatorControlFlowStorageCallNode';
import { LogicalExpressionFunctionNode } from '../../../custom-nodes/control-flow-replacers-nodes/logical-expression-control-flow-replacer-nodes/LogicalExpressionFunctionNode';
import { NodeCallsControllerFunctionNode } from '../../../custom-nodes/node-calls-controller-nodes/NodeCallsControllerFunctionNode';
import { SelfDefendingUnicodeNode } from '../../../custom-nodes/self-defending-nodes/SelfDefendingUnicodeNode';
@@ -36,8 +38,12 @@ export const customNodesModule: interfaces.ContainerModule = new ContainerModule
.whenTargetNamed(CustomNodes.BinaryExpressionFunctionNode);
bind<interfaces.Newable<ICustomNode>>(ServiceIdentifiers.Newable__ICustomNode)
.toConstructor(ControlFlowStorageCallNode)
.whenTargetNamed(CustomNodes.ControlFlowStorageCallNode);
.toConstructor(CallExpressionControlFlowStorageCallNode)
.whenTargetNamed(CustomNodes.CallExpressionControlFlowStorageCallNode);
bind<interfaces.Newable<ICustomNode>>(ServiceIdentifiers.Newable__ICustomNode)
.toConstructor(CallExpressionFunctionNode)
.whenTargetNamed(CustomNodes.CallExpressionFunctionNode);
bind<interfaces.Newable<ICustomNode>>(ServiceIdentifiers.Newable__ICustomNode)
.toConstructor(ControlFlowStorageNode)
@@ -63,6 +69,10 @@ export const customNodesModule: interfaces.ContainerModule = new ContainerModule
.toConstructor(DomainLockNode)
.whenTargetNamed(CustomNodes.DomainLockNode);
bind<interfaces.Newable<ICustomNode>>(ServiceIdentifiers.Newable__ICustomNode)
.toConstructor(ExpressionWithOperatorControlFlowStorageCallNode)
.whenTargetNamed(CustomNodes.ExpressionWithOperatorControlFlowStorageCallNode);
bind<interfaces.Newable<ICustomNode>>(ServiceIdentifiers.Newable__ICustomNode)
.toConstructor(LogicalExpressionFunctionNode)
.whenTargetNamed(CustomNodes.LogicalExpressionFunctionNode);
@@ -6,6 +6,7 @@ import { IControlFlowReplacer } from '../../../interfaces/node-transformers/ICon
import { NodeControlFlowReplacers } from '../../../enums/container/NodeControlFlowReplacers';
import { BinaryExpressionControlFlowReplacer } from '../../../node-transformers/node-control-flow-transformers/control-flow-replacers/BinaryExpressionControlFlowReplacer';
import { CallExpressionControlFlowReplacer } from '../../../node-transformers/node-control-flow-transformers/control-flow-replacers/CallExpressionControlFlowReplacer';
import { LogicalExpressionControlFlowReplacer } from '../../../node-transformers/node-control-flow-transformers/control-flow-replacers/LogicalExpressionControlFlowReplacer';
export const nodeControlFlowTransformersModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
@@ -13,6 +14,10 @@ export const nodeControlFlowTransformersModule: interfaces.ContainerModule = new
.to(BinaryExpressionControlFlowReplacer)
.whenTargetNamed(NodeControlFlowReplacers.BinaryExpressionControlFlowReplacer);
bind<IControlFlowReplacer>(ServiceIdentifiers.IControlFlowReplacer)
.to(CallExpressionControlFlowReplacer)
.whenTargetNamed(NodeControlFlowReplacers.CallExpressionControlFlowReplacer);
bind<IControlFlowReplacer>(ServiceIdentifiers.IControlFlowReplacer)
.to(LogicalExpressionControlFlowReplacer)
.whenTargetNamed(NodeControlFlowReplacers.LogicalExpressionControlFlowReplacer);
@@ -51,7 +51,7 @@ export class ConsoleOutputDisableExpressionNode extends AbstractCustomNode {
*/
protected getTemplate (): string {
return format(ConsoleOutputDisableExpressionTemplate(), {
consoleLogDisableFunctionName: RandomGeneratorUtils.getRandomVariableName(),
consoleLogDisableFunctionName: RandomGeneratorUtils.getRandomVariableName(6, true, true),
singleNodeCallControllerFunctionName: this.callsControllerFunctionName
});
}
@@ -96,7 +96,7 @@ export class ConsoleOutputCustomNodeGroup extends AbstractCustomNodeGroup {
return;
}
const callsControllerFunctionName: string = RandomGeneratorUtils.getRandomVariableName();
const callsControllerFunctionName: string = RandomGeneratorUtils.getRandomVariableName(6, true, true);
const consoleOutputDisableExpressionNode: ICustomNode = this.customNodeFactory(CustomNodes.ConsoleOutputDisableExpressionNode);
const nodeCallsControllerFunctionNode: ICustomNode = this.customNodeFactory(CustomNodes.NodeCallsControllerFunctionNode);
@@ -43,7 +43,7 @@ export class BinaryExpressionFunctionNode extends AbstractCustomNode {
protected getNodeStructure (): TStatement[] {
return [
Nodes.getFunctionDeclarationNode(
RandomGeneratorUtils.getRandomVariableName(1),
RandomGeneratorUtils.getRandomVariableName(1, true, false),
[
Nodes.getIdentifierNode('x'),
Nodes.getIdentifierNode('y')
@@ -0,0 +1,70 @@
import { injectable, inject } from 'inversify';
import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
import * as ESTree from 'estree';
import { TStatement } from '../../../types/node/TStatement';
import { IOptions } from '../../../interfaces/options/IOptions';
import { initializable } from '../../../decorators/Initializable';
import { AbstractCustomNode } from '../../AbstractCustomNode';
import { Nodes } from '../../../node/Nodes';
import { RandomGeneratorUtils } from '../../../utils/RandomGeneratorUtils';
@injectable()
export class CallExpressionFunctionNode extends AbstractCustomNode {
/**
* @type {(ESTree.Expression | ESTree.SpreadElement)[]}
*/
@initializable()
private expressionArguments: (ESTree.Expression | ESTree.SpreadElement)[];
/**
* @param options
*/
constructor (
@inject(ServiceIdentifiers.IOptions) options: IOptions
) {
super(options);
}
/**
* @param expressionArguments
*/
public initialize (expressionArguments: (ESTree.Expression | ESTree.SpreadElement)[]): void {
this.expressionArguments = expressionArguments;
}
/**
* @returns {TStatement[]}
*/
protected getNodeStructure (): TStatement[] {
const calleeIdentifier: ESTree.Identifier = Nodes.getIdentifierNode('callee');
const params: ESTree.Identifier[] = [];
const argumentsLength: number = this.expressionArguments.length;
for (let i: number = 0; i < argumentsLength; i++) {
params.push(Nodes.getIdentifierNode(`param${i + 1}`));
}
return [
Nodes.getFunctionDeclarationNode(
RandomGeneratorUtils.getRandomVariableName(1, true, false),
[
calleeIdentifier,
...params
],
Nodes.getBlockStatementNode([
Nodes.getReturnStatementNode(
Nodes.getCallExpressionNode(
calleeIdentifier,
params
)
)
])
)
];
}
}
@@ -43,7 +43,7 @@ export class LogicalExpressionFunctionNode extends AbstractCustomNode {
protected getNodeStructure (): TStatement[] {
return [
Nodes.getFunctionDeclarationNode(
RandomGeneratorUtils.getRandomVariableName(1),
RandomGeneratorUtils.getRandomVariableName(1, true, false),
[
Nodes.getIdentifierNode('x'),
Nodes.getIdentifierNode('y')
@@ -0,0 +1,85 @@
import { injectable, inject } from 'inversify';
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import * as ESTree from 'estree';
import { Expression } from 'estree';
import { TStatement } from '../../types/node/TStatement';
import { IOptions } from '../../interfaces/options/IOptions';
import { initializable } from '../../decorators/Initializable';
import { AbstractCustomNode } from '../AbstractCustomNode';
import { Nodes } from '../../node/Nodes';
@injectable()
export class CallExpressionControlFlowStorageCallNode extends AbstractCustomNode {
/**
* @type {Expression}
*/
@initializable()
private callee: Expression;
/**
* @type {string}
*/
@initializable()
private controlFlowStorageKey: string;
/**
* @type {string}
*/
@initializable()
private controlFlowStorageName: string;
/**
* @type {(ESTree.Expression | ESTree.SpreadElement)[]}
*/
@initializable()
private expressionArguments: (ESTree.Expression | ESTree.SpreadElement)[];
/**
* @param options
*/
constructor (
@inject(ServiceIdentifiers.IOptions) options: IOptions
) {
super(options);
}
/**
* @param controlFlowStorageName
* @param controlFlowStorageKey
* @param callee
* @param expressionArguments
*/
public initialize (
controlFlowStorageName: string,
controlFlowStorageKey: string,
callee: Expression,
expressionArguments: (ESTree.Expression | ESTree.SpreadElement)[]
): void {
this.controlFlowStorageName = controlFlowStorageName;
this.controlFlowStorageKey = controlFlowStorageKey;
this.callee = callee;
this.expressionArguments = expressionArguments;
}
protected getNodeStructure (): TStatement[] {
return [
Nodes.getExpressionStatementNode(
Nodes.getCallExpressionNode(
Nodes.getMemberExpressionNode(
Nodes.getIdentifierNode(this.controlFlowStorageName),
Nodes.getIdentifierNode(this.controlFlowStorageKey)
),
[
this.callee,
...this.expressionArguments
]
)
)
];
}
}
@@ -13,7 +13,7 @@ import { AbstractCustomNode } from '../AbstractCustomNode';
import { Nodes } from '../../node/Nodes';
@injectable()
export class ControlFlowStorageCallNode extends AbstractCustomNode {
export class ExpressionWithOperatorControlFlowStorageCallNode extends AbstractCustomNode {
/**
* @type {string}
*/
@@ -89,7 +89,7 @@ export class DebugProtectionCustomNodeGroup extends AbstractCustomNodeGroup {
return;
}
const debugProtectionFunctionName: string = RandomGeneratorUtils.getRandomVariableName();
const debugProtectionFunctionName: string = RandomGeneratorUtils.getRandomVariableName(6, true, true);
const debugProtectionFunctionNode: ICustomNode = this.customNodeFactory(CustomNodes.DebugProtectionFunctionNode);
const debugProtectionFunctionCallNode: ICustomNode = this.customNodeFactory(CustomNodes.DebugProtectionFunctionCallNode);
@@ -55,7 +55,7 @@ export class DomainLockNode extends AbstractCustomNode {
const [hiddenDomainsString, diff]: string[] = CryptUtils.hideString(domainsString, domainsString.length * 3);
return format(DomainLockNodeTemplate(), {
domainLockFunctionName: RandomGeneratorUtils.getRandomVariableName(),
domainLockFunctionName: RandomGeneratorUtils.getRandomVariableName(6, true, true),
diff: diff,
domains: hiddenDomainsString,
singleNodeCallControllerFunctionName: this.callsControllerFunctionName
@@ -96,7 +96,7 @@ export class DomainLockCustomNodeGroup extends AbstractCustomNodeGroup {
return;
}
const callsControllerFunctionName: string = RandomGeneratorUtils.getRandomVariableName();
const callsControllerFunctionName: string = RandomGeneratorUtils.getRandomVariableName(6, true, true);
const domainLockNode: ICustomNode = this.customNodeFactory(CustomNodes.DomainLockNode);
const nodeCallsControllerFunctionNode: ICustomNode = this.customNodeFactory(CustomNodes.NodeCallsControllerFunctionNode);
@@ -55,7 +55,7 @@ export class SelfDefendingUnicodeNode extends AbstractCustomNode {
protected getTemplate (): string {
return JavaScriptObfuscator.obfuscate(
format(SelfDefendingTemplate(), {
selfDefendingFunctionName: RandomGeneratorUtils.getRandomVariableName(),
selfDefendingFunctionName: RandomGeneratorUtils.getRandomVariableName(6, true, true),
singleNodeCallControllerFunctionName: this.callsControllerFunctionName
}),
{
@@ -96,7 +96,7 @@ export class SelfDefendingCustomNodeGroup extends AbstractCustomNodeGroup {
return;
}
const callsControllerFunctionName: string = RandomGeneratorUtils.getRandomVariableName();
const callsControllerFunctionName: string = RandomGeneratorUtils.getRandomVariableName(6, true, true);
const selfDefendingUnicodeNode: ICustomNode = this.customNodeFactory(CustomNodes.SelfDefendingUnicodeNode);
const nodeCallsControllerFunctionNode: ICustomNode = this.customNodeFactory(CustomNodes.NodeCallsControllerFunctionNode);
@@ -76,8 +76,8 @@ export class StringArrayRotateFunctionNode extends AbstractCustomNode {
* @returns {string}
*/
protected getTemplate (): string {
const timesName: string = RandomGeneratorUtils.getRandomVariableName();
const whileFunctionName: string = RandomGeneratorUtils.getRandomVariableName();
const timesName: string = RandomGeneratorUtils.getRandomVariableName(6, true, true);
const whileFunctionName: string = RandomGeneratorUtils.getRandomVariableName(6, true, true);
let code: string = '';
+1
View File
@@ -6,6 +6,7 @@ declare module 'estree' {
interface BaseNode {
obfuscated?: boolean;
parentNode?: ESTree.Node;
skippedByControlFlow?: boolean;
}
interface SimpleLiteral extends ESTree.BaseNode, ESTree.BaseExpression {
+3 -1
View File
@@ -1,12 +1,14 @@
export enum CustomNodes {
BinaryExpressionFunctionNode,
ControlFlowStorageCallNode,
CallExpressionControlFlowStorageCallNode,
CallExpressionFunctionNode,
ControlFlowStorageNode,
ConsoleOutputDisableExpressionNode,
DebugProtectionFunctionCallNode,
DebugProtectionFunctionIntervalNode,
DebugProtectionFunctionNode,
DomainLockNode,
ExpressionWithOperatorControlFlowStorageCallNode,
LogicalExpressionFunctionNode,
NodeCallsControllerFunctionNode,
SelfDefendingUnicodeNode,
@@ -1,4 +1,5 @@
export enum NodeControlFlowReplacers {
BinaryExpressionControlFlowReplacer,
CallExpressionControlFlowReplacer,
LogicalExpressionControlFlowReplacer
}
@@ -30,6 +30,7 @@ export class FunctionControlFlowTransformer extends AbstractNodeTransformer {
*/
private static readonly controlFlowReplacersMap: Map <string, NodeControlFlowReplacers> = new Map([
[NodeType.BinaryExpression, NodeControlFlowReplacers.BinaryExpressionControlFlowReplacer],
[NodeType.CallExpression, NodeControlFlowReplacers.CallExpressionControlFlowReplacer],
[NodeType.LogicalExpression, NodeControlFlowReplacers.LogicalExpressionControlFlowReplacer]
]);
@@ -4,16 +4,12 @@ import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
import * as ESTree from 'estree';
import { TCustomNodeFactory } from '../../../types/container/TCustomNodeFactory';
import { TStatement } from '../../../types/node/TStatement';
import { IControlFlowReplacer } from '../../../interfaces/node-transformers/IControlFlowReplacer';
import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
import { IOptions } from '../../../interfaces/options/IOptions';
import { IStorage } from '../../../interfaces/storages/IStorage';
import { BinaryExpressionControlFlowReplacer } from './BinaryExpressionControlFlowReplacer';
import { CustomNodes } from '../../../enums/container/CustomNodes';
import { Node } from '../../../node/Node';
import { RandomGeneratorUtils } from '../../../utils/RandomGeneratorUtils';
@injectable()
@@ -73,32 +69,6 @@ export abstract class AbstractControlFlowReplacer implements IControlFlowReplace
*/
public abstract replace (node: ESTree.Node, parentNode: ESTree.Node, controlFlowStorage: IStorage <ICustomNode>): ESTree.Node;
/**
* @param controlFlowStorageId
* @param storageKey
* @param leftExpression
* @param rightExpression
* @returns {ESTree.Node}
*/
protected getControlFlowStorageCallNode (
controlFlowStorageId: string,
storageKey: string,
leftExpression: ESTree.Expression,
rightExpression: ESTree.Expression
): ESTree.Node {
const controlFlowStorageCallCustomNode: ICustomNode = this.customNodeFactory(CustomNodes.ControlFlowStorageCallNode);
controlFlowStorageCallCustomNode.initialize(controlFlowStorageId, storageKey, leftExpression, rightExpression);
const statementNode: TStatement = controlFlowStorageCallCustomNode.getNode()[0];
if (!statementNode || !Node.isExpressionStatementNode(statementNode)) {
throw new Error(`\`controlFlowStorageCallNode.getNode()[0]\` should returns array with \`ExpressionStatement\` node`);
}
return statementNode.expression;
}
/**
* @param customNode
* @param controlFlowStorage
@@ -113,7 +83,7 @@ export abstract class AbstractControlFlowReplacer implements IControlFlowReplace
usingExistingIdentifierChance: number
): string {
const controlFlowStorageId: string = controlFlowStorage.getStorageId();
const storageKeysById: Map<string, string[]> = BinaryExpressionControlFlowReplacer
const storageKeysById: Map<string, string[]> = AbstractControlFlowReplacer
.getStorageKeysByIdForCurrentStorage(this.replacerDataByControlFlowStorageId, controlFlowStorageId);
const storageKeysForCurrentId: string[] | undefined = storageKeysById.get(replacerId);
@@ -11,10 +11,10 @@ import { IStorage } from '../../../interfaces/storages/IStorage';
import { CustomNodes } from '../../../enums/container/CustomNodes';
import { AbstractControlFlowReplacer } from './AbstractControlFlowReplacer';
import { ExpressionWithOperatorControlFlowReplacer } from './ExpressionWithOperatorControlFlowReplacer';
@injectable()
export class BinaryExpressionControlFlowReplacer extends AbstractControlFlowReplacer {
export class BinaryExpressionControlFlowReplacer extends ExpressionWithOperatorControlFlowReplacer {
/**
* @type {number}
*/
@@ -0,0 +1,102 @@
import { injectable, inject } from 'inversify';
import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
import * as ESTree from 'estree';
import { TCustomNodeFactory } from '../../../types/container/TCustomNodeFactory';
import { TStatement } from '../../../types/node/TStatement';
import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
import { IOptions } from '../../../interfaces/options/IOptions';
import { IStorage } from '../../../interfaces/storages/IStorage';
import { CustomNodes } from '../../../enums/container/CustomNodes';
import { AbstractControlFlowReplacer } from './AbstractControlFlowReplacer';
import { Node } from '../../../node/Node';
@injectable()
export class CallExpressionControlFlowReplacer extends AbstractControlFlowReplacer {
/**
* @type {number}
*/
private static readonly usingExistingIdentifierChance: number = 0.5;
/**
* @param customNodeFactory
* @param options
*/
constructor (
@inject(ServiceIdentifiers.Factory__ICustomNode) customNodeFactory: TCustomNodeFactory,
@inject(ServiceIdentifiers.IOptions) options: IOptions
) {
super(customNodeFactory, options);
}
/**
* @param callExpressionNode
* @param parentNode
* @param controlFlowStorage
* @returns {ESTree.Node}
*/
public replace (
callExpressionNode: ESTree.CallExpression,
parentNode: ESTree.Node,
controlFlowStorage: IStorage <ICustomNode>
): ESTree.Node {
const callee: ESTree.Expression = <ESTree.Expression>callExpressionNode.callee;
if (!Node.isIdentifierNode(callee)) {
return callExpressionNode;
}
const replacerId: string = String(callExpressionNode.arguments.length);
const callExpressionFunctionCustomNode: ICustomNode = this.customNodeFactory(CustomNodes.CallExpressionFunctionNode);
const expressionArguments: (ESTree.Expression | ESTree.SpreadElement)[] = callExpressionNode.arguments;
callExpressionFunctionCustomNode.initialize(expressionArguments);
const storageKey: string = this.insertCustomNodeToControlFlowStorage(
callExpressionFunctionCustomNode,
controlFlowStorage,
replacerId,
CallExpressionControlFlowReplacer.usingExistingIdentifierChance
);
return this.getControlFlowStorageCallNode(
controlFlowStorage.getStorageId(),
storageKey,
callee,
expressionArguments
);
}
/**
* @param controlFlowStorageId
* @param storageKey
* @param callee
* @param expressionArguments
* @param arguments
* @returns {ESTree.Node}
*/
protected getControlFlowStorageCallNode (
controlFlowStorageId: string,
storageKey: string,
callee: ESTree.Expression,
expressionArguments: (ESTree.Expression | ESTree.SpreadElement)[]
): ESTree.Node {
const controlFlowStorageCallCustomNode: ICustomNode = this.customNodeFactory(
CustomNodes.CallExpressionControlFlowStorageCallNode
);
controlFlowStorageCallCustomNode.initialize(controlFlowStorageId, storageKey, callee, expressionArguments);
const statementNode: TStatement = controlFlowStorageCallCustomNode.getNode()[0];
if (!statementNode || !Node.isExpressionStatementNode(statementNode)) {
throw new Error(`\`controlFlowStorageCallCustomNode.getNode()[0]\` should returns array with \`ExpressionStatement\` node`);
}
return statementNode.expression;
}
}
@@ -0,0 +1,71 @@
import { injectable, inject } from 'inversify';
import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
import * as ESTree from 'estree';
import { TCustomNodeFactory } from '../../../types/container/TCustomNodeFactory';
import { TStatement } from '../../../types/node/TStatement';
import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
import { IOptions } from '../../../interfaces/options/IOptions';
import { AbstractControlFlowReplacer } from './AbstractControlFlowReplacer';
import { CustomNodes } from '../../../enums/container/CustomNodes';
import { Node } from '../../../node/Node';
@injectable()
export abstract class ExpressionWithOperatorControlFlowReplacer extends AbstractControlFlowReplacer {
/**
* @type {TCustomNodeFactory}
*/
protected readonly customNodeFactory: TCustomNodeFactory;
/**
* @type {IOptions}
*/
protected readonly options: IOptions;
/**
* @type {Map<string, Map<string, string[]>>}
*/
protected readonly replacerDataByControlFlowStorageId: Map <string, Map<string, string[]>> = new Map();
/**
* @param customNodeFactory
* @param options
*/
constructor (
@inject(ServiceIdentifiers.Factory__ICustomNode) customNodeFactory: TCustomNodeFactory,
@inject(ServiceIdentifiers.IOptions) options: IOptions
) {
super(customNodeFactory, options);
}
/**
* @param controlFlowStorageId
* @param storageKey
* @param leftExpression
* @param rightExpression
* @returns {ESTree.Node}
*/
protected getControlFlowStorageCallNode (
controlFlowStorageId: string,
storageKey: string,
leftExpression: ESTree.Expression,
rightExpression: ESTree.Expression
): ESTree.Node {
const controlFlowStorageCallCustomNode: ICustomNode = this.customNodeFactory(
CustomNodes.ExpressionWithOperatorControlFlowStorageCallNode
);
controlFlowStorageCallCustomNode.initialize(controlFlowStorageId, storageKey, leftExpression, rightExpression);
const statementNode: TStatement = controlFlowStorageCallCustomNode.getNode()[0];
if (!statementNode || !Node.isExpressionStatementNode(statementNode)) {
throw new Error(`\`controlFlowStorageCallCustomNode.getNode()[0]\` should returns array with \`ExpressionStatement\` node`);
}
return statementNode.expression;
}
}
@@ -11,12 +11,12 @@ import { IStorage } from '../../../interfaces/storages/IStorage';
import { CustomNodes } from '../../../enums/container/CustomNodes';
import { AbstractControlFlowReplacer } from './AbstractControlFlowReplacer';
import { ExpressionWithOperatorControlFlowReplacer } from './ExpressionWithOperatorControlFlowReplacer';
import { Node } from '../../../node/Node';
import { NodeUtils } from '../../../node/NodeUtils';
@injectable()
export class LogicalExpressionControlFlowReplacer extends AbstractControlFlowReplacer {
export class LogicalExpressionControlFlowReplacer extends ExpressionWithOperatorControlFlowReplacer {
/**
* @type {number}
*/
@@ -47,7 +47,7 @@ export class IdentifierReplacer extends AbstractReplacer implements IObfuscatorR
*/
public storeNames (nodeName: string, nodeIdentifier: number): void {
if (!this.isReservedName(nodeName)) {
this.namesMap.set(`${nodeName}-${String(nodeIdentifier)}`, RandomGeneratorUtils.getRandomVariableName());
this.namesMap.set(`${nodeName}-${String(nodeIdentifier)}`, RandomGeneratorUtils.getRandomVariableName(6, true, true));
}
}
+50 -2
View File
@@ -51,6 +51,23 @@ export class Nodes {
};
}
/**
* @param label
* @return {ESTree.BreakStatement}
*/
public static getBreakStatement (label?: ESTree.Identifier): ESTree.BreakStatement {
const breakStatementNode: ESTree.BreakStatement = {
type: NodeType.BreakStatement,
obfuscated: false
};
if (label) {
breakStatementNode.label = label;
}
return breakStatementNode;
}
/**
* @param body
* @returns {ESTree.CatchClause}
@@ -71,7 +88,7 @@ export class Nodes {
*/
public static getCallExpressionNode (
callee: ESTree.Expression,
args: ESTree.Expression[] | ESTree.SpreadElement[] = []
args: (ESTree.Expression | ESTree.SpreadElement)[] = []
): ESTree.CallExpression {
return {
type: NodeType.CallExpression,
@@ -202,7 +219,7 @@ export class Nodes {
* @return {ESTree.MemberExpression}
*/
public static getMemberExpressionNode (
object: ESTree.Identifier,
object: ESTree.Expression | ESTree.Super,
property: ESTree.Identifier|ESTree.Literal,
computed: boolean = false
): ESTree.MemberExpression {
@@ -279,6 +296,37 @@ export class Nodes {
};
}
/**
* @param discriminant
* @param cases
* @returns {ESTree.SwitchStatement}
*/
public static getSwitchStatementNode (
discriminant: ESTree.Expression,
cases: ESTree.SwitchCase[]
): ESTree.SwitchStatement {
return {
type: NodeType.SwitchStatement,
discriminant,
cases,
obfuscated: false
};
}
/**
* @param test
* @param consequent
* @returns {ESTree.SwitchCase}
*/
public static getSwitchCaseNode (test: ESTree.Expression, consequent: ESTree.Statement[]): ESTree.SwitchCase {
return {
type: NodeType.SwitchCase,
test,
consequent,
obfuscated: false
};
}
/**
* @param declarations
* @param kind
@@ -18,7 +18,7 @@ export class StringArrayStorage extends ArrayStorage <string> {
public initialize (...args: any[]): void {
super.initialize(args);
this.storageId = RandomGeneratorUtils.getRandomVariableName(4, false);
this.storageId = RandomGeneratorUtils.getRandomVariableName(4, false, false);
}
/**
+16 -3
View File
@@ -13,6 +13,11 @@ export class RandomGeneratorUtils {
*/
public static readonly randomGeneratorPoolWithNumbers: string = `${RandomGeneratorUtils.randomGeneratorPool}0123456789`;
/**
* @type {Set<string>}
*/
public static randomVariableNameSet: Set <string> = new Set();
/**
* @type {Chance.Chance | Chance.SeededChance}
*/
@@ -68,18 +73,26 @@ export class RandomGeneratorUtils {
/**
* @param length
* @param withPrefix
* @param unique
* @returns {string}
*/
public static getRandomVariableName (length: number = 6, withPrefix: boolean = true): string {
public static getRandomVariableName (length: number, withPrefix: boolean, unique: boolean): string {
const prefix: string = withPrefix ? `_${Utils.hexadecimalPrefix}` : '';
const rangeMinInteger: number = 10000;
const rangeMaxInteger: number = 99999999;
return `${prefix}${(
const randomVariableName: string = `${prefix}${(
Utils.decToHex(
RandomGeneratorUtils.getRandomInteger(rangeMinInteger, rangeMaxInteger)
)
).substr(0, length)}`;
if (unique && RandomGeneratorUtils.randomVariableNameSet.has(randomVariableName)) {
return RandomGeneratorUtils.getRandomVariableName(length, withPrefix, unique);
}
RandomGeneratorUtils.randomVariableNameSet.add(randomVariableName);
return randomVariableName;
}
/**
+1 -30
View File
@@ -49,41 +49,12 @@ if (!(<any>global)._babelPolyfill) {
return abc.item = 15, test1();
};
var regexptest = /version\\/(\\d+)/i;
console.log(regexptest);
test2(22);
console.log(105.4);
console.log(true, false);
var sA = 'shorthand1';
var sB = 'shorthand2';
console.log({sA, sB});
try {
} catch (error) {
console.log(error);
}
function foo () {
return function () {
var sum1 = 10 + 20;
var sum2 = 20 + 30;
var sum3 = 30 + 50;
var sub = sum3 - sum2;
return sum1 + sub;
}
}
console.log(foo()());
})();
`,
{
compact: false,
controlFlowFlattening: true,
controlFlowFlatteningThreshold: 1,
disableConsoleOutput: false
}
).getObfuscatedCode();
@@ -0,0 +1,7 @@
(function () {
function sum (a, b) {
return a + b;
}
var variable = sum(1, 2);
})();
@@ -0,0 +1,8 @@
(function () {
function sum (a, b) {
return a + b;
}
var variable1 = sum(1, 2);
var variable2 = sum(2, 3);
})();
@@ -0,0 +1,9 @@
(function () {
var object = {
sum: function (a, b) {
return a + b;
}
};
var variable = object.sum(1, 2);
})();
@@ -152,9 +152,12 @@ describe('JavaScriptObfuscator', () => {
const obfuscationResult1: IObfuscationResult = JavaScriptObfuscator.obfuscate(
code, { seed: seed }
);
RandomGeneratorUtils.randomVariableNameSet.clear();
const obfuscationResult2: IObfuscationResult = JavaScriptObfuscator.obfuscate(
code, { seed: seed }
);
RandomGeneratorUtils.randomVariableNameSet.clear();
assert.equal(obfuscationResult1.getObfuscatedCode(), obfuscationResult2.getObfuscatedCode());
});
@@ -0,0 +1,96 @@
import { assert } from 'chai';
import { IObfuscationResult } from '../../../../../src/interfaces/IObfuscationResult';
import { NO_CUSTOM_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes';
import { readFileAsString } from '../../../../helpers/readFileAsString';
import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscator';
describe('CallExpressionControlFlowReplacer', () => {
describe('replace (callExpressionNode: ESTree.CallExpression,parentNode: ESTree.Node,controlFlowStorage: IStorage <ICustomNode>)', () => {
describe('variant #1 - single call expression', () => {
const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
readFileAsString(
'./test/fixtures/node-transformers/node-control-flow-transformers/control-flow-replacers/call-expression-control-flow-replacer/call-expression-control-flow-replacer-1.js'
),
{
...NO_CUSTOM_NODES_PRESET,
controlFlowFlattening: true,
controlFlowFlatteningThreshold: 1
}
);
const obfuscatedCode: string = obfuscationResult.getObfuscatedCode();
const controlFlowStorageCallRegExp: RegExp = /var *_0x([a-z0-9]){4,6} *= *_0x([a-z0-9]){4,6}\['(\\x[a-f0-9]*){3}'\]\(_0x([a-z0-9]){4,6}, *0x1, *0x2\);/;
it('should replace call expression node by call to control flow storage node', () => {
assert.match(obfuscatedCode, controlFlowStorageCallRegExp);
});
});
describe('variant #2 - multiple call expressions with threshold = 1', () => {
it('should replace call expression node by call to control flow storage node', function () {
this.timeout(4000);
const samplesCount: number = 200;
const expectedValue: number = 0.5;
const delta: number = 0.1;
let equalsValue: number = 0;
for (let i = 0; i < samplesCount; i++) {
const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
readFileAsString(
'./test/fixtures/node-transformers/node-control-flow-transformers/control-flow-replacers/call-expression-control-flow-replacer/call-expression-control-flow-replacer-2.js'
),
{
...NO_CUSTOM_NODES_PRESET,
controlFlowFlattening: true,
controlFlowFlatteningThreshold: 1
}
);
const obfuscatedCode: string = obfuscationResult.getObfuscatedCode();
const controlFlowStorageCallRegExp1: RegExp = /var *_0x([a-z0-9]){4,6} *= *(_0x([a-z0-9]){4,6}\['(\\x[a-f0-9]*){3}'\])\(_0x([a-z0-9]){4,6}, *0x1, *0x2\);/;
const controlFlowStorageCallRegExp2: RegExp = /var *_0x([a-z0-9]){4,6} *= *(_0x([a-z0-9]){4,6}\['(\\x[a-f0-9]*){3}'\])\(_0x([a-z0-9]){4,6}, *0x2, *0x3\);/;
const firstMatchArray: RegExpMatchArray | null = obfuscatedCode.match(controlFlowStorageCallRegExp1);
const secondMatchArray: RegExpMatchArray | null = obfuscatedCode.match(controlFlowStorageCallRegExp2);
const firstMatch: string | undefined = firstMatchArray ? firstMatchArray[2] : undefined;
const secondMatch: string | undefined = secondMatchArray ? secondMatchArray[2] : undefined;
assert.match(obfuscatedCode, controlFlowStorageCallRegExp1);
assert.match(obfuscatedCode, controlFlowStorageCallRegExp2);
assert.isOk(firstMatch);
assert.isOk(secondMatch);
if (firstMatch === secondMatch) {
equalsValue++;
}
}
assert.closeTo(equalsValue / samplesCount, expectedValue, delta);
});
});
describe('variant #3 - callee - member expression', () => {
const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
readFileAsString(
'./test/fixtures/node-transformers/node-control-flow-transformers/control-flow-replacers/call-expression-control-flow-replacer/call-expression-control-flow-replacer-3.js'
),
{
...NO_CUSTOM_NODES_PRESET,
controlFlowFlattening: true,
controlFlowFlatteningThreshold: 1
}
);
const obfuscatedCode: string = obfuscationResult.getObfuscatedCode();
const controlFlowStorageCallRegExp: RegExp = /var *_0x([a-z0-9]){4,6} *= *_0x([a-z0-9]){4,6}\['\\x73\\x75\\x6d'\]\(0x1, *0x2\);/;
it('shouldn\'t replace call expression node by call to control flow storage node if call expression callee is member expression node', () => {
assert.match(obfuscatedCode, controlFlowStorageCallRegExp);
});
});
});
});
+1
View File
@@ -32,6 +32,7 @@ import './functional-tests/custom-nodes/string-array-nodes/StringArrayRotateFunc
import './functional-tests/custom-nodes/string-array-nodes/StringArrayNode.spec';
import './functional-tests/node-transformers/node-control-flow-transformers/FunctionControlFlowTransformer.spec';
import './functional-tests/node-transformers/node-control-flow-transformers/control-flow-replacers/BinaryExpressionControlFlowReplacer.spec';
import './functional-tests/node-transformers/node-control-flow-transformers/control-flow-replacers/CallExpressionControlFlowReplacer.spec';
import './functional-tests/node-transformers/node-control-flow-transformers/control-flow-replacers/LogicalExpressionControlFlowReplacer.spec';
import './functional-tests/node-transformers/node-obfuscators/CatchClauseObfuscator.spec';
import './functional-tests/node-transformers/node-obfuscators/FunctionDeclarationObfuscator.spec';
@@ -5,8 +5,8 @@ import { RandomGeneratorUtils } from '../../../src/utils/RandomGeneratorUtils';
describe('RandomGeneratorUtils', () => {
describe('getRandomVariableName (length: number = 6): string', () => {
it('should return a string of given length with random variable name', () => {
assert.match(RandomGeneratorUtils.getRandomVariableName(4), /^_0x(\w){4}$/);
assert.match(RandomGeneratorUtils.getRandomVariableName(6), /^_0x(\w){4,6}$/);
assert.match(RandomGeneratorUtils.getRandomVariableName(4, true, false), /^_0x(\w){4}$/);
assert.match(RandomGeneratorUtils.getRandomVariableName(6, true, true), /^_0x(\w){4,6}$/);
});
});
});