mirror of
https://github.com/javascript-obfuscator/javascript-obfuscator
synced 2026-08-09 12:42:29 +00:00
added BlockStatementControlFlowReplacer
This commit is contained in:
Vendored
+1016
-966
File diff suppressed because it is too large
Load Diff
@@ -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 { BlockStatementControlFlowReplacer } from '../../../node-transformers/node-control-flow-transformers/control-flow-replacers/BlockStatementControlFlowReplacer';
|
||||
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';
|
||||
|
||||
@@ -14,6 +15,10 @@ export const nodeControlFlowTransformersModule: interfaces.ContainerModule = new
|
||||
.to(BinaryExpressionControlFlowReplacer)
|
||||
.whenTargetNamed(NodeControlFlowReplacers.BinaryExpressionControlFlowReplacer);
|
||||
|
||||
bind<IControlFlowReplacer>(ServiceIdentifiers.IControlFlowReplacer)
|
||||
.to(BlockStatementControlFlowReplacer)
|
||||
.whenTargetNamed(NodeControlFlowReplacers.BlockStatementControlFlowReplacer);
|
||||
|
||||
bind<IControlFlowReplacer>(ServiceIdentifiers.IControlFlowReplacer)
|
||||
.to(CallExpressionControlFlowReplacer)
|
||||
.whenTargetNamed(NodeControlFlowReplacers.CallExpressionControlFlowReplacer);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export enum NodeControlFlowReplacers {
|
||||
BinaryExpressionControlFlowReplacer,
|
||||
BlockStatementControlFlowReplacer,
|
||||
CallExpressionControlFlowReplacer,
|
||||
LogicalExpressionControlFlowReplacer
|
||||
}
|
||||
|
||||
+20
-127
@@ -20,10 +20,8 @@ import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
|
||||
import { Node } from '../../node/Node';
|
||||
import { NodeAppender } from '../../node/NodeAppender';
|
||||
import { NodeControlFlowReplacers } from '../../enums/container/NodeControlFlowReplacers';
|
||||
import { Nodes } from '../../node/Nodes';
|
||||
import { NodeUtils } from '../../node/NodeUtils';
|
||||
import { RandomGeneratorUtils } from '../../utils/RandomGeneratorUtils';
|
||||
import { Utils } from '../../utils/Utils';
|
||||
|
||||
@injectable()
|
||||
export class FunctionControlFlowTransformer extends AbstractNodeTransformer {
|
||||
@@ -32,6 +30,7 @@ export class FunctionControlFlowTransformer extends AbstractNodeTransformer {
|
||||
*/
|
||||
private static readonly controlFlowReplacersMap: Map <string, NodeControlFlowReplacers> = new Map([
|
||||
[NodeType.BinaryExpression, NodeControlFlowReplacers.BinaryExpressionControlFlowReplacer],
|
||||
[NodeType.BlockStatement, NodeControlFlowReplacers.BlockStatementControlFlowReplacer],
|
||||
[NodeType.CallExpression, NodeControlFlowReplacers.CallExpressionControlFlowReplacer],
|
||||
[NodeType.LogicalExpression, NodeControlFlowReplacers.LogicalExpressionControlFlowReplacer]
|
||||
]);
|
||||
@@ -90,18 +89,6 @@ export class FunctionControlFlowTransformer extends AbstractNodeTransformer {
|
||||
this.customNodeFactory = customNodeFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param node
|
||||
* @return {boolean}
|
||||
*/
|
||||
private static functionHasProhibitedStatements (node: ESTree.Node): boolean {
|
||||
const isBreakOrContinueStatement: boolean = Node.isBreakStatementNode(node) || Node.isContinueStatementNode(node);
|
||||
const isVariableDeclarationWithLetOrConstKind: boolean = Node.isVariableDeclarationNode(node) &&
|
||||
(node.kind === 'const' || node.kind === 'let');
|
||||
|
||||
return Node.isFunctionDeclarationNode(node) || isBreakOrContinueStatement || isVariableDeclarationWithLetOrConstKind;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param functionNode
|
||||
* @returns {TNodeWithBlockStatement}
|
||||
@@ -138,23 +125,8 @@ export class FunctionControlFlowTransformer extends AbstractNodeTransformer {
|
||||
const hostNode: TNodeWithBlockStatement = FunctionControlFlowTransformer.getHostNode(functionNode);
|
||||
const controlFlowStorage: IStorage<ICustomNode> = this.getControlFlowStorage(hostNode);
|
||||
|
||||
let functionHasProhibitedStatements: boolean = false;
|
||||
|
||||
this.controlFlowData.set(hostNode, controlFlowStorage);
|
||||
|
||||
estraverse.replace(functionNode.body, {
|
||||
enter: (node: ESTree.Node, parentNode: ESTree.Node): any => {
|
||||
if (!functionHasProhibitedStatements) {
|
||||
functionHasProhibitedStatements = FunctionControlFlowTransformer.functionHasProhibitedStatements(node);
|
||||
}
|
||||
|
||||
return this.transformFunctionNodes(node, parentNode, controlFlowStorage);
|
||||
}
|
||||
});
|
||||
|
||||
if (!functionHasProhibitedStatements) {
|
||||
this.transformFunctionStatements(functionNode);
|
||||
}
|
||||
this.transformFunctionBody(functionNode.body, controlFlowStorage);
|
||||
|
||||
if (!controlFlowStorage.getLength()) {
|
||||
return functionNode;
|
||||
@@ -190,108 +162,29 @@ export class FunctionControlFlowTransformer extends AbstractNodeTransformer {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param node
|
||||
* @param parentNode
|
||||
* @param functionNodeBody
|
||||
* @param controlFlowStorage
|
||||
* @return {ESTree.Node}
|
||||
*/
|
||||
private transformFunctionNodes (
|
||||
node: ESTree.Node,
|
||||
parentNode: ESTree.Node,
|
||||
controlFlowStorage: IStorage<ICustomNode>
|
||||
): ESTree.Node {
|
||||
if (!FunctionControlFlowTransformer.controlFlowReplacersMap.has(node.type)) {
|
||||
return node;
|
||||
}
|
||||
private transformFunctionBody (functionNodeBody: ESTree.BlockStatement, controlFlowStorage: IStorage<ICustomNode>): void {
|
||||
estraverse.replace(functionNodeBody, {
|
||||
enter: (node: ESTree.Node, parentNode: ESTree.Node): any => {
|
||||
if (!FunctionControlFlowTransformer.controlFlowReplacersMap.has(node.type)) {
|
||||
return node;
|
||||
}
|
||||
|
||||
if (RandomGeneratorUtils.getRandomFloat(0, 1) > this.options.controlFlowFlatteningThreshold) {
|
||||
return node;
|
||||
}
|
||||
if (RandomGeneratorUtils.getRandomFloat(0, 1) > this.options.controlFlowFlatteningThreshold) {
|
||||
return node;
|
||||
}
|
||||
|
||||
const controlFlowReplacerName: NodeControlFlowReplacers = <NodeControlFlowReplacers>FunctionControlFlowTransformer
|
||||
.controlFlowReplacersMap.get(node.type);
|
||||
const controlFlowReplacerName: NodeControlFlowReplacers = <NodeControlFlowReplacers>FunctionControlFlowTransformer
|
||||
.controlFlowReplacersMap.get(node.type);
|
||||
|
||||
return {
|
||||
...this.controlFlowReplacerFactory(controlFlowReplacerName).replace(node, parentNode, controlFlowStorage),
|
||||
parentNode
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param functionNode
|
||||
*/
|
||||
private transformFunctionStatements (functionNode: ESTree.FunctionExpression | ESTree.FunctionDeclaration): void {
|
||||
if (RandomGeneratorUtils.getRandomFloat(0, 1) > this.options.controlFlowFlatteningThreshold) {
|
||||
return;
|
||||
}
|
||||
|
||||
const functionStatements: ESTree.Statement[] = functionNode.body.body;
|
||||
const functionStatementsObject: any = Object.assign({}, functionStatements);
|
||||
const originalKeys: number[] = Object.keys(functionStatementsObject).map((key: string) => parseInt(key, 10));
|
||||
const shuffledKeys: number[] = Utils.arrayShuffle(originalKeys);
|
||||
const originalKeysIndexesInShuffledArray: number[] = originalKeys.map((key: number) => shuffledKeys.indexOf(key));
|
||||
|
||||
if (functionStatements.length <= 4) {
|
||||
return;
|
||||
} else if (!functionStatements.length) {
|
||||
functionStatements.push(
|
||||
Nodes.getReturnStatementNode(
|
||||
Nodes.getLiteralNode(true)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const controllerIdentifierName: string = RandomGeneratorUtils.getRandomString(3);
|
||||
const indexIdentifierName: string = RandomGeneratorUtils.getRandomString(3);
|
||||
|
||||
functionNode.body.body = [
|
||||
Nodes.getVariableDeclarationNode([
|
||||
Nodes.getVariableDeclaratorNode(
|
||||
Nodes.getIdentifierNode(controllerIdentifierName),
|
||||
Nodes.getCallExpressionNode(
|
||||
Nodes.getMemberExpressionNode(
|
||||
Nodes.getLiteralNode(
|
||||
originalKeysIndexesInShuffledArray.join('|')
|
||||
),
|
||||
Nodes.getIdentifierNode('split')
|
||||
),
|
||||
[
|
||||
Nodes.getLiteralNode('|')
|
||||
]
|
||||
)
|
||||
),
|
||||
Nodes.getVariableDeclaratorNode(
|
||||
Nodes.getIdentifierNode(indexIdentifierName),
|
||||
Nodes.getLiteralNode(0)
|
||||
)
|
||||
]),
|
||||
Nodes.getWhileStatementNode(
|
||||
Nodes.getLiteralNode(true),
|
||||
Nodes.getBlockStatementNode([
|
||||
Nodes.getSwitchStatementNode(
|
||||
Nodes.getMemberExpressionNode(
|
||||
Nodes.getIdentifierNode(controllerIdentifierName),
|
||||
Nodes.getUpdateExpressionNode(
|
||||
'++',
|
||||
Nodes.getIdentifierNode(indexIdentifierName)
|
||||
),
|
||||
true
|
||||
),
|
||||
shuffledKeys.map((key: number, index: number) => {
|
||||
return Nodes.getSwitchCaseNode(
|
||||
Nodes.getLiteralNode(String(index)),
|
||||
[
|
||||
functionStatementsObject[key],
|
||||
Nodes.getContinueStatement()
|
||||
]
|
||||
);
|
||||
})
|
||||
),
|
||||
Nodes.getBreakStatement()
|
||||
])
|
||||
)
|
||||
];
|
||||
|
||||
NodeUtils.parentize(functionNode.body);
|
||||
return {
|
||||
...this.controlFlowReplacerFactory(controlFlowReplacerName).replace(node, parentNode, controlFlowStorage),
|
||||
parentNode
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
import { injectable, inject } from 'inversify';
|
||||
import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
|
||||
|
||||
import * as ESTree from 'estree';
|
||||
|
||||
import { TCustomNodeFactory } from '../../../types/container/TCustomNodeFactory';
|
||||
|
||||
import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
|
||||
import { IOptions } from '../../../interfaces/options/IOptions';
|
||||
import { IStorage } from '../../../interfaces/storages/IStorage';
|
||||
|
||||
import { AbstractControlFlowReplacer } from './AbstractControlFlowReplacer';
|
||||
import { Node } from '../../../node/Node';
|
||||
import { Nodes } from '../../../node/Nodes';
|
||||
import { NodeUtils } from '../../../node/NodeUtils';
|
||||
import { RandomGeneratorUtils } from '../../../utils/RandomGeneratorUtils';
|
||||
import { Utils } from '../../../utils/Utils';
|
||||
|
||||
@injectable()
|
||||
export class BlockStatementControlFlowReplacer extends AbstractControlFlowReplacer {
|
||||
/**
|
||||
* @param customNodeFactory
|
||||
* @param options
|
||||
*/
|
||||
constructor (
|
||||
@inject(ServiceIdentifiers.Factory__ICustomNode) customNodeFactory: TCustomNodeFactory,
|
||||
@inject(ServiceIdentifiers.IOptions) options: IOptions
|
||||
) {
|
||||
super(customNodeFactory, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param blockStatementNode
|
||||
* @return {boolean}
|
||||
*/
|
||||
private static blockStatementHasProhibitedStatements (blockStatementNode: ESTree.BlockStatement): boolean {
|
||||
return blockStatementNode.body.some((statement: ESTree.Statement) => {
|
||||
const isBreakOrContinueStatement: boolean = Node.isBreakStatementNode(statement) || Node.isContinueStatementNode(statement);
|
||||
const isVariableDeclarationWithLetOrConstKind: boolean = Node.isVariableDeclarationNode(statement) &&
|
||||
(statement.kind === 'const' || statement.kind === 'let');
|
||||
|
||||
return Node.isFunctionDeclarationNode(statement) || isBreakOrContinueStatement || isVariableDeclarationWithLetOrConstKind;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param blockStatementNode
|
||||
* @param parentNode
|
||||
* @param controlFlowStorage
|
||||
* @returns {ESTree.Node}
|
||||
*/
|
||||
public replace (
|
||||
blockStatementNode: ESTree.BlockStatement,
|
||||
parentNode: ESTree.Node,
|
||||
controlFlowStorage: IStorage <ICustomNode>
|
||||
): ESTree.BlockStatement {
|
||||
if (BlockStatementControlFlowReplacer.blockStatementHasProhibitedStatements(blockStatementNode)) {
|
||||
return blockStatementNode;
|
||||
}
|
||||
|
||||
const blockStatementStatements: ESTree.Statement[] = blockStatementNode.body;
|
||||
const blockStatementStatementsAsObject: any = Object.assign({}, blockStatementStatements);
|
||||
const originalKeys: number[] = Object.keys(blockStatementStatementsAsObject).map((key: string) => parseInt(key, 10));
|
||||
const shuffledKeys: number[] = Utils.arrayShuffle(originalKeys);
|
||||
const originalKeysIndexesInShuffledArray: number[] = originalKeys.map((key: number) => shuffledKeys.indexOf(key));
|
||||
|
||||
if (blockStatementStatements.length <= 4) {
|
||||
return blockStatementNode;
|
||||
} else if (!blockStatementStatements.length) {
|
||||
blockStatementStatements.push(
|
||||
Nodes.getReturnStatementNode(
|
||||
Nodes.getLiteralNode(true)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const controllerIdentifierName: string = RandomGeneratorUtils.getRandomString(3);
|
||||
const indexIdentifierName: string = RandomGeneratorUtils.getRandomString(3);
|
||||
|
||||
blockStatementNode.body = [
|
||||
Nodes.getVariableDeclarationNode([
|
||||
Nodes.getVariableDeclaratorNode(
|
||||
Nodes.getIdentifierNode(controllerIdentifierName),
|
||||
Nodes.getCallExpressionNode(
|
||||
Nodes.getMemberExpressionNode(
|
||||
Nodes.getLiteralNode(
|
||||
originalKeysIndexesInShuffledArray.join('|')
|
||||
),
|
||||
Nodes.getIdentifierNode('split')
|
||||
),
|
||||
[
|
||||
Nodes.getLiteralNode('|')
|
||||
]
|
||||
)
|
||||
),
|
||||
Nodes.getVariableDeclaratorNode(
|
||||
Nodes.getIdentifierNode(indexIdentifierName),
|
||||
Nodes.getLiteralNode(0)
|
||||
)
|
||||
]),
|
||||
Nodes.getWhileStatementNode(
|
||||
Nodes.getLiteralNode(true),
|
||||
Nodes.getBlockStatementNode([
|
||||
Nodes.getSwitchStatementNode(
|
||||
Nodes.getMemberExpressionNode(
|
||||
Nodes.getIdentifierNode(controllerIdentifierName),
|
||||
Nodes.getUpdateExpressionNode(
|
||||
'++',
|
||||
Nodes.getIdentifierNode(indexIdentifierName)
|
||||
),
|
||||
true
|
||||
),
|
||||
shuffledKeys.map((key: number, index: number) => {
|
||||
return Nodes.getSwitchCaseNode(
|
||||
Nodes.getLiteralNode(String(index)),
|
||||
[
|
||||
blockStatementStatementsAsObject[key],
|
||||
Nodes.getContinueStatement()
|
||||
]
|
||||
);
|
||||
})
|
||||
),
|
||||
Nodes.getBreakStatement()
|
||||
])
|
||||
)
|
||||
];
|
||||
|
||||
NodeUtils.parentize(blockStatementNode);
|
||||
|
||||
return blockStatementNode;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -99,7 +99,7 @@ if (!(<any>global)._babelPolyfill) {
|
||||
controlFlowFlattening: true,
|
||||
controlFlowFlatteningThreshold: 1,
|
||||
disableConsoleOutput: false,
|
||||
stringArray: false,
|
||||
stringArray: true,
|
||||
unicodeEscapeSequence: false
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
|
||||
Reference in New Issue
Block a user