mirror of
https://github.com/javascript-obfuscator/javascript-obfuscator
synced 2026-08-09 12:42:29 +00:00
Improved integration between renameProperties and controlFlowFlattening options (#1060)
This commit is contained in:
+25
-42
@@ -1,55 +1,38 @@
|
||||
'use strict';
|
||||
|
||||
import { StringArrayWrappersType } from '../../src/enums/node-transformers/string-array-transformers/StringArrayWrappersType';
|
||||
|
||||
(function () {
|
||||
const JavaScriptObfuscator: any = require('../../index');
|
||||
|
||||
let obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
|
||||
`
|
||||
function foo () {
|
||||
function bar() {
|
||||
var string1 = 'string1';
|
||||
var string2 = 'string2';
|
||||
var string3 = 'string3';
|
||||
var string4 = 'string4';
|
||||
var string5 = 'string5';
|
||||
var string6 = 'string6';
|
||||
|
||||
function bark () {
|
||||
var string1 = 'string1';
|
||||
var string2 = 'string2';
|
||||
var string3 = 'string3';
|
||||
var string4 = 'string4';
|
||||
var string5 = 'string5';
|
||||
var string6 = 'string6';
|
||||
}
|
||||
}
|
||||
|
||||
bar()
|
||||
var obj = {
|
||||
foo: 1
|
||||
}
|
||||
|
||||
console.log(foo());
|
||||
`,
|
||||
{
|
||||
identifierNamesGenerator: 'mangled',
|
||||
compact: false,
|
||||
controlFlowFlattening: false,
|
||||
controlFlowFlatteningThreshold: 1,
|
||||
simplify: false,
|
||||
stringArrayRotate: false,
|
||||
stringArray: true,
|
||||
stringArrayIndexesType: [
|
||||
'hexadecimal-number',
|
||||
'hexadecimal-numeric-string'
|
||||
],
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayCallsTransform: true,
|
||||
stringArrayCallsTransformThreshold: 1,
|
||||
rotateStringArray: true,
|
||||
stringArrayWrappersType: StringArrayWrappersType.Function,
|
||||
transformObjectKeys: false,
|
||||
seed: 1
|
||||
"compact": false,
|
||||
"controlFlowFlattening": true,
|
||||
"controlFlowFlatteningThreshold": 1,
|
||||
"disableConsoleOutput": false,
|
||||
"identifierNamesGenerator": "mangled",
|
||||
"log": true,
|
||||
"numbersToExpressions": true,
|
||||
"renameProperties": true,
|
||||
"renamePropertiesMode": "safe",
|
||||
"simplify": false,
|
||||
"stringArray": true,
|
||||
"stringArrayCallsTransform": true,
|
||||
"stringArrayIndexShift": true,
|
||||
"stringArrayRotate": false,
|
||||
"stringArrayShuffle": false,
|
||||
"stringArrayWrappersCount": 5,
|
||||
"stringArrayWrappersChainedCalls": true,
|
||||
"stringArrayWrappersParametersMaxCount": 5,
|
||||
"stringArrayWrappersType": "function",
|
||||
"stringArrayThreshold": 0,
|
||||
"transformObjectKeys": true,
|
||||
"unicodeEscapeSequence": false,
|
||||
"ignoreRequireImports": false
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
|
||||
|
||||
+56
-22
@@ -3,6 +3,7 @@ import { assert } from 'chai';
|
||||
import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../../src/options/presets/NoCustomNodes';
|
||||
|
||||
import { readFileAsString } from '../../../../../helpers/readFileAsString';
|
||||
import { getRegExpMatch } from '../../../../../helpers/getRegExpMatch';
|
||||
|
||||
import { JavaScriptObfuscator } from '../../../../../../src/JavaScriptObfuscatorFacade';
|
||||
|
||||
@@ -10,34 +11,67 @@ describe('StringLiteralControlFlowReplacer', () => {
|
||||
describe('replace', () => {
|
||||
const variableMatch: string = '_0x([a-f0-9]){4,6}';
|
||||
|
||||
const controlFlowStorageStringLiteralRegExp: RegExp = new RegExp(
|
||||
`var ${variableMatch} *= *\\{'\\w{5}' *: *'test'\\};`
|
||||
);
|
||||
const controlFlowStorageCallRegExp: RegExp = new RegExp(
|
||||
`var ${variableMatch} *= *${variableMatch}\\['\\w{5}'\\];`
|
||||
);
|
||||
describe('Variant #1 - base behavior', () => {
|
||||
|
||||
let obfuscatedCode: string;
|
||||
const controlFlowStorageStringLiteralRegExp: RegExp = new RegExp(
|
||||
`var ${variableMatch} *= *\\{'\\w{5}' *: *'test'\\};`
|
||||
);
|
||||
const controlFlowStorageCallRegExp: RegExp = new RegExp(
|
||||
`var ${variableMatch} *= *${variableMatch}\\['\\w{5}'\\];`
|
||||
);
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/input-1.js');
|
||||
let obfuscatedCode: string;
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
controlFlowFlattening: true,
|
||||
controlFlowFlatteningThreshold: 1
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/input-1.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
controlFlowFlattening: true,
|
||||
controlFlowFlatteningThreshold: 1
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should add string literal node as property of control flow storage node', () => {
|
||||
assert.match(obfuscatedCode, controlFlowStorageStringLiteralRegExp);
|
||||
});
|
||||
|
||||
it('should replace string literal node with call to control flow storage node', () => {
|
||||
assert.match(obfuscatedCode, controlFlowStorageCallRegExp);
|
||||
});
|
||||
});
|
||||
|
||||
it('should add string literal node as property of control flow storage node', () => {
|
||||
assert.match(obfuscatedCode, controlFlowStorageStringLiteralRegExp);
|
||||
});
|
||||
describe('Variant #2 - same storage key for same string values', () => {
|
||||
const storageKeyRegExp: RegExp = /'(\w{5})': 'value'/;
|
||||
const expectedStorageCallsMatchesCount: number = 5;
|
||||
|
||||
it('should replace string literal node with call to control flow storage node', () => {
|
||||
assert.match(obfuscatedCode, controlFlowStorageCallRegExp);
|
||||
let storageCallsMatchesCount: number;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/same-storage-key-for-same-string-values.js');
|
||||
|
||||
const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
compact: false,
|
||||
controlFlowFlattening: true,
|
||||
controlFlowFlatteningThreshold: 1
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
|
||||
const storageKeyMatch = getRegExpMatch(obfuscatedCode, storageKeyRegExp);
|
||||
const storageCallsRegExp = new RegExp(`${variableMatch}\\[\'${storageKeyMatch}\']`, 'g')
|
||||
|
||||
storageCallsMatchesCount = obfuscatedCode.match(storageCallsRegExp)?.length ?? 0;
|
||||
});
|
||||
|
||||
it('should add string literal nodes with same values under same storage item', () => {
|
||||
assert.equal(storageCallsMatchesCount, expectedStorageCallsMatchesCount);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
(function () {
|
||||
var string1 = 'value';
|
||||
var string2 = 'value';
|
||||
var string3 = 'value';
|
||||
var string4 = 'value';
|
||||
var string5 = 'value';
|
||||
})();
|
||||
+64
@@ -411,6 +411,70 @@ describe('RenamePropertiesTransformer', () => {
|
||||
assert.match(obfuscatedCode, propertyRegExp);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #10: integration with `controlFlowFlattening` option', () => {
|
||||
const propertyRegExp: RegExp = new RegExp(
|
||||
'const b *= *{ *' +
|
||||
'\'\\w{5}\' *: *\'a\' *' +
|
||||
'}; *' +
|
||||
'const c *= *{' +
|
||||
'\'a\': *0x1' +
|
||||
'};' +
|
||||
'c\\[b\\[\'\\w{5}\']];'
|
||||
);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/control-flow-flattening-integration.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
renameProperties: true,
|
||||
renamePropertiesMode: RenamePropertiesMode.Unsafe,
|
||||
identifierNamesGenerator: IdentifierNamesGenerator.MangledIdentifierNamesGenerator,
|
||||
controlFlowFlattening: true,
|
||||
controlFlowFlatteningThreshold: 1
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('Should correctly rename property when `controlFlowFlattening` option is enabled', () => {
|
||||
assert.match(obfuscatedCode, propertyRegExp);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #11: integration with `transformObjectKeys` option', () => {
|
||||
const propertyRegExp: RegExp = new RegExp(
|
||||
'const b *= *{}; *' +
|
||||
'b\\[\'a\'] *= *0x1;' +
|
||||
'const foo *= *b;' +
|
||||
'foo\\[\'a\'];'
|
||||
);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/transform-object-keys-integration.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
renameProperties: true,
|
||||
renamePropertiesMode: RenamePropertiesMode.Unsafe,
|
||||
identifierNamesGenerator: IdentifierNamesGenerator.MangledIdentifierNamesGenerator,
|
||||
transformObjectKeys: true
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('Should correctly rename property when `transformObjectKeys` option is enabled', () => {
|
||||
assert.match(obfuscatedCode, propertyRegExp);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #3: Ignored literal node type', () => {
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
(() => {
|
||||
const foo = {
|
||||
bar: 1
|
||||
};
|
||||
foo['bar'];
|
||||
})();
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
const foo = {
|
||||
bar: 1
|
||||
};
|
||||
foo['bar'];
|
||||
+9
-5
@@ -132,13 +132,14 @@ describe('StringArrayRotateFunctionTransformer', function () {
|
||||
});
|
||||
|
||||
describe('Code evaluation', function () {
|
||||
this.timeout(100000);
|
||||
const samplesCount: number = 50;
|
||||
const evaluationTimeout: number = 5000;
|
||||
|
||||
const samplesCount: number = 100;
|
||||
this.timeout(samplesCount * evaluationTimeout);
|
||||
|
||||
let hasRuntimeErrors: boolean = false;
|
||||
|
||||
before(() => {
|
||||
before(async() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/code-evaluation.js');
|
||||
|
||||
const obfuscateFunc = () => {
|
||||
@@ -186,7 +187,10 @@ describe('StringArrayRotateFunctionTransformer', function () {
|
||||
|
||||
for (let i = 0; i < samplesCount; i++) {
|
||||
try {
|
||||
const evaluationResult = eval(obfuscateFunc());
|
||||
const evaluationResult = await evaluateInWorker(
|
||||
obfuscateFunc(),
|
||||
evaluationTimeout
|
||||
);
|
||||
|
||||
if (evaluationResult !== 'fooooooo') {
|
||||
hasRuntimeErrors = true;
|
||||
@@ -205,7 +209,7 @@ describe('StringArrayRotateFunctionTransformer', function () {
|
||||
});
|
||||
|
||||
describe('Prevent early successful comparison', () => {
|
||||
const evaluationTimeout: number = 1000;
|
||||
const evaluationTimeout: number = 1000;
|
||||
const samplesCount: number = 100;
|
||||
|
||||
let numberNumericalExpressionAnalyzerAnalyzeStub: sinon.SinonStub;
|
||||
|
||||
@@ -86,6 +86,24 @@ describe('NodeMetadata', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('propertyKeyToRenameNode', () => {
|
||||
const expectedValue: boolean = true;
|
||||
|
||||
let node: ESTree.Identifier,
|
||||
value: boolean | undefined;
|
||||
|
||||
before(() => {
|
||||
node = NodeFactory.identifierNode('foo');
|
||||
node.metadata = {};
|
||||
node.metadata.propertyKeyToRenameNode = true;
|
||||
value = NodeMetadata.isPropertyKeyToRenameNode(node);
|
||||
});
|
||||
|
||||
it('should return metadata value', () => {
|
||||
assert.equal(value, expectedValue);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isStringArrayCallLiteralNode', () => {
|
||||
const expectedValue: boolean = true;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user