ExpressionStatementsMergeTransformer + optimized AbstractStatementSimplifyTransformer logic

This commit is contained in:
sanex3339
2020-07-15 15:20:19 +03:00
parent c8213529b1
commit 37eb0aa745
13 changed files with 223 additions and 26 deletions
+6 -6
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1
View File
@@ -68,6 +68,7 @@ export class JavaScriptObfuscator implements IJavaScriptObfuscator {
NodeTransformer.CustomCodeHelpersTransformer,
NodeTransformer.DeadCodeInjectionTransformer,
NodeTransformer.EvalCallExpressionTransformer,
NodeTransformer.ExpressionStatementsMergeTransformer,
NodeTransformer.FunctionControlFlowTransformer,
NodeTransformer.IfStatementSimplifyTransformer,
NodeTransformer.LabeledStatementTransformer,
@@ -6,6 +6,7 @@ import { INodeTransformer } from '../../../interfaces/node-transformers/INodeTra
import { NodeTransformer } from '../../../enums/node-transformers/NodeTransformer';
import { BlockStatementSimplifyTransformer } from '../../../node-transformers/simplifying-transformers/BlockStatementSimplifyTransformer';
import { ExpressionStatementsMergeTransformer } from '../../../node-transformers/simplifying-transformers/ExpressionStatementsMergeTransformer';
import { IfStatementSimplifyTransformer } from '../../../node-transformers/simplifying-transformers/IfStatementSimplifyTransformer';
import { VariableDeclarationsMergeTransformer } from '../../../node-transformers/simplifying-transformers/VariableDeclarationsMergeTransformer';
@@ -15,6 +16,10 @@ export const simplifyingTransformersModule: interfaces.ContainerModule = new Con
.to(BlockStatementSimplifyTransformer)
.whenTargetNamed(NodeTransformer.BlockStatementSimplifyTransformer);
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(ExpressionStatementsMergeTransformer)
.whenTargetNamed(NodeTransformer.ExpressionStatementsMergeTransformer);
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(IfStatementSimplifyTransformer)
.whenTargetNamed(NodeTransformer.IfStatementSimplifyTransformer);
@@ -5,6 +5,7 @@ export enum NodeTransformer {
CustomCodeHelpersTransformer = 'CustomCodeHelpersTransformer',
DeadCodeInjectionTransformer = 'DeadCodeInjectionTransformer',
EvalCallExpressionTransformer = 'EvalCallExpressionTransformer',
ExpressionStatementsMergeTransformer = 'ExpressionStatementsMergeTransformer',
FunctionControlFlowTransformer = 'FunctionControlFlowTransformer',
IfStatementSimplifyTransformer = 'IfStatementSimplifyTransformer',
LabeledStatementTransformer = 'LabeledStatementTransformer',
@@ -23,6 +23,7 @@ export abstract class AbstractStatementSimplifyTransformer extends AbstractNodeT
* @type {NodeTransformer[]}
*/
public readonly runAfter: NodeTransformer[] = [
NodeTransformer.ExpressionStatementsMergeTransformer,
NodeTransformer.VariableDeclarationsMergeTransformer
];
@@ -110,17 +111,19 @@ export abstract class AbstractStatementSimplifyTransformer extends AbstractNodeT
const unwrappedExpressions: ESTree.Expression[] = [];
let hasReturnStatement: boolean = false;
let startIndex: number | null = 0;
let startIndex: number | null = null;
for (let i = 0; i < statementNodeBodyLength; i++) {
for (let i = statementNodeBodyLength - 1; i >= 0; i--) {
const statementBodyStatementNode: ESTree.Statement = statementNode.body[i];
if (startIndex === null) {
startIndex = i;
}
if (NodeGuards.isExpressionStatementNode(statementBodyStatementNode)) {
unwrappedExpressions.push(statementBodyStatementNode.expression);
if (NodeGuards.isSequenceExpressionNode(statementBodyStatementNode.expression)) {
unwrappedExpressions.unshift(...statementBodyStatementNode.expression.expressions);
} else {
unwrappedExpressions.unshift(statementBodyStatementNode.expression);
}
startIndex = i;
continue;
}
@@ -128,13 +131,13 @@ export abstract class AbstractStatementSimplifyTransformer extends AbstractNodeT
NodeGuards.isReturnStatementNode(statementBodyStatementNode)
&& statementBodyStatementNode.argument
) {
unwrappedExpressions.push(statementBodyStatementNode.argument);
unwrappedExpressions.unshift(statementBodyStatementNode.argument);
hasReturnStatement = true;
startIndex = i;
continue;
}
startIndex = null;
unwrappedExpressions.length = 0;
break;
}
return {
@@ -0,0 +1,97 @@
import { inject, injectable, } from 'inversify';
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import * as estraverse from 'estraverse';
import * as ESTree from 'estree';
import { TStatement } from '../../types/node/TStatement';
import { IOptions } from '../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
import { IVisitor } from '../../interfaces/node-transformers/IVisitor';
import { NodeTransformationStage } from '../../enums/node-transformers/NodeTransformationStage';
import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
import { NodeFactory } from '../../node/NodeFactory';
import { NodeGuards } from '../../node/NodeGuards';
import { NodeStatementUtils } from '../../node/NodeStatementUtils';
import { NodeUtils } from '../../node/NodeUtils';
/**
* replaces:
* console.log(1);
* console.log(2);
*
* on:
* (console.log(1), console.log(2));
*/
@injectable()
export class ExpressionStatementsMergeTransformer extends AbstractNodeTransformer {
/**
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
*/
public constructor (
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IOptions) options: IOptions
) {
super(randomGenerator, options);
}
/**
* @param {NodeTransformationStage} nodeTransformationStage
* @returns {IVisitor | null}
*/
public getVisitor (nodeTransformationStage: NodeTransformationStage): IVisitor | null {
switch (nodeTransformationStage) {
case NodeTransformationStage.Simplifying:
return {
leave: (
node: ESTree.Node,
parentNode: ESTree.Node | null
): ESTree.Node | estraverse.VisitorOption | undefined => {
if (parentNode && NodeGuards.isExpressionStatementNode(node)) {
return this.transformNode(node, parentNode);
}
}
};
default:
return null;
}
}
/**
* @param {ESTree.ExpressionStatement} expressionStatementNode
* @param {ESTree.Node} parentNode
* @returns {ESTree.ExpressionStatement | estraverse.VisitorOption}
*/
public transformNode (
expressionStatementNode: ESTree.ExpressionStatement,
parentNode: ESTree.Node
): ESTree.ExpressionStatement | estraverse.VisitorOption {
if (!NodeGuards.isNodeWithStatements(parentNode)) {
return expressionStatementNode;
}
const prevStatement: TStatement | null = NodeStatementUtils.getPreviousSiblingStatement(expressionStatementNode);
if (!prevStatement || !NodeGuards.isExpressionStatementNode(prevStatement)) {
return expressionStatementNode;
}
if (NodeGuards.isSequenceExpressionNode(prevStatement.expression)) {
prevStatement.expression.expressions.push(expressionStatementNode.expression);
} else {
prevStatement.expression = NodeFactory.sequenceExpressionNode([
prevStatement.expression,
expressionStatementNode.expression
]);
}
NodeUtils.parentizeAst(prevStatement);
return estraverse.VisitorOption.Remove;
}
}
+5 -8
View File
@@ -7,14 +7,11 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../src/options/presets/NoCustomNo
let obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
`
var foo = function () {};
var bar = function () {
var baz = function () {};
var bark = function () {
var hawk = 1;
var dog = 2;
};
};
function foo () {
console.log(7);
return 9;
}
`,
{
...NO_ADDITIONAL_NODES_PRESET,
@@ -0,0 +1,72 @@
import { assert } from 'chai';
import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes';
import { readFileAsString } from '../../../../helpers/readFileAsString';
import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade';
describe('ExpressionStatementsMergeTransformer', () => {
describe('Variant #1: simple', () => {
const regExp: RegExp = new RegExp(
'function foo *\\(\\) *{ *' +
'bar\\(\\), *' +
'baz\\(\\), *' +
'bark\\(\\); *' +
'}'
);
let obfuscatedCode: string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/simple.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
simplify: true
}
).getObfuscatedCode();
});
it('should merge expression statements', () => {
assert.match(obfuscatedCode, regExp);
});
});
describe('Variant #2: complex', () => {
const regExp: RegExp = new RegExp(
'function foo *\\(\\) *{ *' +
'console\\[\'log\']\\(0x1\\), *' +
'console\\[\'log\']\\(0x2\\); *' +
'function _0x([a-f0-9]){4,6} *\\(\\) *{ *} *' +
'console\\[\'log\']\\(0x3\\), *' +
'console\\[\'log\']\\(0x4\\), *' +
'console\\[\'log\']\\(0x5\\); *' +
'const _0x([a-f0-9]){4,6} *= *0x6; *' +
'console\\[\'log\']\\(0x7\\); *' +
'}'
);
let obfuscatedCode: string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/complex.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
simplify: true
}
).getObfuscatedCode();
});
it('should merge expression statements', () => {
assert.match(obfuscatedCode, regExp);
});
});
});
@@ -0,0 +1,14 @@
function foo () {
console.log(1);
console.log(2);
function bar () {}
console.log(3);
console.log(4);
console.log(5);
const baz = 6;
console.log(7);
}
@@ -0,0 +1,5 @@
function foo () {
bar();
baz();
bark();
}
+2
View File
@@ -95,6 +95,8 @@ import './functional-tests/node-transformers/converting-transformers/split-strin
import './functional-tests/node-transformers/converting-transformers/template-literal-transformer/TemplateLiteralTransformer.spec';
import './functional-tests/node-transformers/dead-code-injection-transformers/DeadCodeInjectionTransformer.spec';
import './functional-tests/node-transformers/initializing-transformers/comments-transformer/CommentsTransformer.spec';
import './functional-tests/node-transformers/simplifying-transformers/block-statement-simplify-transformer/BlockStatementSimplifyTransformer.spec';
import './functional-tests/node-transformers/simplifying-transformers/expression-statements-merge-transformer/ExpressionStatementsMergeTransformer.spec';
import './functional-tests/node-transformers/simplifying-transformers/if-statement-simplify-transformer/IfStatementSimplifyTransformer.spec';
import './functional-tests/node-transformers/simplifying-transformers/variable-declarations-merge-transformer/VariableDeclarationsMergeTransformer.spec';
import './functional-tests/node-transformers/obfuscating-transformers/labeled-statement-transformer/LabeledStatementTransformer.spec';