More cases with improved objectExpressionKeys support

Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/387
This commit is contained in:
sanex3339
2020-01-06 01:41:00 +03:00
parent 84492b3420
commit 56e80ae800
21 changed files with 500 additions and 46 deletions
+1
View File
@@ -3,6 +3,7 @@ Change Log
v0.21.0
---
* Improved `transformObjectKeys` transformation to cover more cases
* Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/387
v0.20.4
---
+3 -3
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
+3
View File
@@ -14,6 +14,9 @@ export enum NodeType {
ContinueStatement = 'ContinueStatement',
ExportNamedDeclaration = 'ExportNamedDeclaration',
ExpressionStatement = 'ExpressionStatement',
ForStatement = 'ForStatement',
ForInStatement = 'ForInStatement',
ForOfStatement = 'ForOfStatement',
FunctionDeclaration = 'FunctionDeclaration',
FunctionExpression = 'FunctionExpression',
Identifier = 'Identifier',
@@ -70,14 +70,6 @@ export abstract class AbstractPropertiesExtractor implements IPropertiesExtracto
return null;
}
/**
* @param {Node} node
* @returns {propertyValueNode is Pattern}
*/
protected static isProhibitedHostParent (node: ESTree.Node): node is ESTree.Pattern {
return NodeGuards.isMemberExpressionNode(node);
}
/**
* @param {Node} node
* @returns {propertyValueNode is Pattern}
@@ -7,6 +7,7 @@ import { IOptions } from '../../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../../interfaces/utils/IRandomGenerator';
import { AbstractPropertiesExtractor } from './AbstractPropertiesExtractor';
import { NodeGuards } from '../../../node/NodeGuards';
@injectable()
export class AssignmentExpressionPropertiesExtractor extends AbstractPropertiesExtractor {
@@ -21,6 +22,35 @@ export class AssignmentExpressionPropertiesExtractor extends AbstractPropertiesE
super(randomGenerator, options);
}
/**
* @param {Node} node
* @returns {propertyValueNode is Pattern}
*/
private static isProhibitedHostParent (node: ESTree.Node): node is ESTree.Pattern {
if (NodeGuards.isMemberExpressionNode(node)) {
return true;
}
if (AssignmentExpressionPropertiesExtractor.isProhibitedStatementNode(node)) {
return true;
}
// statements without block statement
return NodeGuards.isExpressionStatementNode(node)
&& !!node.parentNode
&& AssignmentExpressionPropertiesExtractor.isProhibitedStatementNode(node.parentNode);
}
/**
* @param {Node} node
* @returns {boolean}
*/
private static isProhibitedStatementNode (node: ESTree.Node): boolean {
return NodeGuards.isIfStatementNode(node)
|| NodeGuards.isForStatementTypeNode(node)
|| NodeGuards.isWhileStatementNode(node);
}
/**
* @param {ObjectExpression} objectExpressionNode
* @param {AssignmentExpression} hostNode
@@ -38,8 +68,8 @@ export class AssignmentExpressionPropertiesExtractor extends AbstractPropertiesE
return objectExpressionNode;
}
// left node shouldn't be as Pattern node
if (hostParentNode && AbstractPropertiesExtractor.isProhibitedHostParent(hostParentNode)) {
// left node shouldn't be as prohibited node
if (hostParentNode && AssignmentExpressionPropertiesExtractor.isProhibitedHostParent(hostParentNode)) {
return objectExpressionNode;
}
+44
View File
@@ -124,6 +124,42 @@ export class NodeGuards {
&& !('directive' in node);
}
/**
* @param {Node} node
* @returns {boolean}
*/
public static isForStatementTypeNode (
node: ESTree.Node
): node is ESTree.ForStatement | ESTree.ForInStatement | ESTree.ForOfStatement {
return NodeGuards.isForStatementNode(node)
|| NodeGuards.isForInStatementNode(node)
|| NodeGuards.isForOfStatementNode(node);
}
/**
* @param {Node} node
* @returns {boolean}
*/
public static isForStatementNode (node: ESTree.Node): node is ESTree.ForStatement {
return node.type === NodeType.ForStatement;
}
/**
* @param {Node} node
* @returns {boolean}
*/
public static isForInStatementNode (node: ESTree.Node): node is ESTree.ForInStatement {
return node.type === NodeType.ForInStatement;
}
/**
* @param {Node} node
* @returns {boolean}
*/
public static isForOfStatementNode (node: ESTree.Node): node is ESTree.ForOfStatement {
return node.type === NodeType.ForOfStatement;
}
/**
* @param {Node} node
* @returns {boolean}
@@ -160,6 +196,14 @@ export class NodeGuards {
return node.type === NodeType.Identifier;
}
/**
* @param {Node} node
* @returns {boolean}
*/
public static isIfStatementNode (node: ESTree.Node): node is ESTree.IfStatement {
return node.type === NodeType.IfStatement;
}
/**
* @param {Node} node
* @returns {boolean}
+4 -10
View File
@@ -8,20 +8,14 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../src/options/presets/NoCustomNo
let obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
`
function foo () {
function foo () {
return {
bar: {
foo: 1
}
};
}
var bar;
if (false)
bar = {baz: 1};
}
`,
{
...NO_ADDITIONAL_NODES_PRESET,
transformObjectKeys: true,
controlFlowFlattening: true,
controlFlowFlatteningThreshold: 1
transformObjectKeys: true
}
).getObfuscatedCode();
@@ -456,34 +456,363 @@ describe('ObjectExpressionKeysTransformer', () => {
describe('correct placement of expression statements', () => {
describe('Variant #1: if statement', () => {
const match: string = `` +
`if *\\(!!\\[]\\) *{` +
describe('Variant #1: with block statement', () => {
const match: string = `` +
`if *\\(!!\\[]\\) *{` +
`var *${variableMatch} *= *{};` +
`${variableMatch}\\['foo'] *= *'bar';` +
`}` +
``;
const regExp: RegExp = new RegExp(match);
`}` +
``;
const regExp: RegExp = new RegExp(match);
let obfuscatedCode: string;
let obfuscatedCode: string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/placement-inside-if-statement.js');
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/placement-inside-if-statement.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
transformObjectKeys: true
}
).getObfuscatedCode();
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
transformObjectKeys: true
}
).getObfuscatedCode();
});
it('should correctly transform object keys', () => {
assert.match(obfuscatedCode, regExp);
});
});
it('should correctly transform object keys', () => {
assert.match(obfuscatedCode, regExp);
describe('Variant #2: without block statement', () => {
const match: string = `` +
`var ${variableMatch};` +
`var ${variableMatch} *= *{};` +
`${variableMatch}\\['bar'] *= *'bar';` +
`var ${variableMatch} *= *{};` +
`${variableMatch}\\['baz'] *= *'baz';` +
`if *\\(!!\\[]\\)` +
`${variableMatch} *= *${variableMatch};` +
`else *` +
`${variableMatch} *= *${variableMatch};` +
``;
const regExp: RegExp = new RegExp(match);
let obfuscatedCode: string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/placement-inside-if-statement-without-block-statement.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
transformObjectKeys: true
}
).getObfuscatedCode();
});
it('should correctly transform object keys', () => {
assert.match(obfuscatedCode, regExp);
});
});
describe('Variant #3: inside condition', () => {
const match: string = `` +
`var ${variableMatch};` +
`var ${variableMatch} *= *{};` +
`${variableMatch}\\['bar'] *= *'bar';` +
`if *\\(${variableMatch} *= *${variableMatch}\\) *{}` +
``;
const regExp: RegExp = new RegExp(match);
let obfuscatedCode: string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/placement-inside-if-statement-condition.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
transformObjectKeys: true
}
).getObfuscatedCode();
});
it('should correctly transform object keys', () => {
assert.match(obfuscatedCode, regExp);
});
});
});
describe('Variant #2: try statement', () => {
describe('Variant #2: for statement', () => {
describe('Variant #1: with block statement', () => {
const match: string = `` +
`for *\\(var *${variableMatch} *= *0x0; *${variableMatch} *< *0xa; *${variableMatch}\\+\\+\\) *{` +
`var *${variableMatch} *= *{};` +
`${variableMatch}\\['foo'] *= *'bar';` +
`}` +
``;
const regExp: RegExp = new RegExp(match);
let obfuscatedCode: string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/placement-inside-for-statement.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
transformObjectKeys: true
}
).getObfuscatedCode();
});
it('should correctly transform object keys', () => {
assert.match(obfuscatedCode, regExp);
});
});
describe('Variant #2: without block statement', () => {
const match: string = `` +
`var ${variableMatch};` +
`var ${variableMatch} *= *{};` +
`${variableMatch}\\['bar'] *= *'bar';` +
`for *\\(var *${variableMatch} *= *0x0; *${variableMatch} *< *0xa; *${variableMatch}\\+\\+\\) *` +
`${variableMatch} *= *${variableMatch};` +
``;
const regExp: RegExp = new RegExp(match);
let obfuscatedCode: string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/placement-inside-for-statement-without-block-statement.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
transformObjectKeys: true
}
).getObfuscatedCode();
});
it('should correctly transform object keys', () => {
assert.match(obfuscatedCode, regExp);
});
});
});
describe('Variant #3: for in statement', () => {
describe('Variant #1: with block statement', () => {
const match: string = `` +
`var ${variableMatch} *= *{};` +
`for *\\(var *${variableMatch} in *${variableMatch}\\) *{` +
`${variableMatch} *= *{};` +
`${variableMatch}\\['bar'] *= *'bar';` +
`}` +
``;
const regExp: RegExp = new RegExp(match);
let obfuscatedCode: string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/placement-inside-for-in-statement.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
transformObjectKeys: true
}
).getObfuscatedCode();
});
it('should correctly transform object keys', () => {
assert.match(obfuscatedCode, regExp);
});
});
describe('Variant #2: without block statement', () => {
const match: string = `` +
`var ${variableMatch} *= *{};` +
`var ${variableMatch} *= *{};` +
`${variableMatch}\\['bar'] *= *'bar';` +
`for *\\(var *${variableMatch} in *${variableMatch}\\) *` +
`${variableMatch} *= *${variableMatch};` +
``;
const regExp: RegExp = new RegExp(match);
let obfuscatedCode: string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/placement-inside-for-in-statement-without-block-statement.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
transformObjectKeys: true
}
).getObfuscatedCode();
});
it('should correctly transform object keys', () => {
assert.match(obfuscatedCode, regExp);
});
});
});
describe('Variant #4: for of statement', () => {
describe('Variant #1: with block statement', () => {
const match: string = `` +
`var ${variableMatch} *= *\\[];` +
`for *\\(var *${variableMatch} of *${variableMatch}\\) *{` +
`${variableMatch} *= *{};` +
`${variableMatch}\\['bar'] *= *'bar';` +
`}` +
``;
const regExp: RegExp = new RegExp(match);
let obfuscatedCode: string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/placement-inside-for-of-statement.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
transformObjectKeys: true
}
).getObfuscatedCode();
});
it('should correctly transform object keys', () => {
assert.match(obfuscatedCode, regExp);
});
});
describe('Variant #2: without block statement', () => {
const match: string = `` +
`var ${variableMatch} *= *\\[];` +
`var ${variableMatch} *= *{};` +
`${variableMatch}\\['bar'] *= *'bar';` +
`for *\\(var *${variableMatch} of *${variableMatch}\\) *` +
`${variableMatch} *= *${variableMatch};` +
``;
const regExp: RegExp = new RegExp(match);
let obfuscatedCode: string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/placement-inside-for-of-statement-without-block-statement.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
transformObjectKeys: true
}
).getObfuscatedCode();
});
it('should correctly transform object keys', () => {
assert.match(obfuscatedCode, regExp);
});
});
});
describe('Variant #5: while statement', () => {
describe('Variant #1: with block statement', () => {
const match: string = `` +
`while *\\(!!\\[]\\) *{` +
`var *${variableMatch} *= *{};` +
`${variableMatch}\\['foo'] *= *'bar';` +
`}` +
``;
const regExp: RegExp = new RegExp(match);
let obfuscatedCode: string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/placement-inside-while-statement.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
transformObjectKeys: true
}
).getObfuscatedCode();
});
it('should correctly transform object keys', () => {
assert.match(obfuscatedCode, regExp);
});
});
describe('Variant #2: without block statement', () => {
const match: string = `` +
`var ${variableMatch};` +
`var ${variableMatch} *= *{};` +
`${variableMatch}\\['bar'] *= *'bar';` +
`while *\\(!!\\[]\\)` +
`${variableMatch} *= *${variableMatch};` +
``;
const regExp: RegExp = new RegExp(match);
let obfuscatedCode: string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/placement-inside-while-statement-without-block-statement.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
transformObjectKeys: true
}
).getObfuscatedCode();
});
it('should correctly transform object keys', () => {
assert.match(obfuscatedCode, regExp);
});
});
describe('Variant #3: inside condition', () => {
const match: string = `` +
`var ${variableMatch};` +
`var ${variableMatch} *= *{};` +
`${variableMatch}\\['bar'] *= *'bar';` +
`while *\\(${variableMatch} *= *${variableMatch}\\) *{}` +
``;
const regExp: RegExp = new RegExp(match);
let obfuscatedCode: string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/placement-inside-while-statement-condition.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
transformObjectKeys: true
}
).getObfuscatedCode();
});
it('should correctly transform object keys', () => {
assert.match(obfuscatedCode, regExp);
});
});
});
describe('Variant #6: try statement', () => {
const match: string = `` +
`try *{` +
`var *${variableMatch} *= *{};` +
@@ -512,7 +841,7 @@ describe('ObjectExpressionKeysTransformer', () => {
});
});
describe('Variant #3: catch clause statement', () => {
describe('Variant #7: catch clause statement', () => {
const match: string = `` +
`try *{` +
`} *catch *\\(${variableMatch}\\) *{` +
@@ -541,7 +870,7 @@ describe('ObjectExpressionKeysTransformer', () => {
});
});
describe('Variant #4: switch catch statement', () => {
describe('Variant #8: switch catch statement', () => {
const match: string = `` +
`switch *\\(!!\\[]\\) *{` +
`case *!!\\[]:` +
@@ -570,7 +899,7 @@ describe('ObjectExpressionKeysTransformer', () => {
});
});
describe('Variant #5: variable declarator with object call', () => {
describe('Variant #9: variable declarator with object call', () => {
describe('Variant #1', () => {
const match: string = `` +
`const *${variableMatch} *= *{}; *` +
@@ -0,0 +1,5 @@
(function(){
var foo = {};
for (var i in foo)
foo = {bar: 'bar'};
})();
@@ -0,0 +1,6 @@
(function(){
var object = {};
for (var i in object) {
object = {bar: 'bar'};
}
})();
@@ -0,0 +1,5 @@
(function(){
var foo = [];
for (var i of foo)
foo = {bar: 'bar'};
})();
@@ -0,0 +1,6 @@
(function(){
var object = [];
for (var i of object) {
object = {bar: 'bar'};
}
})();
@@ -0,0 +1,5 @@
(function(){
var foo;
for (var i = 0; i < 10; i++)
foo = {bar: 'bar'};
})();
@@ -0,0 +1,7 @@
(function(){
for (var i = 0; i < 10; i++) {
var object = {
foo: 'bar'
};
}
})();
@@ -0,0 +1,4 @@
(function(){
var object;
if (object = {bar: 'bar'}) {}
})();
@@ -0,0 +1,7 @@
(function () {
var foo;
if (true)
foo = {bar: 'bar'};
else
foo = {baz: 'baz'};
})();
@@ -0,0 +1,4 @@
(function(){
var object;
while (object = {bar: 'bar'}) {}
})();
@@ -0,0 +1,7 @@
(function(){
while (true) {
var object = {
foo: 'bar'
};
}
})();