Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
Change Log

v3.2.6
---
* Improved integration between `renameProperties` and `controlFlowFlattening` options. Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1053

v3.2.5
---
* Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1056
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "javascript-obfuscator",
"version": "3.2.5",
"version": "3.2.6",
"description": "JavaScript obfuscator",
"keywords": [
"obfuscator",
Expand Down
10 changes: 9 additions & 1 deletion src/declarations/ESTree.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import * as acorn from 'acorn';
import * as escodegen from '@javascript-obfuscator/escodegen';
import * as eslintScope from 'eslint-scope';
import { BlockStatement } from 'estree';

declare module 'estree' {
/**
Expand All @@ -14,8 +13,13 @@ declare module 'estree' {
ignoredNode?: boolean;
}

export interface IdentifierNodeMetadata extends BaseNodeMetadata {
propertyKeyToRenameNode?: boolean
}

export interface LiteralNodeMetadata extends BaseNodeMetadata {
stringArrayCallLiteralNode?: boolean;
propertyKeyToRenameNode?: boolean
}

/**
Expand All @@ -40,6 +44,10 @@ declare module 'estree' {
scope?: eslintScope.Scope | null;
}

interface Identifier extends BaseNode {
metadata?: IdentifierNodeMetadata;
}

interface BigIntLiteral extends BaseNode {
metadata?: LiteralNodeMetadata;
'x-verbatim-property'?: escodegen.XVerbatimProperty;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,6 @@ export class MangledIdentifierNamesGenerator extends AbstractIdentifierNamesGene
*/
private static readonly initMangledNameCharacter: string = '9';

/**
* @type {WeakMap<TNodeWithLexicalScope, string>}
*/
private static readonly lastMangledNameInScopeMap: WeakMap <TNodeWithLexicalScope, string> = new WeakMap();

/**
* @type {string[]}
*/
Expand All @@ -48,14 +43,19 @@ export class MangledIdentifierNamesGenerator extends AbstractIdentifierNamesGene
private static readonly reservedNamesSet: Set<string> = new Set(reservedIdentifierNames);

/**
* @type {WeakMap<string, string>}
* @type {string}
*/
private readonly lastMangledNameForLabelMap: Map <string, string> = new Map();
private lastMangledName: string = MangledIdentifierNamesGenerator.initMangledNameCharacter;

/**
* @type {string}
* @type {WeakMap<TNodeWithLexicalScope, string>}
*/
private previousMangledName: string = MangledIdentifierNamesGenerator.initMangledNameCharacter;
private readonly lastMangledNameForScopeMap: WeakMap <TNodeWithLexicalScope, string> = new WeakMap();

/**
* @type {WeakMap<string, string>}
*/
private readonly lastMangledNameForLabelMap: Map <string, string> = new Map();

/**
* @type {ISetUtils}
Expand Down Expand Up @@ -85,7 +85,7 @@ export class MangledIdentifierNamesGenerator extends AbstractIdentifierNamesGene
* @returns {string}
*/
public generateNext (nameLength?: number): string {
const identifierName: string = this.generateNewMangledName(this.previousMangledName);
const identifierName: string = this.generateNewMangledName(this.lastMangledName);

this.updatePreviousMangledName(identifierName);
this.preserveName(identifierName);
Expand All @@ -103,7 +103,7 @@ export class MangledIdentifierNamesGenerator extends AbstractIdentifierNamesGene
: '';

const identifierName: string = this.generateNewMangledName(
this.previousMangledName,
this.lastMangledName,
(newIdentifierName: string) => {
const identifierNameWithPrefix: string = `${prefix}${newIdentifierName}`;

Expand Down Expand Up @@ -136,7 +136,7 @@ export class MangledIdentifierNamesGenerator extends AbstractIdentifierNamesGene
this.isValidIdentifierNameInLexicalScopes(newIdentifierName, lexicalScopes)
);

MangledIdentifierNamesGenerator.lastMangledNameInScopeMap.set(lexicalScopeNode, identifierName);
this.lastMangledNameForScopeMap.set(lexicalScopeNode, identifierName);

this.updatePreviousMangledName(identifierName);
this.preserveNameForLexicalScope(identifierName, lexicalScopeNode);
Expand Down Expand Up @@ -216,11 +216,11 @@ export class MangledIdentifierNamesGenerator extends AbstractIdentifierNamesGene
* @param {string} name
*/
protected updatePreviousMangledName (name: string): void {
if (!this.isIncrementedMangledName(name, this.previousMangledName)) {
if (!this.isIncrementedMangledName(name, this.lastMangledName)) {
return;
}

this.previousMangledName = name;
this.lastMangledName = name;
}

/**
Expand Down Expand Up @@ -309,8 +309,7 @@ export class MangledIdentifierNamesGenerator extends AbstractIdentifierNamesGene
*/
private getLastMangledNameForScopes (lexicalScopeNodes: TNodeWithLexicalScope[]): string {
for (const lexicalScope of lexicalScopeNodes) {
const lastMangledName: string | null = MangledIdentifierNamesGenerator.lastMangledNameInScopeMap
.get(lexicalScope) ?? null;
const lastMangledName: string | null = this.lastMangledNameForScopeMap.get(lexicalScope) ?? null;

if (!lastMangledName) {
continue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ export abstract class AbstractControlFlowReplacer implements IControlFlowReplace
protected readonly randomGenerator: IRandomGenerator;

/**
* @type {Map<string, Map<string, string[]>>}
* @type {Map<string, Map<string | number, string[]>>}
*/
protected readonly replacerDataByControlFlowStorageId: Map <string, Map<string, string[]>> = new Map();
protected readonly replacerDataByControlFlowStorageId: Map <string, Map<string | number, string[]>> = new Map();

/**
* @param {TControlFlowCustomNodeFactory} controlFlowCustomNodeFactory
Expand Down Expand Up @@ -80,31 +80,32 @@ export abstract class AbstractControlFlowReplacer implements IControlFlowReplace
/**
* @param {ICustomNode} customNode
* @param {IControlFlowStorage} controlFlowStorage
* @param {string} replacerId
* @param {string | number} replacerId
* @param {number} usingExistingIdentifierChance
* @returns {string}
*/
protected insertCustomNodeToControlFlowStorage (
customNode: ICustomNode,
controlFlowStorage: IControlFlowStorage,
replacerId: string,
replacerId: string | number,
usingExistingIdentifierChance: number
): string {
const controlFlowStorageId: string = controlFlowStorage.getStorageId();
const storageKeysById: Map<string, string[]> = this.replacerDataByControlFlowStorageId.get(controlFlowStorageId)
const storageKeysById: Map<string | number, string[]> = this.replacerDataByControlFlowStorageId.get(controlFlowStorageId)
?? new Map <string, string[]>();
const storageKeysForCurrentId: string[] | null = storageKeysById.get(replacerId) ?? null;
const storageKeysForCurrentId: string[] = storageKeysById.get(replacerId) ?? [];

const shouldPickFromStorageKeysById = this.randomGenerator.getMathRandom() < usingExistingIdentifierChance
&& storageKeysForCurrentId?.length;
&& storageKeysForCurrentId.length;

if (shouldPickFromStorageKeysById) {
return this.randomGenerator.getRandomGenerator().pickone(storageKeysForCurrentId);
}

const storageKey: string = this.generateStorageKey(controlFlowStorage);

storageKeysById.set(replacerId, [storageKey]);
storageKeysForCurrentId.push(storageKey);
storageKeysById.set(replacerId, storageKeysForCurrentId);
this.replacerDataByControlFlowStorageId.set(controlFlowStorageId, storageKeysById);
controlFlowStorage.set(storageKey, customNode);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export class CallExpressionControlFlowReplacer extends AbstractControlFlowReplac
return callExpressionNode;
}

const replacerId: string = String(callExpressionNode.arguments.length);
const replacerId: number = callExpressionNode.arguments.length;
const callExpressionFunctionCustomNode: ICustomNode<TInitialData<CallExpressionFunctionNode>> =
this.controlFlowCustomNodeFactory(ControlFlowCustomNode.CallExpressionFunctionNode);
const expressionArguments: (ESTree.Expression | ESTree.SpreadElement)[] = callExpressionNode.arguments;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export class StringArrayCallControlFlowReplacer extends AbstractControlFlowRepla
return literalNode;
}

const replacerId: string = String(literalNode.value);
const replacerId: string | number = literalNode.value;
const literalCustomNode: ICustomNode<TInitialData<LiteralNode>> =
this.controlFlowCustomNodeFactory(ControlFlowCustomNode.LiteralNode);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export class StringLiteralControlFlowReplacer extends AbstractControlFlowReplace
return literalNode;
}

const replacerId: string = String(literalNode.value);
const replacerId: string = literalNode.value;
const literalCustomNode: ICustomNode<TInitialData<LiteralNode>> =
this.controlFlowCustomNodeFactory(ControlFlowCustomNode.LiteralNode);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { RenamePropertiesMode } from '../../enums/node-transformers/rename-prope
import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
import { NodeGuards } from '../../node/NodeGuards';
import { NodeLiteralUtils } from '../../node/NodeLiteralUtils';
import { NodeUtils } from '../../node/NodeUtils';
import { NodeMetadata } from '../../node/NodeMetadata';

@injectable()
export class RenamePropertiesTransformer extends AbstractNodeTransformer {
Expand Down Expand Up @@ -48,15 +48,15 @@ export class RenamePropertiesTransformer extends AbstractNodeTransformer {
| ESTree.PropertyDefinition
| ESTree.MemberExpression
| ESTree.MethodDefinition
> (
> (
propertyNode: TNode,
propertyKeyNode: ESTree.Expression | ESTree.PrivateIdentifier
): propertyKeyNode is ESTree.Identifier | ESTree.Literal {
if (NodeGuards.isIdentifierNode(propertyKeyNode) && propertyNode.computed) {
return false;
}

return NodeGuards.isIdentifierNode(propertyKeyNode) || NodeGuards.isLiteralNode(propertyKeyNode);
return true;
}

/**
Expand Down Expand Up @@ -96,6 +96,15 @@ export class RenamePropertiesTransformer extends AbstractNodeTransformer {
node: ESTree.Node,
parentNode: ESTree.Node
): void {
if ((NodeGuards.isPropertyNode(parentNode) && parentNode.key === node)
|| NodeGuards.isMemberExpressionNode(parentNode) && parentNode.property === node
|| NodeGuards.isMethodDefinitionNode(parentNode) && parentNode.key === node
|| NodeGuards.isPropertyDefinitionNode(parentNode) && parentNode.key === node) {
NodeMetadata.set(node, {propertyKeyToRenameNode: true});

return;
}

if (this.options.renamePropertiesMode === RenamePropertiesMode.Safe) {
this.analyzeAutoExcludedPropertyNames(node, parentNode);
}
Expand All @@ -107,87 +116,35 @@ export class RenamePropertiesTransformer extends AbstractNodeTransformer {
* @returns {Node}
*/
public transformNode (node: ESTree.Node, parentNode: ESTree.Node): ESTree.Node {
let propertyNode: ESTree.Node | null = null;

if (NodeGuards.isPropertyNode(node)) {
propertyNode = this.transformPropertyNode(node);
} else if (NodeGuards.isPropertyDefinitionNode(node)) {
propertyNode = this.transformPropertyDefinitionNode(node);
} else if (NodeGuards.isMemberExpressionNode(node)) {
propertyNode = this.transformMemberExpressionNode(node);
} else if (NodeGuards.isMethodDefinitionNode(node)) {
propertyNode = this.transformMethodDefinitionNode(node);
}

if (propertyNode) {
NodeUtils.parentizeNode(propertyNode, parentNode);
if (!NodeGuards.isIdentifierNode(node) && !NodeGuards.isLiteralNode(node)) {
return node;
}

return node;
}

/**
* @param {Property} propertyNode
* @returns {Property}
*/
private transformPropertyNode (propertyNode: ESTree.Property): ESTree.Property {
const propertyKeyNode: ESTree.Expression | ESTree.PrivateIdentifier = propertyNode.key;

if (RenamePropertiesTransformer.isValidPropertyNode(propertyNode, propertyKeyNode)) {
propertyNode.key = this.renamePropertiesReplacer.replace(propertyKeyNode);
propertyNode.shorthand = false;
}

return propertyNode;
}

/**
* @param {PropertyDefinition} propertyNode
* @returns {PropertyDefinition}
*/
private transformPropertyDefinitionNode (propertyNode: ESTree.PropertyDefinition): ESTree.PropertyDefinition {
const propertyKeyNode: ESTree.Expression | ESTree.PrivateIdentifier = propertyNode.key;

if (RenamePropertiesTransformer.isValidPropertyNode(propertyNode, propertyKeyNode)) {
propertyNode.key = this.renamePropertiesReplacer.replace(propertyKeyNode);
if (!NodeMetadata.isPropertyKeyToRenameNode(node)) {
return node;
}

return propertyNode;
}
const isPropertyNode = NodeGuards.isPropertyNode(parentNode);
const isPropertyLikeNode = isPropertyNode
|| NodeGuards.isPropertyDefinitionNode(parentNode)
|| NodeGuards.isMemberExpressionNode(parentNode)
|| NodeGuards.isMethodDefinitionNode(parentNode);

/**
* @param {Property} memberExpressionNode
* @returns {Property}
*/
private transformMemberExpressionNode (memberExpressionNode: ESTree.MemberExpression): ESTree.MemberExpression {
const propertyKeyNode: ESTree.Expression | ESTree.PrivateIdentifier = memberExpressionNode.property;

if (RenamePropertiesTransformer.isValidPropertyNode(memberExpressionNode, propertyKeyNode)) {
memberExpressionNode.property = this.renamePropertiesReplacer.replace(propertyKeyNode);
if (isPropertyLikeNode && !RenamePropertiesTransformer.isValidPropertyNode(parentNode, node)) {
return node;
}

return memberExpressionNode;
}

/**
* @param {MethodDefinition} methodDefinitionNode
* @returns {MethodDefinition}
*/
private transformMethodDefinitionNode (methodDefinitionNode: ESTree.MethodDefinition): ESTree.MethodDefinition {
const propertyKeyNode: ESTree.Expression | ESTree.PrivateIdentifier = methodDefinitionNode.key;

if (RenamePropertiesTransformer.isValidPropertyNode(methodDefinitionNode, propertyKeyNode)) {
methodDefinitionNode.key = this.renamePropertiesReplacer.replace(propertyKeyNode);
if (isPropertyNode) {
parentNode.shorthand = false;
}

return methodDefinitionNode;
return this.renamePropertiesReplacer.replace(node);
}

/**
* @param {Node} node
* @param {Node} parentNode
*/
// eslint-disable-next-line complexity
private analyzeAutoExcludedPropertyNames (
node: ESTree.Node,
parentNode: ESTree.Node
Expand All @@ -196,15 +153,6 @@ export class RenamePropertiesTransformer extends AbstractNodeTransformer {
return;
}

if (
(NodeGuards.isPropertyNode(parentNode) && parentNode.key === node)
|| NodeGuards.isMemberExpressionNode(parentNode) && parentNode.property === node
|| NodeGuards.isMethodDefinitionNode(parentNode) && parentNode.key === node
|| NodeGuards.isPropertyDefinitionNode(parentNode) && parentNode.key === node
) {
return;
}

this.renamePropertiesReplacer.excludePropertyName(node.value);
}
}
11 changes: 11 additions & 0 deletions src/node/NodeMetadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,17 @@ export class NodeMetadata {
return NodeMetadata.get<ESTree.BaseNodeMetadata, 'ignoredNode'>(node, 'ignoredNode') === true;
}

/**
* @param {Identifier | Literal} node
* @returns {boolean}
*/
public static isPropertyKeyToRenameNode (node: ESTree.Identifier | ESTree.Literal): boolean {
return NodeMetadata.get<ESTree.IdentifierNodeMetadata | ESTree.LiteralNodeMetadata, 'propertyKeyToRenameNode'>(
node,
'propertyKeyToRenameNode'
) === true;
}

/**
* @param {Node} literalNode
* @returns {boolean}
Expand Down
Loading