control flow flattening improvements: less storage nodes, faster speed

This commit is contained in:
sanex3339
2016-12-13 08:16:08 +03:00
parent bc4b18f1e1
commit 59a2511ec6
23 changed files with 1247 additions and 1157 deletions
+1139 -1084
View File
File diff suppressed because it is too large Load Diff
+9 -2
View File
@@ -31,7 +31,9 @@ export abstract class AbstractCustomNode implements ICustomNode {
/**
* @returns {string}
*/
public abstract getCode (): string;
public getCode (): string {
return NodeUtils.convertStructureToCode(this.getNode());
}
/**
* @returns {TStatement[]}
@@ -44,6 +46,11 @@ export abstract class AbstractCustomNode implements ICustomNode {
* @returns {TStatement[]}
*/
protected getNodeStructure (): TStatement[] {
return NodeUtils.convertCodeToStructure(this.getCode());
return NodeUtils.convertCodeToStructure(this.getTemplate());
}
/**
* @returns {string}
*/
protected abstract getTemplate (): string;
}
@@ -39,7 +39,7 @@ export class ConsoleOutputDisableExpressionNode extends AbstractCustomNode {
/**
* @returns {string}
*/
public getCode (): string {
protected getTemplate (): string {
return format(ConsoleOutputDisableExpressionTemplate(), {
consoleLogDisableFunctionName: RandomGeneratorUtils.getRandomVariableName(),
singleNodeCallControllerFunctionName: this.callsControllerFunctionName
@@ -32,14 +32,14 @@ export class BinaryExpressionFunctionNode extends AbstractCustomNode {
/**
* @param operator
*/
initialize (operator: string): void {
public initialize (operator: string): void {
this.operator = operator;
}
/**
* @returns {string}
*/
public getCode (): string {
protected getTemplate (): string {
return format(BinaryExpressionFunctionTemplate(), {
functionName: RandomGeneratorUtils.getRandomVariableName(1),
operator: this.operator
@@ -67,7 +67,7 @@ export class ControlFlowStorageCallNode extends AbstractCustomNode {
/**
* @returns {string}
*/
public getCode (): string {
protected getTemplate (): string {
return format(ControlFlowStorageCallTemplate(), {
controlFlowStorageKey: this.controlFlowStorageKey,
controlFlowStorageName: this.controlFlowStorageName,
@@ -48,7 +48,7 @@ export class ControlFlowStorageNode extends AbstractCustomNode {
/**
* @returns {string}
*/
public getCode (): string {
protected getTemplate (): string {
return format(ControlFlowStorageTemplate(), {
controlFlowStorage: this.controlFlowStorage.toString(),
controlFlowStorageName: this.controlFlowStorageName
@@ -38,7 +38,7 @@ export class DebugProtectionFunctionCallNode extends AbstractCustomNode {
/**
* @returns {string}
*/
public getCode (): string {
protected getTemplate (): string {
return format(DebugProtectionFunctionCallTemplate(), {
debugProtectionFunctionName: this.debugProtectionFunctionName
});
@@ -38,7 +38,7 @@ export class DebugProtectionFunctionIntervalNode extends AbstractCustomNode {
/**
* @returns {string}
*/
public getCode (): string {
protected getTemplate (): string {
return format(DebugProtectionFunctionIntervalTemplate(), {
debugProtectionFunctionName: this.debugProtectionFunctionName
});
@@ -38,7 +38,7 @@ export class DebugProtectionFunctionNode extends AbstractCustomNode {
/**
* @returns {string}
*/
public getCode (): string {
protected getTemplate (): string {
return format(DebugProtectionFunctionTemplate(), {
debugProtectionFunctionName: this.debugProtectionFunctionName
});
@@ -40,7 +40,7 @@ export class DomainLockNode extends AbstractCustomNode {
/**
* @returns {string}
*/
public getCode (): string {
protected getTemplate (): string {
let domainsString: string = this.options.domainLock.join(';'),
[hiddenDomainsString, diff]: string[] = CryptUtils.hideString(domainsString, domainsString.length * 3);
@@ -53,7 +53,7 @@ export class NodeCallsControllerFunctionNode extends AbstractCustomNode {
/**
* @returns {string}
*/
public getCode (): string {
protected getTemplate (): string {
if (this.appendEvent === ObfuscationEvents.AfterObfuscation) {
return JavaScriptObfuscator.obfuscate(
format(SingleNodeCallControllerTemplate(), {
@@ -42,7 +42,7 @@ export class SelfDefendingUnicodeNode extends AbstractCustomNode {
/**
* @returns {string}
*/
public getCode (): string {
protected getTemplate (): string {
return JavaScriptObfuscator.obfuscate(
format(SelfDefendingTemplate(), {
selfDefendingFunctionName: RandomGeneratorUtils.getRandomVariableName(),
@@ -67,25 +67,6 @@ export class StringArrayCallsWrapper extends AbstractCustomNode implements ICust
this.stringArrayCallsWrapperName = stringArrayCallsWrapperName;
}
/**
* @returns {string}
*/
public getCode (): string {
const decodeNodeTemplate: string = this.getDecodeStringArrayTemplate();
return JavaScriptObfuscator.obfuscate(
format(StringArrayCallsWrapperTemplate(), {
decodeNodeTemplate,
stringArrayCallsWrapperName: this.stringArrayCallsWrapperName,
stringArrayName: this.stringArrayName
}),
{
...NO_CUSTOM_NODES_PRESET,
seed: this.options.seed
}
).getObfuscatedCode();
}
/**
* @returns {string}
*/
@@ -130,4 +111,23 @@ export class StringArrayCallsWrapper extends AbstractCustomNode implements ICust
return decodeStringArrayTemplate;
}
/**
* @returns {string}
*/
protected getTemplate (): string {
const decodeNodeTemplate: string = this.getDecodeStringArrayTemplate();
return JavaScriptObfuscator.obfuscate(
format(StringArrayCallsWrapperTemplate(), {
decodeNodeTemplate,
stringArrayCallsWrapperName: this.stringArrayCallsWrapperName,
stringArrayName: this.stringArrayName
}),
{
...NO_CUSTOM_NODES_PRESET,
seed: this.options.seed
}
).getObfuscatedCode();
}
}
@@ -64,16 +64,6 @@ export class StringArrayNode extends AbstractCustomNode {
this.stringArrayRotateValue = stringArrayRotateValue;
}
/**
* @returns {string}
*/
public getCode (): string {
return format(StringArrayTemplate(), {
stringArrayName: this.stringArrayName,
stringArray: this.stringArray.toString()
});
}
/**
* @returns {TStatement[]}
*/
@@ -82,4 +72,14 @@ export class StringArrayNode extends AbstractCustomNode {
return super.getNode();
}
/**
* @returns {string}
*/
protected getTemplate (): string {
return format(StringArrayTemplate(), {
stringArrayName: this.stringArrayName,
stringArray: this.stringArray.toString()
});
}
}
@@ -65,7 +65,7 @@ export class StringArrayRotateFunctionNode extends AbstractCustomNode {
/**
* @returns {string}
*/
public getCode (): string {
protected getTemplate (): string {
let code: string = '',
timesName: string = RandomGeneratorUtils.getRandomVariableName(),
whileFunctionName: string = RandomGeneratorUtils.getRandomVariableName();
+1
View File
@@ -6,6 +6,7 @@ declare module 'estree' {
interface BaseNode {
parentNode?: ESTree.Node;
obfuscated?: boolean;
skipByControlFlow?: boolean;
}
interface SimpleLiteral extends ESTree.BaseNode, ESTree.BaseExpression {
+2
View File
@@ -25,6 +25,8 @@ export const NodeType: any = Utils.strEnumify({
Program: 'Program',
Property: 'Property',
ReturnStatement: 'ReturnStatement',
SwitchCase: 'SwitchCase',
SwitchStatement: 'SwitchStatement',
TryStatement: 'TryStatement',
UnaryExpression: 'UnaryExpression',
UpdateExpression: 'UpdateExpression',
+2 -2
View File
@@ -9,12 +9,12 @@ export interface IControlFlowReplacer {
* @param parentNode
* @param controlFlowStorage
* @param controlFlowStorageCustomNodeName
* @returns ICustomNode | undefined
* @returns ESTree.Node
*/
replace (
node: ESTree.Node,
parentNode: ESTree.Node,
controlFlowStorage: IStorage <ICustomNode>,
controlFlowStorageCustomNodeName: string
): ICustomNode | undefined;
): ESTree.Node;
}
@@ -7,7 +7,6 @@ import * as ESTree from 'estree';
import { TControlFlowReplacerFactory } from '../../types/container/TControlFlowReplacerFactory';
import { TControlFlowStorageFactory } from '../../types/container/TControlFlowStorageFactory';
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';
@@ -20,6 +19,7 @@ import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
import { Node } from '../../node/Node';
import { NodeAppender } from '../../node/NodeAppender';
import { NodeControlFlowReplacers } from '../../enums/container/NodeControlFlowReplacers';
import { NodeUtils } from '../../node/NodeUtils';
import { RandomGeneratorUtils } from '../../utils/RandomGeneratorUtils';
@injectable()
@@ -92,24 +92,11 @@ export class FunctionControlFlowTransformer extends AbstractNodeTransformer {
return;
}
const controlFlowStorageCallCustomNode: ICustomNode | undefined = this.controlFlowReplacerFactory(controlFlowReplacerName)
.replace(node, parentNode, controlFlowStorage, controlFlowStorageCustomNodeName);
if (!controlFlowStorageCallCustomNode) {
return;
}
// controlFlowStorageCallCustomNode will always have only one TStatement node,
// so we can get it by index `0`
// also we need to return `expression` property of `ExpressionStatement` node because bug:
// https://github.com/estools/escodegen/issues/289
const statementNode: TStatement = controlFlowStorageCallCustomNode.getNode()[0];
if (!statementNode || !Node.isExpressionStatementNode(statementNode)) {
throw new Error(`\`controlFlowStorageCallCustomNode.getNode()\` should returns array with \`ExpressionStatement\` node`);
}
return statementNode.expression;
return {
...this.controlFlowReplacerFactory(controlFlowReplacerName)
.replace(node, parentNode, controlFlowStorage, controlFlowStorageCustomNodeName),
parentNode
};
}
});
@@ -121,6 +108,12 @@ export class FunctionControlFlowTransformer extends AbstractNodeTransformer {
controlFlowStorageCustomNode.initialize(controlFlowStorage, controlFlowStorageCustomNodeName);
NodeAppender.prependNode(functionNode.body, controlFlowStorageCustomNode.getNode());
NodeAppender.prependNode(
NodeUtils.getBlockScopeOfNode(
functionNode.body,
RandomGeneratorUtils.getRandomInteger(0, 5)
),
controlFlowStorageCustomNode.getNode()
);
}
}
@@ -41,12 +41,12 @@ export abstract class AbstractControlFlowReplacer implements IControlFlowReplace
* @param parentNode
* @param controlFlowStorage
* @param controlFlowStorageCustomNodeName
* @returns {ICustomNode | undefined}
* @returns {ESTree.Node}
*/
public abstract replace (
node: ESTree.Node,
parentNode: ESTree.Node,
controlFlowStorage: IStorage <ICustomNode>,
controlFlowStorageCustomNodeName: string
): ICustomNode | undefined;
): ESTree.Node;
}
@@ -5,6 +5,7 @@ import * as escodegen from 'escodegen';
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';
@@ -13,6 +14,7 @@ import { IStorage } from '../../../interfaces/storages/IStorage';
import { CustomNodes } from '../../../enums/container/CustomNodes';
import { AbstractControlFlowReplacer } from './AbstractControlFlowReplacer';
import { Node } from '../../../node/Node';
@injectable()
export class BinaryExpressionControlFlowReplacer extends AbstractControlFlowReplacer {
@@ -49,14 +51,14 @@ export class BinaryExpressionControlFlowReplacer extends AbstractControlFlowRepl
* @param parentNode
* @param controlFlowStorage
* @param controlFlowStorageCustomNodeName
* @returns {ICustomNode}
* @returns {ESTree.Node}
*/
public replace (
binaryExpressionNode: ESTree.BinaryExpression,
parentNode: ESTree.Node,
controlFlowStorage: IStorage <ICustomNode>,
controlFlowStorageCustomNodeName: string
): ICustomNode {
): ESTree.Node {
const key: string = AbstractControlFlowReplacer.getStorageKey();
const binaryExpressionFunctionNode: ICustomNode = this.customNodeFactory(CustomNodes.BinaryExpressionFunctionNode);
const controlFlowStorageCallNode: ICustomNode = this.customNodeFactory(CustomNodes.ControlFlowStorageCallNode);
@@ -71,6 +73,12 @@ export class BinaryExpressionControlFlowReplacer extends AbstractControlFlowRepl
controlFlowStorage.set(key, binaryExpressionFunctionNode);
return controlFlowStorageCallNode;
const statementNode: TStatement = controlFlowStorageCallNode.getNode()[0];
if (!statementNode || !Node.isExpressionStatementNode(statementNode)) {
throw new Error(`\`controlFlowStorageCallCustomNode.getNode()\` should returns array with \`ExpressionStatement\` node`);
}
return statementNode.expression;
}
}
+8
View File
@@ -91,6 +91,14 @@ export class Node {
return node.type === NodeType.Identifier;
}
/**
* @param node
* @returns {boolean}
*/
public static isIfStatementNode (node: ESTree.Node): node is ESTree.IfStatement {
return node.type === NodeType.IfStatement;
}
/**
* @param node
* @param parentNode
+19 -3
View File
@@ -50,6 +50,22 @@ export class NodeUtils {
return <TStatement[]>structure.body;
}
/**
* @param structure
* @returns {string}
*/
public static convertStructureToCode (structure: ESTree.Node[]): string {
let code: string = '';
for (let node of structure) {
code += escodegen.generate(node, {
sourceMapWithCode: true
}).code;
}
return code;
}
/**
* @param node
* @param index
@@ -97,7 +113,7 @@ export class NodeUtils {
return parentNode;
}
return NodeUtils.getBlockScopeOfNode(parentNode);
return NodeUtils.getBlockScopeOfNode(parentNode, depth);
}
/**
@@ -180,12 +196,12 @@ export class NodeUtils {
(<any>estraverse)[traverseType](node, {
enter: (node: ESTree.Node, parentNode: ESTree.Node): any => {
if (node.type === nodeType && visitor.enter) {
visitor.enter(node, parentNode);
return visitor.enter(node, parentNode);
}
},
leave: (node: ESTree.Node, parentNode: ESTree.Node): any => {
if (node.type === nodeType && visitor.leave) {
visitor.leave(node, parentNode);
return visitor.leave(node, parentNode);
}
}
});