Improved mangled identifier names generator. Improved variable preserving.

This commit is contained in:
sanex3339
2020-02-11 23:03:02 +03:00
parent 029d5953c2
commit 002697caf5
27 changed files with 255 additions and 164 deletions
+1
View File
@@ -2,6 +2,7 @@ Change Log
v0.25.0
---
* Improved `mangled` identifier names generator logic
* Fixed conflicts between generated names and names from untouched identifiers from source code. Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/550. Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/549
* Prevented transformation of object keys in sequence expression that has `super` call
+5 -5
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
+34 -6
View File
@@ -2,6 +2,7 @@ import { inject, injectable } from 'inversify';
import { ServiceIdentifiers } from '../container/ServiceIdentifiers';
import { TIdentifierNamesGeneratorFactory } from '../types/container/generators/TIdentifierNamesGeneratorFactory';
import { TInputOptions } from '../types/options/TInputOptions';
import { TStatement } from '../types/node/TStatement';
import { ICustomNode } from '../interfaces/custom-nodes/ICustomNode';
@@ -13,6 +14,10 @@ import { ICustomNodeFormatter } from '../interfaces/custom-nodes/ICustomNodeForm
import { GlobalVariableTemplate1 } from '../templates/GlobalVariableTemplate1';
import { GlobalVariableTemplate2 } from '../templates/GlobalVariableTemplate2';
import { NO_ADDITIONAL_NODES_PRESET } from '../options/presets/NoCustomNodes';
import { JavaScriptObfuscator } from '../JavaScriptObfuscatorFacade';
@injectable()
export abstract class AbstractCustomNode <
TInitialData extends any[] = any[]
@@ -100,16 +105,39 @@ export abstract class AbstractCustomNode <
return '';
}
/**
* @param {string} template
* @param {TInputOptions} options
* @returns {string}
*/
protected obfuscateTemplate (template: string, options: TInputOptions = {}): string {
const reservedNames: string[] = this.getPreservedNames(options.reservedNames);
return JavaScriptObfuscator.obfuscate(
template,
{
...NO_ADDITIONAL_NODES_PRESET,
identifierNamesGenerator: this.options.identifierNamesGenerator,
identifiersDictionary: this.options.identifiersDictionary,
seed: this.randomGenerator.getRawSeed(),
...options,
reservedNames
}
).getObfuscatedCode();
}
/**
* @param {string[]} additionalNames
* @returns {string[]}
*/
protected getPreservedNames (additionalNames: string[]): string[] {
return Array.from(new Set([
...Array.from(this.identifierNamesGenerator.getPreservedNames().values()),
...additionalNames
]).values())
.map((preservedName: string) => `^${preservedName}$`);
private getPreservedNames (additionalNames: string[] = []): string[] {
return Array
.from(new Set([
...Array.from(this.identifierNamesGenerator.getPreservedNames().values()),
...additionalNames
])
.values())
.map((preservedName: string) => `^${preservedName}$`);
}
/**
@@ -4,6 +4,7 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import { TIdentifierNamesGeneratorFactory } from '../../types/container/generators/TIdentifierNamesGeneratorFactory';
import { TStatement } from '../../types/node/TStatement';
import { ICustomNodeFormatter } from '../../interfaces/custom-nodes/ICustomNodeFormatter';
import { IOptions } from '../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
@@ -13,12 +14,8 @@ import { initializable } from '../../decorators/Initializable';
import { SingleNodeCallControllerTemplate } from '../../templates/SingleNodeCallControllerTemplate';
import { NO_ADDITIONAL_NODES_PRESET } from '../../options/presets/NoCustomNodes';
import { AbstractCustomNode } from '../AbstractCustomNode';
import { JavaScriptObfuscator } from '../../JavaScriptObfuscatorFacade';
import { NodeUtils } from '../../node/NodeUtils';
import { ICustomNodeFormatter } from '../../interfaces/custom-nodes/ICustomNodeFormatter';
@injectable()
export class NodeCallsControllerFunctionNode extends AbstractCustomNode {
@@ -72,17 +69,11 @@ export class NodeCallsControllerFunctionNode extends AbstractCustomNode {
*/
protected getNodeTemplate (): string {
if (this.appendEvent === ObfuscationEvent.AfterObfuscation) {
return JavaScriptObfuscator.obfuscate(
return this.obfuscateTemplate(
this.customNodeFormatter.formatTemplate(SingleNodeCallControllerTemplate(), {
singleNodeCallControllerFunctionName: this.callsControllerFunctionName
}),
{
...NO_ADDITIONAL_NODES_PRESET,
identifierNamesGenerator: this.options.identifierNamesGenerator,
identifiersDictionary: this.options.identifiersDictionary,
seed: this.options.seed
}
).getObfuscatedCode();
})
);
}
return this.customNodeFormatter.formatTemplate(SingleNodeCallControllerTemplate(), {
@@ -4,6 +4,7 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import * as ESTree from 'estree';
import { TIdentifierNamesGeneratorFactory } from '../../types/container/generators/TIdentifierNamesGeneratorFactory';
import { TNodeWithLexicalScope } from '../../types/node/TNodeWithLexicalScope';
import { TStatement } from '../../types/node/TStatement';
import { IOptions } from '../../interfaces/options/IOptions';
@@ -15,6 +16,10 @@ import { NodeFactory } from '../../node/NodeFactory';
@injectable()
export class ObjectExpressionVariableDeclarationHostNode extends AbstractCustomNode {
/**
* @type {TNodeWithLexicalScope}
*/
private lexicalScopeNode!: TNodeWithLexicalScope;
/**
* @ type {Property}
*/
@@ -36,7 +41,8 @@ export class ObjectExpressionVariableDeclarationHostNode extends AbstractCustomN
super(identifierNamesGeneratorFactory, customNodeFormatter, randomGenerator, options);
}
public initialize (properties: ESTree.Property[]): void {
public initialize (lexicalScopeNode: TNodeWithLexicalScope, properties: ESTree.Property[]): void {
this.lexicalScopeNode = lexicalScopeNode;
this.properties = properties;
}
@@ -49,7 +55,7 @@ export class ObjectExpressionVariableDeclarationHostNode extends AbstractCustomN
[
NodeFactory.variableDeclaratorNode(
NodeFactory.identifierNode(
this.identifierNamesGenerator.generate()
this.identifierNamesGenerator.generateForLexicalScope(this.lexicalScopeNode)
),
NodeFactory.objectExpressionNode(this.properties)
)
@@ -11,12 +11,9 @@ import { ICustomNodeFormatter } from '../../interfaces/custom-nodes/ICustomNodeF
import { initializable } from '../../decorators/Initializable';
import { NO_ADDITIONAL_NODES_PRESET } from '../../options/presets/NoCustomNodes';
import { SelfDefendingTemplate } from '../../templates/self-defending-nodes/self-defending-unicode-node/SelfDefendingTemplate';
import { AbstractCustomNode } from '../AbstractCustomNode';
import { JavaScriptObfuscator } from '../../JavaScriptObfuscatorFacade';
import { NodeUtils } from '../../node/NodeUtils';
@injectable()
@@ -71,18 +68,14 @@ export class SelfDefendingUnicodeNode extends AbstractCustomNode {
* @returns {string}
*/
protected getNodeTemplate (): string {
return JavaScriptObfuscator.obfuscate(
return this.obfuscateTemplate(
this.customNodeFormatter.formatTemplate(SelfDefendingTemplate(this.escapeSequenceEncoder), {
selfDefendingFunctionName: this.identifierNamesGenerator.generate(),
singleNodeCallControllerFunctionName: this.callsControllerFunctionName
}),
{
...NO_ADDITIONAL_NODES_PRESET,
identifierNamesGenerator: this.options.identifierNamesGenerator,
identifiersDictionary: this.options.identifiersDictionary,
seed: this.options.seed,
unicodeEscapeSequence: true
}
).getObfuscatedCode();
);
}
}
@@ -14,8 +14,6 @@ import { StringArrayEncoding } from '../../enums/StringArrayEncoding';
import { initializable } from '../../decorators/Initializable';
import { NO_ADDITIONAL_NODES_PRESET } from '../../options/presets/NoCustomNodes';
import { AtobTemplate } from '../../templates/AtobTemplate';
import { GlobalVariableNoEvalTemplate } from '../../templates/GlobalVariableNoEvalTemplate';
import { Rc4Template } from '../../templates/Rc4Template';
@@ -25,7 +23,6 @@ import { StringArrayCallsWrapperTemplate } from '../../templates/string-array-no
import { StringArrayRc4DecodeNodeTemplate } from '../../templates/string-array-nodes/string-array-calls-wrapper/StringArrayRC4DecodeNodeTemplate';
import { AbstractCustomNode } from '../AbstractCustomNode';
import { JavaScriptObfuscator } from '../../JavaScriptObfuscatorFacade';
import { NodeUtils } from '../../node/NodeUtils';
@injectable()
@@ -93,24 +90,18 @@ export class StringArrayCallsWrapper extends AbstractCustomNode {
protected getNodeTemplate (): string {
const decodeNodeTemplate: string = this.getDecodeStringArrayTemplate();
const preservedNames: string[] = this.getPreservedNames([this.stringArrayName]);
const preservedNames: string[] = [this.stringArrayName];
return JavaScriptObfuscator.obfuscate(
return this.obfuscateTemplate(
this.customNodeFormatter.formatTemplate(StringArrayCallsWrapperTemplate(), {
decodeNodeTemplate,
stringArrayCallsWrapperName: this.stringArrayCallsWrapperName,
stringArrayName: this.stringArrayName
}),
{
...NO_ADDITIONAL_NODES_PRESET,
identifierNamesGenerator: this.options.identifierNamesGenerator,
identifiersDictionary: this.options.identifiersDictionary,
reservedNames: [
...preservedNames
],
seed: this.randomGenerator.getRawSeed()
reservedNames: preservedNames
}
).getObfuscatedCode();
);
}
/**
@@ -11,13 +11,10 @@ import { ICustomNodeFormatter } from '../../interfaces/custom-nodes/ICustomNodeF
import { initializable } from '../../decorators/Initializable';
import { NO_ADDITIONAL_NODES_PRESET } from '../../options/presets/NoCustomNodes';
import { SelfDefendingTemplate } from '../../templates/string-array-nodes/string-array-rotate-function-node/SelfDefendingTemplate';
import { StringArrayRotateFunctionTemplate } from '../../templates/string-array-nodes/string-array-rotate-function-node/StringArrayRotateFunctionTemplate';
import { AbstractCustomNode } from '../AbstractCustomNode';
import { JavaScriptObfuscator } from '../../JavaScriptObfuscatorFacade';
import { NodeUtils } from '../../node/NodeUtils';
import { NumberUtils } from '../../utils/NumberUtils';
@@ -86,6 +83,7 @@ export class StringArrayRotateFunctionNode extends AbstractCustomNode {
protected getNodeTemplate (): string {
const timesName: string = this.identifierNamesGenerator.generate();
const whileFunctionName: string = this.identifierNamesGenerator.generate();
const preservedNames: string[] = [this.stringArrayName];
let code: string = '';
@@ -98,20 +96,17 @@ export class StringArrayRotateFunctionNode extends AbstractCustomNode {
code = `${whileFunctionName}(++${timesName})`;
}
return JavaScriptObfuscator.obfuscate(
return this.obfuscateTemplate(
this.customNodeFormatter.formatTemplate(StringArrayRotateFunctionTemplate(), {
code,
timesName,
whileFunctionName,
stringArrayName: this.stringArrayName,
stringArrayRotationAmount: NumberUtils.toHex(this.stringArrayRotationAmount),
whileFunctionName
stringArrayRotationAmount: NumberUtils.toHex(this.stringArrayRotationAmount)
}),
{
...NO_ADDITIONAL_NODES_PRESET,
identifierNamesGenerator: this.options.identifierNamesGenerator,
identifiersDictionary: this.options.identifiersDictionary,
seed: this.randomGenerator.getRawSeed()
reservedNames: preservedNames
}
).getObfuscatedCode();
);
}
}
@@ -45,7 +45,14 @@ export abstract class AbstractIdentifierNamesGenerator implements IIdentifierNam
* @returns {Set<string>}
*/
public getPreservedNames (): Set<string> {
return this.preservedNamesSet;
const lexicalScopesPreservedNames: Set<string>[] = Array.from(this.lexicalScopesPreservedNamesMap.values());
const preservedNames: string[] = Array.from(this.preservedNamesSet);
for (const lexicalScopePreservedNames of lexicalScopesPreservedNames) {
preservedNames.push(...lexicalScopePreservedNames);
}
return new Set(preservedNames);
}
/**
@@ -60,8 +67,6 @@ export abstract class AbstractIdentifierNamesGenerator implements IIdentifierNam
* @param {TNodeWithLexicalScope} lexicalScopeNode
*/
public preserveNameForLexicalScope (name: string, lexicalScopeNode: TNodeWithLexicalScope): void {
this.preservedNamesSet.add(name);
const preservedNamesForLexicalScopeSet: Set<string> =
this.lexicalScopesPreservedNamesMap.get(lexicalScopeNode) ?? new Set();
@@ -80,22 +85,28 @@ export abstract class AbstractIdentifierNamesGenerator implements IIdentifierNam
/**
* @param {string} name
* @param {TNodeWithLexicalScope} lexicalScopeNode
* @param {TNodeWithLexicalScope[]} lexicalScopeNodes
* @returns {boolean}
*/
public isValidIdentifierNameInLexicalScope (name: string, lexicalScopeNode: TNodeWithLexicalScope): boolean {
if (!this.notReservedName(name)) {
public isValidIdentifierNameInLexicalScopes (name: string, lexicalScopeNodes: TNodeWithLexicalScope[]): boolean {
if (!this.isValidIdentifierName(name)) {
return false;
}
const preservedNamesForLexicalScopeSet: Set<string> | null =
this.lexicalScopesPreservedNamesMap.get(lexicalScopeNode) ?? null;
for (const lexicalScope of lexicalScopeNodes) {
const preservedNamesForLexicalScopeSet: Set<string> | null =
this.lexicalScopesPreservedNamesMap.get(lexicalScope) ?? null;
if (!preservedNamesForLexicalScopeSet) {
return true;
if (!preservedNamesForLexicalScopeSet) {
continue;
}
if (preservedNamesForLexicalScopeSet.has(name)) {
return false;
}
}
return !preservedNamesForLexicalScopeSet.has(name);
return true;
}
/**
@@ -7,6 +7,7 @@ import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
import { AbstractIdentifierNamesGenerator } from './AbstractIdentifierNamesGenerator';
import { TNodeWithLexicalScope } from '../../types/node/TNodeWithLexicalScope';
import { NodeLexicalScopeUtils } from '../../node/NodeLexicalScopeUtils';
@injectable()
export class DictionaryIdentifierNamesGenerator extends AbstractIdentifierNamesGenerator {
@@ -69,26 +70,11 @@ export class DictionaryIdentifierNamesGenerator extends AbstractIdentifierNamesG
}
public generate (): string {
if (!this.identifierNamesSet.size) {
throw new Error('Too many identifiers in the code, add more words to identifiers dictionary');
}
const identifierName: string = this.generateNewDictionaryName();
const iteratorResult: IteratorResult<string> = this.identifiersIterator.next();
this.preserveName(identifierName);
if (!iteratorResult.done) {
const identifierName: string =iteratorResult.value;
if (!this.isValidIdentifierName(identifierName)) {
return this.generate();
}
return iteratorResult.value;
}
this.identifierNamesSet = new Set(this.getIncrementedIdentifierNames([...this.identifierNamesSet]));
this.identifiersIterator = this.identifierNamesSet.values();
return this.generate();
return identifierName;
}
/**
@@ -96,12 +82,18 @@ export class DictionaryIdentifierNamesGenerator extends AbstractIdentifierNamesG
* @returns {string}
*/
public generateForLexicalScope (lexicalScopeNode: TNodeWithLexicalScope): string {
const identifierName: string = this.generate();
const lexicalScopes: TNodeWithLexicalScope[] = [
lexicalScopeNode,
...NodeLexicalScopeUtils.getLexicalScopes(lexicalScopeNode)
];
const identifierName: string = this.generateNewDictionaryName();
if (!this.isValidIdentifierNameInLexicalScope(identifierName, lexicalScopeNode)) {
if (!this.isValidIdentifierNameInLexicalScopes(identifierName, lexicalScopes)) {
return this.generateForLexicalScope(lexicalScopeNode);
}
this.preserveNameForLexicalScope(identifierName, lexicalScopeNode);
return identifierName;
}
@@ -112,7 +104,7 @@ export class DictionaryIdentifierNamesGenerator extends AbstractIdentifierNamesG
const prefix: string = this.options.identifiersPrefix ?
`${this.options.identifiersPrefix}`
: '';
const identifierName: string = this.generate();
const identifierName: string = this.generateNewDictionaryName();
const identifierNameWithPrefix: string = `${prefix}${identifierName}`;
if (!this.isValidIdentifierName(identifierNameWithPrefix)) {
@@ -124,6 +116,32 @@ export class DictionaryIdentifierNamesGenerator extends AbstractIdentifierNamesG
return identifierNameWithPrefix;
}
/**
* @returns {string}
*/
private generateNewDictionaryName (): string {
if (!this.identifierNamesSet.size) {
throw new Error('Too many identifiers in the code, add more words to identifiers dictionary');
}
const iteratorResult: IteratorResult<string> = this.identifiersIterator.next();
if (!iteratorResult.done) {
const identifierName: string =iteratorResult.value;
if (!this.isValidIdentifierName(identifierName)) {
return this.generateNewDictionaryName();
}
return iteratorResult.value;
}
this.identifierNamesSet = new Set(this.getIncrementedIdentifierNames([...this.identifierNamesSet]));
this.identifiersIterator = this.identifierNamesSet.values();
return this.generateNewDictionaryName();
}
/**
* @param {string[]} identifierNames
* @returns {string[]}
@@ -7,6 +7,7 @@ import { IOptions } from '../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
import { AbstractIdentifierNamesGenerator } from './AbstractIdentifierNamesGenerator';
import { NodeLexicalScopeUtils } from '../../node/NodeLexicalScopeUtils';
@injectable()
export class MangledIdentifierNamesGenerator extends AbstractIdentifierNamesGenerator {
@@ -15,6 +16,11 @@ export class MangledIdentifierNamesGenerator extends AbstractIdentifierNamesGene
*/
private static readonly initMangledNameCharacter: string = '9';
/**
* @type {Map<TNodeWithLexicalScope, string>}
*/
private static readonly lastMangledNameInScopeMap: Map <TNodeWithLexicalScope, string> = new Map();
/**
* @type {string[]}
*/
@@ -56,6 +62,7 @@ export class MangledIdentifierNamesGenerator extends AbstractIdentifierNamesGene
const identifierName: string = this.generateNewMangledName(this.previousMangledName);
this.previousMangledName = identifierName;
this.preserveName(identifierName);
return identifierName;
}
@@ -66,13 +73,22 @@ export class MangledIdentifierNamesGenerator extends AbstractIdentifierNamesGene
* @returns {string}
*/
public generateForLexicalScope (lexicalScopeNode: TNodeWithLexicalScope, nameLength?: number): string {
const identifierName: string = this.generateNewMangledName(this.previousMangledName);
const lexicalScopes: TNodeWithLexicalScope[] = [
lexicalScopeNode,
...NodeLexicalScopeUtils.getLexicalScopes(lexicalScopeNode)
];
if (!this.isValidIdentifierNameInLexicalScope(identifierName, lexicalScopeNode)) {
return this.generateForLexicalScope(lexicalScopeNode, nameLength);
}
const lastMangledNameForScope: string = this.getLastMangledNameForScopes(lexicalScopes);
this.previousMangledName = identifierName;
let identifierName: string = lastMangledNameForScope;
do {
identifierName = this.generateNewMangledName(identifierName);
} while (!this.isValidIdentifierNameInLexicalScopes(identifierName, lexicalScopes));
MangledIdentifierNamesGenerator.lastMangledNameInScopeMap.set(lexicalScopeNode, identifierName);
this.preserveNameForLexicalScope(identifierName, lexicalScopeNode);
return identifierName;
}
@@ -85,9 +101,11 @@ export class MangledIdentifierNamesGenerator extends AbstractIdentifierNamesGene
const prefix: string = this.options.identifiersPrefix ?
`${this.options.identifiersPrefix}`
: '';
const identifierName: string = this.generate(nameLength);
const identifierName: string = this.generateNewMangledName(this.previousMangledName);
const identifierNameWithPrefix: string = `${prefix}${identifierName}`;
this.previousMangledName = identifierName;
if (!this.isValidIdentifierName(identifierNameWithPrefix)) {
return this.generateWithPrefix(nameLength);
}
@@ -150,4 +168,23 @@ export class MangledIdentifierNamesGenerator extends AbstractIdentifierNamesGene
return newMangledName;
}
/**
* @param {TNodeWithLexicalScope[]} lexicalScopeNodes
* @returns {string}
*/
private getLastMangledNameForScopes (lexicalScopeNodes: TNodeWithLexicalScope[]): string {
for (const lexicalScope of lexicalScopeNodes) {
const lastMangledName: string | null = MangledIdentifierNamesGenerator.lastMangledNameInScopeMap
.get(lexicalScope) ?? null;
if (!lastMangledName) {
continue;
}
return lastMangledName;
}
return MangledIdentifierNamesGenerator.initMangledNameCharacter;
}
}
@@ -34,10 +34,10 @@ export interface IIdentifierNamesGenerator {
/**
* @param {string} identifierName
* @param {TNodeWithLexicalScope} lexicalScopeNode
* @param {TNodeWithLexicalScope[]} lexicalScopeNodes
* @returns {boolean}
*/
isValidIdentifierNameInLexicalScope (identifierName: string, lexicalScopeNode: TNodeWithLexicalScope): boolean;
isValidIdentifierNameInLexicalScopes (identifierName: string, lexicalScopeNodes: TNodeWithLexicalScope[]): boolean;
/**
* @param {string} identifierName
@@ -19,6 +19,8 @@ import { NodeAppender } from '../../../node/NodeAppender';
import { NodeGuards } from '../../../node/NodeGuards';
import { NodeStatementUtils } from '../../../node/NodeStatementUtils';
import { NodeUtils } from '../../../node/NodeUtils';
import { TNodeWithLexicalScope } from '../../../types/node/TNodeWithLexicalScope';
import { NodeLexicalScopeUtils } from '../../../node/NodeLexicalScopeUtils';
@injectable()
export class ObjectExpressionToVariableDeclarationExtractor implements IObjectExpressionExtractor {
@@ -74,12 +76,18 @@ export class ObjectExpressionToVariableDeclarationExtractor implements IObjectEx
objectExpressionNode: ESTree.ObjectExpression,
hostStatement: ESTree.Statement
): IObjectExpressionExtractorResult {
const lexicalScopeNode: TNodeWithLexicalScope | null = NodeLexicalScopeUtils.getLexicalScope(hostStatement) ?? null;
if (!lexicalScopeNode) {
throw new Error('Cannot find lexical scope node for the host statement node');
}
const properties: ESTree.Property[] = objectExpressionNode.properties;
const newObjectExpressionHostStatement: ESTree.VariableDeclaration = this.getObjectExpressionHostNode(properties);
const newObjectExpressionIdentifier: ESTree.Identifier = this.getObjectExpressionIdentifierNode(newObjectExpressionHostStatement);
const newObjectExpressionNode: ESTree.ObjectExpression = this.getObjectExpressionNode(newObjectExpressionHostStatement);
const newObjectExpressionHostStatement: ESTree.VariableDeclaration = this.getObjectExpressionHostNode(
lexicalScopeNode,
properties
);
const statementsToInsert: TStatement[] = [newObjectExpressionHostStatement];
const hostNodeWithStatements: TNodeWithStatements = NodeStatementUtils.getScopeOfNode(hostStatement);
@@ -87,6 +95,9 @@ export class ObjectExpressionToVariableDeclarationExtractor implements IObjectEx
NodeUtils.parentizeAst(newObjectExpressionHostStatement);
NodeUtils.parentizeNode(newObjectExpressionHostStatement, hostNodeWithStatements);
const newObjectExpressionIdentifier: ESTree.Identifier = this.getObjectExpressionIdentifierNode(newObjectExpressionHostStatement);
const newObjectExpressionNode: ESTree.ObjectExpression = this.getObjectExpressionNode(newObjectExpressionHostStatement);
return {
nodeToReplace: newObjectExpressionIdentifier,
objectExpressionHostStatement: newObjectExpressionHostStatement,
@@ -95,16 +106,20 @@ export class ObjectExpressionToVariableDeclarationExtractor implements IObjectEx
}
/**
* @param {TNodeWithLexicalScope} lexicalScopeNode
* @param {Property[]} properties
* @returns {VariableDeclaration}
*/
private getObjectExpressionHostNode (properties: ESTree.Property[]): ESTree.VariableDeclaration {
private getObjectExpressionHostNode (
lexicalScopeNode: TNodeWithLexicalScope,
properties: ESTree.Property[]
): ESTree.VariableDeclaration {
const variableDeclarationHostNodeCustomNode: ICustomNode<TInitialData<ObjectExpressionVariableDeclarationHostNode>> =
this.objectExpressionKeysTransformerCustomNodeFactory(
ObjectExpressionKeysTransformerCustomNode.ObjectExpressionVariableDeclarationHostNode
);
variableDeclarationHostNodeCustomNode.initialize(properties);
variableDeclarationHostNodeCustomNode.initialize(lexicalScopeNode, properties);
const statementNode: TStatement = variableDeclarationHostNodeCustomNode.getNode()[0];
@@ -117,15 +117,6 @@ export class VariablePreserveTransformer extends AbstractNodeTransformer {
identifierNode: ESTree.Identifier,
parentNode: ESTree.Node
): void {
if (
!NodeGuards.parentNodeIsPropertyNode(identifierNode, parentNode)
&& !NodeGuards.parentNodeIsMemberExpressionNode(identifierNode, parentNode)
&& !NodeGuards.parentNodeIsMethodDefinitionNode(identifierNode, parentNode)
&& !NodeGuards.isLabelIdentifierNode(identifierNode, parentNode)
) {
return;
}
for (const lexicalScope of this.enteredLexicalScopesStack) {
this.identifierObfuscatingReplacer.preserveNameForLexicalScope(identifierNode, lexicalScope);
}
+10 -8
View File
@@ -7,21 +7,23 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../src/options/presets/NoCustomNo
let obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
`
function foo () {
const testA = 'abc';
const testB = 'abc';
const testC = 'abc';
const testD = 'abc';
function a (a, b) {
}
function b (b, c) {
}
`,
{
...NO_ADDITIONAL_NODES_PRESET,
compact: false,
identifierNamesGenerator: 'dictionary',
identifiersDictionary: ['a', 'b', 'aa'],
identifierNamesGenerator: 'mangled',
identifiersPrefix: 'a',
transformObjectKeys: true,
stringArray: true,
stringArrayThreshold: 1
stringArrayThreshold: 1,
log: true
}
).getObfuscatedCode();
@@ -78,6 +78,7 @@ describe('MangledIdentifierNamesGenerator', () => {
describe('Variant #2: should not generate same prefixed name for identifier in code as prefixed name of string array', () => {
describe('Variant #1: `renameGlobals` option is disabled', () => {
const stringArrayStorageRegExp: RegExp = /const aa *= *\['abc', *'last'];/;
const functionDeclarationIdentifierNameRegExp: RegExp = /function foo *\(\) *{/;
const lastVariableDeclarationIdentifierNameRegExp: RegExp = /const ac *= *ab\('0x1'\);/;
let obfuscatedCode: string;
@@ -98,18 +99,23 @@ describe('MangledIdentifierNamesGenerator', () => {
).getObfuscatedCode();
});
it('Match #1: should generate correct identifier for string array', () => {
it('Match #1: should generate correct identifier name for string array', () => {
assert.match(obfuscatedCode, stringArrayStorageRegExp);
});
it('Match #2: should keep identifier name for last variable declaration', () => {
it('Match #2: should keep identifier name for function declaration', () => {
assert.match(obfuscatedCode, functionDeclarationIdentifierNameRegExp);
});
it('Match #3: should keep identifier name for last variable declaration', () => {
assert.match(obfuscatedCode, lastVariableDeclarationIdentifierNameRegExp);
});
});
describe('Variant #2: `renameGlobals` option is enabled', () => {
const stringArrayStorageRegExp: RegExp = /const aa *= *\['abc', *'last'];/;
const lastVariableDeclarationIdentifierNameRegExp: RegExp = /const ae *= *ab\('0x1'\);/;
const functionDeclarationIdentifierNameRegExp: RegExp = /function ac *\(\) *{/;
const lastVariableDeclarationIdentifierNameRegExp: RegExp = /const ad *= *ab\('0x1'\);/;
let obfuscatedCode: string;
@@ -130,11 +136,15 @@ describe('MangledIdentifierNamesGenerator', () => {
).getObfuscatedCode();
});
it('Match #1: should generate correct identifier for string array', () => {
it('Match #1: should generate correct identifier name for string array', () => {
assert.match(obfuscatedCode, stringArrayStorageRegExp);
});
it('Match #2: should keep identifier name for last variable declaration', () => {
it('Match #2: should generate correct identifier name for function declaration', () => {
assert.match(obfuscatedCode, functionDeclarationIdentifierNameRegExp);
});
it('Match #3: should keep identifier name for last variable declaration', () => {
assert.match(obfuscatedCode, lastVariableDeclarationIdentifierNameRegExp);
});
});
@@ -59,5 +59,7 @@ function foo () {
const test32 = 'abc';
const test33 = 'abc';
const test34 = 'abc';
const test35 = 'last';
const test35 = 'abc';
const test36 = 'abc';
const test38 = 'last';
}
@@ -482,15 +482,15 @@ describe('ScopeIdentifiersTransformer ClassDeclaration identifiers', () => {
});
});
describe('Variant #3: already renamed identifiers shouldn\'t be renamed twice', () => {
const classDeclarationRegExp: RegExp = /class *b *{/;
const variableDeclarationsRegExp: RegExp = /let c, *d, *e, *f;/;
const classReferenceRegExp: RegExp = /new b\(\);/;
describe('Variant #3: preserved identifier names shouldn\'t be used as identifier names', () => {
const classDeclarationRegExp: RegExp = /class *f *{/;
const variableDeclarationsRegExp: RegExp = /let g, *h, *i, *j;/;
const classReferenceRegExp: RegExp = /new f\(\);/;
let obfuscatedCode: string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/prevent-renaming-of-renamed-identifiers.js');
const code: string = readFileAsString(__dirname + '/fixtures/prevent-using-of-preserved-identifiers.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
@@ -501,15 +501,15 @@ describe('ScopeIdentifiersTransformer ClassDeclaration identifiers', () => {
).getObfuscatedCode();
});
it('Match #1: shouldn\'t rename twice class declaration name', () => {
it('Match #1: shouldn\'t use preserved identifier name as class declaration name', () => {
assert.match(obfuscatedCode, classDeclarationRegExp);
});
it('Match #2: should correctly rename variable declarations', () => {
it('Match #2: shouldn\'t use preserved identifier name as variable declarations', () => {
assert.match(obfuscatedCode, variableDeclarationsRegExp);
});
it('Match #3: should correctly rename class reference identifier', () => {
it('Match #3: shouldn\'t use preserved identifier name as class reference identifier', () => {
assert.match(obfuscatedCode, classReferenceRegExp);
});
});
@@ -143,15 +143,15 @@ describe('ScopeIdentifiersTransformer FunctionDeclaration identifiers', () => {
});
});
describe('Variant #5: already renamed identifiers shouldn\'t be renamed twice', () => {
describe('Variant #5: preserved identifier names shouldn\'t be used as identifier names', () => {
describe('Variant #1', () => {
const functionDeclarationRegExp: RegExp = /function *a\(\) *{/;
const variableDeclarationsRegExp: RegExp = /let c, *d, *e, *f;/;
const functionDeclarationRegExp: RegExp = /function *e\(\) *{/;
const variableDeclarationsRegExp: RegExp = /let g, *h, *i, *j;/;
let obfuscatedCode: string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/prevent-renaming-of-renamed-identifiers-1.js');
const code: string = readFileAsString(__dirname + '/fixtures/prevent-using-of-preserved-identifiers-1.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
@@ -162,11 +162,11 @@ describe('ScopeIdentifiersTransformer FunctionDeclaration identifiers', () => {
).getObfuscatedCode();
});
it('Match #1: shouldn\'t rename twice function declaration name', () => {
it('Match #1: shouldn\'t use preserved identifier name as function declaration name', () => {
assert.match(obfuscatedCode, functionDeclarationRegExp);
});
it('Match #2: should correctly rename variable declarations', () => {
it('Match #2: shouldn\'t use preserved identifier name as variable declarations', () => {
assert.match(obfuscatedCode, variableDeclarationsRegExp);
});
});
@@ -454,18 +454,18 @@ describe('ScopeIdentifiersTransformer VariableDeclaration identifiers', () => {
});
});
describe('Variant #13: already renamed identifiers shouldn\'t be renamed twice', () => {
describe('Variant #13: preserved identifier names shouldn\'t be used as identifier names', () => {
describe('Variant #1', () => {
const variableDeclarationRegExp: RegExp = /var b *= *0x1;/;
const functionDeclarationRegExp1: RegExp = /function *c *\(\) *{}/;
const functionDeclarationRegExp2: RegExp = /function *d *\(\) *{}/;
const functionDeclarationRegExp3: RegExp = /function *e *\(\) *{}/;
const functionDeclarationRegExp4: RegExp = /function *f *\(\) *{}/;
const variableDeclarationRegExp: RegExp = /var f *= *0x1;/;
const functionDeclarationRegExp1: RegExp = /function *g *\(\) *{}/;
const functionDeclarationRegExp2: RegExp = /function *h *\(\) *{}/;
const functionDeclarationRegExp3: RegExp = /function *i *\(\) *{}/;
const functionDeclarationRegExp4: RegExp = /function *j *\(\) *{}/;
let obfuscatedCode: string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/prevent-renaming-of-renamed-identifiers-1.js');
const code: string = readFileAsString(__dirname + '/fixtures/prevent-using-of-preserved-identifiers-1.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
@@ -476,23 +476,23 @@ describe('ScopeIdentifiersTransformer VariableDeclaration identifiers', () => {
).getObfuscatedCode();
});
it('Match #1: shouldn\'t rename twice variable declaration name', () => {
it('Match #1: shouldn\'t use preserved identifier name as variable declaration name', () => {
assert.match(obfuscatedCode, variableDeclarationRegExp);
});
it('Match #2: should correctly rename function declaration name', () => {
it('Match #2: shouldn\'t use preserved identifier name as function declaration name', () => {
assert.match(obfuscatedCode, functionDeclarationRegExp1);
});
it('Match #3: should correctly rename function declaration name', () => {
it('Match #3: shouldn\'t use preserved identifier name as function declaration name', () => {
assert.match(obfuscatedCode, functionDeclarationRegExp2);
});
it('Match #4: should correctly rename function declaration name', () => {
it('Match #4: shouldn\'t use preserved identifier name as function declaration name', () => {
assert.match(obfuscatedCode, functionDeclarationRegExp3);
});
it('Match #5: should correctly rename function declaration name', () => {
it('Match #5: shouldn\'t use preserved identifier name as function declaration name', () => {
assert.match(obfuscatedCode, functionDeclarationRegExp4);
});
});
@@ -501,12 +501,12 @@ describe('ScopeIdentifiersTransformer VariableDeclaration identifiers', () => {
const variableDeclarationRegExp1: RegExp = /var b *= *0x1;/;
const variableDeclarationRegExp2: RegExp = /var c;/;
const functionDeclarationRegExp: RegExp = /function *d *\(\) *{/;
const variableDeclarationRegExp3: RegExp = /var e *= *function *\(\) *{}/;
const variableDeclarationRegExp3: RegExp = /var f *= *function *\(\) *{}/;
let obfuscatedCode: string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/prevent-renaming-of-renamed-identifiers-2.js');
const code: string = readFileAsString(__dirname + '/fixtures/prevent-using-of-preserved-identifiers-2.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
@@ -517,19 +517,19 @@ describe('ScopeIdentifiersTransformer VariableDeclaration identifiers', () => {
).getObfuscatedCode();
});
it('Match #1: shouldn\'t rename twice variable declaration name', () => {
it('Match #1: shouldn\'t use preserved identifier name as variable declaration name', () => {
assert.match(obfuscatedCode, variableDeclarationRegExp1);
});
it('Match #2: shouldn\'t rename twice variable declaration name', () => {
it('Match #2: shouldn\'t use preserved identifier name as variable declaration name', () => {
assert.match(obfuscatedCode, variableDeclarationRegExp2);
});
it('Match #3: should correctly rename function declaration name', () => {
it('Match #3: shouldn\'t use preserved identifier name as function declaration name', () => {
assert.match(obfuscatedCode, functionDeclarationRegExp);
});
it('Match #4: should correctly rename variable declaration name', () => {
it('Match #4: shouldn\'t use preserved identifier name as variable declaration name', () => {
assert.match(obfuscatedCode, variableDeclarationRegExp3);
});
});
@@ -98,8 +98,8 @@ describe('VariablePreserveTransformer', () => {
});
describe('Variant #2: `renameGlobals` option is enabled', () => {
const transformObjectKeysNameRegExp: RegExp = /const c *= *{};/;
const identifierNameRegExp: RegExp = /const d *= *c;/;
const transformObjectKeysNameRegExp: RegExp = /const b *= *{};/;
const identifierNameRegExp: RegExp = /const c *= *b;/;
let obfuscatedCode: string;