浏览代码

Merge pull request #1044 from javascript-obfuscator/refactoring-22.01

Timofey Kachalov 3 年之前
父节点
当前提交
52e971f615
共有 24 个文件被更改,包括 330 次插入134 次删除
  1. 2 2
      src/JavaScriptObfuscator.ts
  2. 2 2
      src/analyzers/string-array-storage-analyzer/StringArrayStorageAnalyzer.ts
  3. 4 1
      src/container/modules/storages/StoragesModule.ts
  4. 14 14
      src/custom-nodes/control-flow-flattening-nodes/control-flow-storage-nodes/ControlFlowStorageNode.ts
  5. 2 2
      src/generators/identifier-names-generators/AbstractIdentifierNamesGenerator.ts
  6. 10 4
      src/interfaces/node-transformers/control-flow-transformers/IControlFlowReplacer.ts
  7. 37 0
      src/interfaces/storages/IWeakMapStorage.ts
  8. 2 2
      src/interfaces/storages/string-array-transformers/IStringArrayScopeCallsWrappersDataStorage.ts
  9. 4 0
      src/node-transformers/control-flow-transformers/BlockStatementControlFlowTransformer.ts
  10. 37 34
      src/node-transformers/control-flow-transformers/control-flow-replacers/AbstractControlFlowReplacer.ts
  11. 11 1
      src/node-transformers/control-flow-transformers/control-flow-replacers/BinaryExpressionControlFlowReplacer.ts
  12. 12 3
      src/node-transformers/control-flow-transformers/control-flow-replacers/CallExpressionControlFlowReplacer.ts
  13. 10 1
      src/node-transformers/control-flow-transformers/control-flow-replacers/ExpressionWithOperatorControlFlowReplacer.ts
  14. 12 3
      src/node-transformers/control-flow-transformers/control-flow-replacers/LogicalExpressionControlFlowReplacer.ts
  15. 13 4
      src/node-transformers/control-flow-transformers/control-flow-replacers/StringLiteralControlFlowReplacer.ts
  16. 10 15
      src/node-transformers/dead-code-injection-transformers/DeadCodeInjectionTransformer.ts
  17. 8 16
      src/node-transformers/rename-identifiers-transformers/ScopeIdentifiersTransformer.ts
  18. 14 19
      src/node-transformers/rename-identifiers-transformers/replacer/IdentifierReplacer.ts
  19. 6 8
      src/node/NodeAppender.ts
  20. 9 0
      src/node/NodeLiteralUtils.ts
  21. 103 0
      src/storages/WeakMapStorage.ts
  22. 2 2
      src/storages/string-array-transformers/StringArrayScopeCallsWrappersDataStorage.ts
  23. 3 0
      src/types/node/TNumberLiteralNode.ts
  24. 3 1
      test/functional-tests/node-transformers/preparing-transformers/eval-call-expression-transformer/EvalCallExpressionTransformer.spec.ts

+ 2 - 2
src/JavaScriptObfuscator.ts

@@ -20,14 +20,14 @@ import { CodeTransformer } from './enums/code-transformers/CodeTransformer';
 import { CodeTransformationStage } from './enums/code-transformers/CodeTransformationStage';
 import { LoggingMessage } from './enums/logger/LoggingMessage';
 import { NodeTransformer } from './enums/node-transformers/NodeTransformer';
-import { NodeTransformationStage } from './enums/node-transformers/NodeTransformationStage';
+import { NodeTransformationStage     } from './enums/node-transformers/NodeTransformationStage';
+import { SourceMapSourcesMode } from './enums/source-map/SourceMapSourcesMode';
 
 import { ecmaVersion } from './constants/EcmaVersion';
 
 import { ASTParserFacade } from './ASTParserFacade';
 import { NodeGuards } from './node/NodeGuards';
 import { Utils } from './utils/Utils';
-import { SourceMapSourcesMode } from './enums/source-map/SourceMapSourcesMode';
 
 @injectable()
 export class JavaScriptObfuscator implements IJavaScriptObfuscator {

+ 2 - 2
src/analyzers/string-array-storage-analyzer/StringArrayStorageAnalyzer.ts

@@ -42,9 +42,9 @@ export class StringArrayStorageAnalyzer implements IStringArrayStorageAnalyzer {
     private readonly stringArrayStorage: IStringArrayStorage;
 
     /**
-     * @type {Map<ESTree.Literal, IStringArrayStorageItemData>}
+     * @type {WeakMap<ESTree.Literal, IStringArrayStorageItemData>}
      */
-    private readonly stringArrayStorageData: Map<ESTree.Literal, IStringArrayStorageItemData> = new Map();
+    private readonly stringArrayStorageData: WeakMap<ESTree.Literal, IStringArrayStorageItemData> = new WeakMap();
 
     /**
      * @param {IStringArrayStorage} stringArrayStorage

+ 4 - 1
src/container/modules/storages/StoragesModule.ts

@@ -69,7 +69,10 @@ export const storagesModule: interfaces.ContainerModule = new ContainerModule((b
                 const options: IOptions = context.container
                     .get<IOptions>(ServiceIdentifiers.IOptions);
 
-                const storage: TControlFlowStorage = new constructor(randomGenerator, options);
+                const storage: TControlFlowStorage = new constructor(
+                    randomGenerator,
+                    options
+                );
 
                 storage.initialize();
 

+ 14 - 14
src/custom-nodes/control-flow-flattening-nodes/control-flow-storage-nodes/ControlFlowStorageNode.ts

@@ -17,7 +17,6 @@ import { initializable } from '../../../decorators/Initializable';
 import { AbstractCustomNode } from '../../AbstractCustomNode';
 import { NodeFactory } from '../../../node/NodeFactory';
 import { NodeGuards } from '../../../node/NodeGuards';
-import { NodeUtils } from '../../../node/NodeUtils';
 
 @injectable()
 export class ControlFlowStorageNode extends AbstractCustomNode {
@@ -59,22 +58,25 @@ export class ControlFlowStorageNode extends AbstractCustomNode {
      * @returns {TStatement[]}
      */
     protected getNodeStructure (): TStatement[] {
-        const propertyNodes: ESTree.Property[] = Array
-            .from<[string, ICustomNode]>(this.controlFlowStorage.getStorage())
-            .map(([key, value]: [string, ICustomNode]) => {
-                const node: ESTree.Node = value.getNode()[0];
+        const propertyNodes: ESTree.Property[] = [];
+        const controlFlowStorageMap: Map<string, ICustomNode> = this.controlFlowStorage.getStorage();
 
-                if (!NodeGuards.isExpressionStatementNode(node)) {
-                    throw new Error('Function node for control flow storage object should be passed inside the `ExpressionStatement` node!');
-                }
+        for (const [key, value] of controlFlowStorageMap) {
+            const node: ESTree.Node = value.getNode()[0];
 
-                return NodeFactory.propertyNode(
+            if (!NodeGuards.isExpressionStatementNode(node)) {
+                throw new Error('Function node for control flow storage object should be passed inside the `ExpressionStatement` node!');
+            }
+
+            propertyNodes.push(
+                NodeFactory.propertyNode(
                     NodeFactory.identifierNode(key),
                     node.expression
-                );
-            });
+                )
+            );
+        }
 
-        let structure: ESTree.Node = NodeFactory.variableDeclarationNode(
+        const structure: ESTree.Node = NodeFactory.variableDeclarationNode(
             [
                 NodeFactory.variableDeclaratorNode(
                     NodeFactory.identifierNode(this.controlFlowStorage.getStorageId()),
@@ -84,8 +86,6 @@ export class ControlFlowStorageNode extends AbstractCustomNode {
             'const'
         );
 
-        structure = NodeUtils.parentizeAst(structure);
-
         return [structure];
     }
 }

+ 2 - 2
src/generators/identifier-names-generators/AbstractIdentifierNamesGenerator.ts

@@ -27,9 +27,9 @@ export abstract class AbstractIdentifierNamesGenerator implements IIdentifierNam
     protected readonly preservedNamesSet: Set<string> = new Set();
 
     /**
-     * @type {Map<TNodeWithLexicalScope, Set<string>>}
+     * @type {WeakMap<TNodeWithLexicalScope, Set<string>>}
      */
-    protected readonly lexicalScopesPreservedNamesMap: Map<TNodeWithLexicalScope, Set<string>> = new Map();
+    protected readonly lexicalScopesPreservedNamesMap: WeakMap<TNodeWithLexicalScope, Set<string>> = new WeakMap();
 
     /**
      * @param {IRandomGenerator} randomGenerator

+ 10 - 4
src/interfaces/node-transformers/control-flow-transformers/IControlFlowReplacer.ts

@@ -4,14 +4,20 @@ import { TControlFlowStorage } from '../../../types/storages/TControlFlowStorage
 
 export interface IControlFlowReplacer {
     /**
-     * @param node
-     * @param parentNode
-     * @param controlFlowStorage
-     * @returns ESTree.Node
+     * @param {Node} node
+     * @param {Node} parentNode
+     * @param {TControlFlowStorage} controlFlowStorage
+     * @returns {Node}
      */
     replace (
         node: ESTree.Node,
         parentNode: ESTree.Node,
         controlFlowStorage: TControlFlowStorage
     ): ESTree.Node;
+
+    /**
+     * @param {TControlFlowStorage} controlFlowStorage
+     * @returns {string}
+     */
+    generateStorageKey (controlFlowStorage: TControlFlowStorage): string;
 }

+ 37 - 0
src/interfaces/storages/IWeakMapStorage.ts

@@ -0,0 +1,37 @@
+import { IInitializable } from '../IInitializable';
+
+export interface IWeakMapStorage <K extends object, V> extends IInitializable {
+    /**
+     * @param {K} key
+     * @returns {V | undefined}
+     */
+    get (key: K): V | undefined;
+
+    /**
+     * @param {K} key
+     * @returns {V}
+     */
+    getOrThrow (key: K): V;
+
+    /**
+     * @returns {WeakMap<K, V>}
+     */
+    getStorage (): WeakMap <K, V>;
+
+    /**
+     * @returns string
+     */
+    getStorageId (): string;
+
+    /**
+     * @param {K} key
+     * @returns {boolean}
+     */
+    has (key: K): boolean;
+
+    /**
+     * @param {K} key
+     * @param {V} value
+     */
+    set (key: K, value: V): void;
+}

+ 2 - 2
src/interfaces/storages/string-array-transformers/IStringArrayScopeCallsWrappersDataStorage.ts

@@ -1,10 +1,10 @@
 import { TNodeWithLexicalScopeStatements } from '../../../types/node/TNodeWithLexicalScopeStatements';
 import { TStringArrayScopeCallsWrappersDataByEncoding } from '../../../types/node-transformers/string-array-transformers/TStringArrayScopeCallsWrappersDataByEncoding';
 
-import { IMapStorage } from '../IMapStorage';
+import { IWeakMapStorage } from '../IWeakMapStorage';
 
 // eslint-disable-next-line @typescript-eslint/no-empty-interface
-export interface IStringArrayScopeCallsWrappersDataStorage extends IMapStorage<
+export interface IStringArrayScopeCallsWrappersDataStorage extends IWeakMapStorage<
     TNodeWithLexicalScopeStatements,
     TStringArrayScopeCallsWrappersDataByEncoding
 > {}

+ 4 - 0
src/node-transformers/control-flow-transformers/BlockStatementControlFlowTransformer.ts

@@ -101,6 +101,10 @@ export class BlockStatementControlFlowTransformer extends AbstractNodeTransforme
      * @returns {IVisitor | null}
      */
     public getVisitor (nodeTransformationStage: NodeTransformationStage): IVisitor | null {
+        if (!this.options.controlFlowFlattening) {
+            return null;
+        }
+
         switch (nodeTransformationStage) {
             case NodeTransformationStage.ControlFlowFlattening:
                 return {

+ 37 - 34
src/node-transformers/control-flow-transformers/control-flow-replacers/AbstractControlFlowReplacer.ts

@@ -5,9 +5,11 @@ import * as ESTree from 'estree';
 
 import { TControlFlowCustomNodeFactory } from '../../../types/container/custom-nodes/TControlFlowCustomNodeFactory';
 import { TControlFlowStorage } from '../../../types/storages/TControlFlowStorage';
+import { TIdentifierNamesGeneratorFactory } from '../../../types/container/generators/TIdentifierNamesGeneratorFactory';
 
 import { IControlFlowReplacer } from '../../../interfaces/node-transformers/control-flow-transformers/IControlFlowReplacer';
 import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
+import { IIdentifierNamesGenerator } from '../../../interfaces/generators/identifier-names-generators/IIdentifierNamesGenerator';
 import { IOptions } from '../../../interfaces/options/IOptions';
 import { IRandomGenerator } from '../../../interfaces/utils/IRandomGenerator';
 
@@ -18,6 +20,11 @@ export abstract class AbstractControlFlowReplacer implements IControlFlowReplace
      */
     protected readonly controlFlowCustomNodeFactory: TControlFlowCustomNodeFactory;
 
+    /**
+     * @type {IIdentifierNamesGenerator}
+     */
+    protected readonly identifierNamesGenerator: IIdentifierNamesGenerator;
+
     /**
      * @type {IOptions}
      */
@@ -35,38 +42,39 @@ export abstract class AbstractControlFlowReplacer implements IControlFlowReplace
 
     /**
      * @param {TControlFlowCustomNodeFactory} controlFlowCustomNodeFactory
+     * @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
      * @param {IRandomGenerator} randomGenerator
      * @param {IOptions} options
      */
     public constructor (
         @inject(ServiceIdentifiers.Factory__IControlFlowCustomNode)
             controlFlowCustomNodeFactory: TControlFlowCustomNodeFactory,
+        @inject(ServiceIdentifiers.Factory__IIdentifierNamesGenerator)
+            identifierNamesGeneratorFactory: TIdentifierNamesGeneratorFactory,
         @inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
         this.controlFlowCustomNodeFactory = controlFlowCustomNodeFactory;
+        this.identifierNamesGenerator = identifierNamesGeneratorFactory(options);
         this.randomGenerator = randomGenerator;
         this.options = options;
     }
 
     /**
-     * @param {Map<string, Map<string, string[]>>} identifierDataByControlFlowStorageId
-     * @param {string} controlFlowStorageId
-     * @returns {Map<string, string[]>}
+     * Generates storage key with length of 5 characters to prevent collisions and to guarantee that
+     * these keys will be added to the string array storage
+     *
+     * @param {TControlFlowStorage} controlFlowStorage
+     * @returns {string}
      */
-    protected static getStorageKeysByIdForCurrentStorage (
-        identifierDataByControlFlowStorageId: Map<string, Map<string, string[]>>,
-        controlFlowStorageId: string
-    ): Map<string, string[]> {
-        let storageKeysById: Map<string, string[]>;
-
-        if (identifierDataByControlFlowStorageId.has(controlFlowStorageId)) {
-            storageKeysById = <Map<string, string[]>>identifierDataByControlFlowStorageId.get(controlFlowStorageId);
-        } else {
-            storageKeysById = new Map <string, string[]>();
+    public generateStorageKey (controlFlowStorage: TControlFlowStorage): string {
+        const key: string = this.randomGenerator.getRandomString(5);
+
+        if (controlFlowStorage.has(key)) {
+            return this.generateStorageKey(controlFlowStorage);
         }
 
-        return storageKeysById;
+        return key;
     }
 
     /**
@@ -83,28 +91,18 @@ export abstract class AbstractControlFlowReplacer implements IControlFlowReplace
         usingExistingIdentifierChance: number
     ): string {
         const controlFlowStorageId: string = controlFlowStorage.getStorageId();
-        const storageKeysById: Map<string, string[]> = AbstractControlFlowReplacer
-            .getStorageKeysByIdForCurrentStorage(this.replacerDataByControlFlowStorageId, controlFlowStorageId);
-        const storageKeysForCurrentId: string[] | undefined = storageKeysById.get(replacerId);
-
-        if (
-            this.randomGenerator.getMathRandom() < usingExistingIdentifierChance &&
-            storageKeysForCurrentId &&
-            storageKeysForCurrentId.length
-        ) {
-            return this.randomGenerator.getRandomGenerator().pickone(storageKeysForCurrentId);
-        }
+        const storageKeysById: Map<string, string[]> = this.replacerDataByControlFlowStorageId.get(controlFlowStorageId)
+            ?? new Map <string, string[]>();
+        const storageKeysForCurrentId: string[] | null = storageKeysById.get(replacerId) ?? null;
 
-        const generateStorageKey: (length: number) => string = (length: number) => {
-            const key: string = this.randomGenerator.getRandomString(length);
+        const shouldPickFromStorageKeysById = this.randomGenerator.getMathRandom() < usingExistingIdentifierChance
+            && storageKeysForCurrentId?.length;
 
-            if (controlFlowStorage.getStorage().has(key)) {
-                return generateStorageKey(length);
-            }
+        if (shouldPickFromStorageKeysById) {
+            return this.randomGenerator.getRandomGenerator().pickone(storageKeysForCurrentId);
+        }
 
-            return key;
-        };
-        const storageKey: string = generateStorageKey(5);
+        const storageKey: string = this.generateStorageKey(controlFlowStorage);
 
         storageKeysById.set(replacerId, [storageKey]);
         this.replacerDataByControlFlowStorageId.set(controlFlowStorageId, storageKeysById);
@@ -116,8 +114,13 @@ export abstract class AbstractControlFlowReplacer implements IControlFlowReplace
     /**
      * @param {Node} node
      * @param {Node} parentNode
+     * @param {TNodeWithLexicalScope} controlFlowStorageLexicalScopeNode
      * @param {TControlFlowStorage} controlFlowStorage
      * @returns {Node}
      */
-    public abstract replace (node: ESTree.Node, parentNode: ESTree.Node, controlFlowStorage: TControlFlowStorage): ESTree.Node;
+    public abstract replace (
+        node: ESTree.Node,
+        parentNode: ESTree.Node,
+        controlFlowStorage: TControlFlowStorage
+    ): ESTree.Node;
 }

+ 11 - 1
src/node-transformers/control-flow-transformers/control-flow-replacers/BinaryExpressionControlFlowReplacer.ts

@@ -5,6 +5,7 @@ import * as ESTree from 'estree';
 
 import { TControlFlowCustomNodeFactory } from '../../../types/container/custom-nodes/TControlFlowCustomNodeFactory';
 import { TControlFlowStorage } from '../../../types/storages/TControlFlowStorage';
+import { TIdentifierNamesGeneratorFactory } from '../../../types/container/generators/TIdentifierNamesGeneratorFactory';
 import { TInitialData } from '../../../types/TInitialData';
 
 import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
@@ -25,21 +26,30 @@ export class BinaryExpressionControlFlowReplacer extends ExpressionWithOperatorC
 
     /**
      * @param {TControlFlowCustomNodeFactory} controlFlowCustomNodeFactory
+     * @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
      * @param {IRandomGenerator} randomGenerator
      * @param {IOptions} options
      */
     public constructor (
         @inject(ServiceIdentifiers.Factory__IControlFlowCustomNode)
             controlFlowCustomNodeFactory: TControlFlowCustomNodeFactory,
+        @inject(ServiceIdentifiers.Factory__IIdentifierNamesGenerator)
+            identifierNamesGeneratorFactory: TIdentifierNamesGeneratorFactory,
         @inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
-        super(controlFlowCustomNodeFactory, randomGenerator, options);
+        super(
+            controlFlowCustomNodeFactory,
+            identifierNamesGeneratorFactory,
+            randomGenerator,
+            options
+        );
     }
 
     /**
      * @param {BinaryExpression} binaryExpressionNode
      * @param {Node} parentNode
+     * @param {TNodeWithLexicalScope} controlFlowStorageLexicalScopeNode
      * @param {TControlFlowStorage} controlFlowStorage
      * @returns {Node}
      */

+ 12 - 3
src/node-transformers/control-flow-transformers/control-flow-replacers/CallExpressionControlFlowReplacer.ts

@@ -5,6 +5,7 @@ import * as ESTree from 'estree';
 
 import { TControlFlowCustomNodeFactory } from '../../../types/container/custom-nodes/TControlFlowCustomNodeFactory';
 import { TControlFlowStorage } from '../../../types/storages/TControlFlowStorage';
+import { TIdentifierNamesGeneratorFactory } from '../../../types/container/generators/TIdentifierNamesGeneratorFactory';
 import { TInitialData } from '../../../types/TInitialData';
 import { TStatement } from '../../../types/node/TStatement';
 
@@ -28,23 +29,31 @@ export class CallExpressionControlFlowReplacer extends AbstractControlFlowReplac
 
     /**
      * @param {TControlFlowCustomNodeFactory} controlFlowCustomNodeFactory
+     * @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
      * @param {IRandomGenerator} randomGenerator
      * @param {IOptions} options
      */
     public constructor (
         @inject(ServiceIdentifiers.Factory__IControlFlowCustomNode)
             controlFlowCustomNodeFactory: TControlFlowCustomNodeFactory,
+        @inject(ServiceIdentifiers.Factory__IIdentifierNamesGenerator)
+            identifierNamesGeneratorFactory: TIdentifierNamesGeneratorFactory,
         @inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
-        super(controlFlowCustomNodeFactory, randomGenerator, options);
+        super(
+            controlFlowCustomNodeFactory,
+            identifierNamesGeneratorFactory,
+            randomGenerator,
+            options
+        );
     }
 
     /**
      * @param {CallExpression} callExpressionNode
-     * @param {NodeGuards} parentNode
+     * @param {Node} parentNode
      * @param {TControlFlowStorage} controlFlowStorage
-     * @returns {NodeGuards}
+     * @returns {Node}
      */
     public replace (
         callExpressionNode: ESTree.CallExpression,

+ 10 - 1
src/node-transformers/control-flow-transformers/control-flow-replacers/ExpressionWithOperatorControlFlowReplacer.ts

@@ -4,6 +4,7 @@ import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
 import * as ESTree from 'estree';
 
 import { TControlFlowCustomNodeFactory } from '../../../types/container/custom-nodes/TControlFlowCustomNodeFactory';
+import { TIdentifierNamesGeneratorFactory } from '../../../types/container/generators/TIdentifierNamesGeneratorFactory';
 import { TInitialData } from '../../../types/TInitialData';
 import { TStatement } from '../../../types/node/TStatement';
 
@@ -21,16 +22,24 @@ import { NodeGuards } from '../../../node/NodeGuards';
 export abstract class ExpressionWithOperatorControlFlowReplacer extends AbstractControlFlowReplacer {
     /**
      * @param {TControlFlowCustomNodeFactory} controlFlowCustomNodeFactory
+     * @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
      * @param {IRandomGenerator} randomGenerator
      * @param {IOptions} options
      */
     public constructor (
         @inject(ServiceIdentifiers.Factory__IControlFlowCustomNode)
             controlFlowCustomNodeFactory: TControlFlowCustomNodeFactory,
+        @inject(ServiceIdentifiers.Factory__IIdentifierNamesGenerator)
+            identifierNamesGeneratorFactory: TIdentifierNamesGeneratorFactory,
         @inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
-        super(controlFlowCustomNodeFactory, randomGenerator, options);
+        super(
+            controlFlowCustomNodeFactory,
+            identifierNamesGeneratorFactory,
+            randomGenerator,
+            options
+        );
     }
 
     /**

+ 12 - 3
src/node-transformers/control-flow-transformers/control-flow-replacers/LogicalExpressionControlFlowReplacer.ts

@@ -5,6 +5,7 @@ import * as ESTree from 'estree';
 
 import { TControlFlowCustomNodeFactory } from '../../../types/container/custom-nodes/TControlFlowCustomNodeFactory';
 import { TControlFlowStorage } from '../../../types/storages/TControlFlowStorage';
+import { TIdentifierNamesGeneratorFactory } from '../../../types/container/generators/TIdentifierNamesGeneratorFactory';
 import { TInitialData } from '../../../types/TInitialData';
 
 import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
@@ -27,23 +28,31 @@ export class LogicalExpressionControlFlowReplacer extends ExpressionWithOperator
 
     /**
      * @param {TControlFlowCustomNodeFactory} controlFlowCustomNodeFactory
+     * @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
      * @param {IRandomGenerator} randomGenerator
      * @param {IOptions} options
      */
     public constructor (
         @inject(ServiceIdentifiers.Factory__IControlFlowCustomNode)
             controlFlowCustomNodeFactory: TControlFlowCustomNodeFactory,
+        @inject(ServiceIdentifiers.Factory__IIdentifierNamesGenerator)
+            identifierNamesGeneratorFactory: TIdentifierNamesGeneratorFactory,
         @inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
-        super(controlFlowCustomNodeFactory, randomGenerator, options);
+        super(
+            controlFlowCustomNodeFactory,
+            identifierNamesGeneratorFactory,
+            randomGenerator,
+            options
+        );
     }
 
     /**
      * @param {LogicalExpression} logicalExpressionNode
-     * @param {NodeGuards} parentNode
+     * @param {Node} parentNode
      * @param {TControlFlowStorage} controlFlowStorage
-     * @returns {NodeGuards}
+     * @returns {Node}
      */
     public replace (
         logicalExpressionNode: ESTree.LogicalExpression,

+ 13 - 4
src/node-transformers/control-flow-transformers/control-flow-replacers/StringLiteralControlFlowReplacer.ts

@@ -5,6 +5,7 @@ import * as ESTree from 'estree';
 
 import { TControlFlowCustomNodeFactory } from '../../../types/container/custom-nodes/TControlFlowCustomNodeFactory';
 import { TControlFlowStorage } from '../../../types/storages/TControlFlowStorage';
+import { TIdentifierNamesGeneratorFactory } from '../../../types/container/generators/TIdentifierNamesGeneratorFactory';
 import { TInitialData } from '../../../types/TInitialData';
 import { TStatement } from '../../../types/node/TStatement';
 
@@ -25,27 +26,35 @@ export class StringLiteralControlFlowReplacer extends AbstractControlFlowReplace
     /**
      * @type {number}
      */
-    private static readonly usingExistingIdentifierChance: number = 1;
+    protected static readonly usingExistingIdentifierChance: number = 1;
 
     /**
      * @param {TControlFlowCustomNodeFactory} controlFlowCustomNodeFactory
+     * @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
      * @param {IRandomGenerator} randomGenerator
      * @param {IOptions} options
      */
     public constructor (
         @inject(ServiceIdentifiers.Factory__IControlFlowCustomNode)
             controlFlowCustomNodeFactory: TControlFlowCustomNodeFactory,
+        @inject(ServiceIdentifiers.Factory__IIdentifierNamesGenerator)
+            identifierNamesGeneratorFactory: TIdentifierNamesGeneratorFactory,
         @inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
-        super(controlFlowCustomNodeFactory, randomGenerator, options);
+        super(
+            controlFlowCustomNodeFactory,
+            identifierNamesGeneratorFactory,
+            randomGenerator,
+            options
+        );
     }
 
     /**
      * @param {Literal} literalNode
-     * @param {NodeGuards} parentNode
+     * @param {Node} parentNode
      * @param {TControlFlowStorage} controlFlowStorage
-     * @returns {NodeGuards}
+     * @returns {Node}
      */
     public replace (
         literalNode: ESTree.Literal,

+ 10 - 15
src/node-transformers/dead-code-injection-transformers/DeadCodeInjectionTransformer.ts

@@ -53,16 +53,9 @@ export class DeadCodeInjectionTransformer extends AbstractNodeTransformer {
     ];
 
     /**
-     * @type {NodeTransformer[]}
-     */
-    public override readonly runAfter: NodeTransformer[] = [
-        NodeTransformer.ScopeIdentifiersTransformer
-    ];
-
-    /**
-     * @type {Set <BlockStatement>}
+     * @type {WeakSet <BlockStatement>}
      */
-    private readonly deadCodeInjectionRootAstHostNodeSet: Set <ESTree.BlockStatement> = new Set();
+    private readonly deadCodeInjectionRootAstHostNodeSet: WeakSet <ESTree.BlockStatement> = new WeakSet();
 
     /**
      * @type {ESTree.BlockStatement[]}
@@ -244,11 +237,7 @@ export class DeadCodeInjectionTransformer extends AbstractNodeTransformer {
                     }
                 };
 
-            case NodeTransformationStage.RenameIdentifiers:
-                if (!this.deadCodeInjectionRootAstHostNodeSet.size) {
-                    return null;
-                }
-
+            case NodeTransformationStage.StringArray:
                 return {
                     enter: (
                         node: ESTree.Node,
@@ -351,7 +340,13 @@ export class DeadCodeInjectionTransformer extends AbstractNodeTransformer {
      * @returns {boolean}
      */
     private isDeadCodeInjectionRootAstHostNode (node: ESTree.Node): node is ESTree.BlockStatement {
-        return NodeGuards.isBlockStatementNode(node) && this.deadCodeInjectionRootAstHostNodeSet.has(node);
+        const isDeadCodeInjectionRootAstHostNode = NodeGuards.isBlockStatementNode(node) && this.deadCodeInjectionRootAstHostNodeSet.has(node);
+
+        if (isDeadCodeInjectionRootAstHostNode) {
+            this.deadCodeInjectionRootAstHostNodeSet.delete(node);
+        }
+
+        return isDeadCodeInjectionRootAstHostNode;
     }
 
     /**

+ 8 - 16
src/node-transformers/rename-identifiers-transformers/ScopeIdentifiersTransformer.ts

@@ -31,9 +31,9 @@ export class ScopeIdentifiersTransformer extends AbstractNodeTransformer {
     private readonly identifierReplacer: IIdentifierReplacer;
 
     /**
-     * @type {Map<TNodeWithLexicalScope, boolean>}
+     * @type {WeakMap<TNodeWithLexicalScope, boolean>}
      */
-    private readonly lexicalScopesWithObjectPatternWithoutDeclarationMap: Map<TNodeWithLexicalScope, boolean> = new Map();
+    private readonly lexicalScopesWithObjectPatternWithoutDeclarationMap: WeakMap<TNodeWithLexicalScope, boolean> = new WeakMap();
 
     /**
      * @type {IScopeIdentifiersTraverser}
@@ -362,24 +362,16 @@ export class ScopeIdentifiersTransformer extends AbstractNodeTransformer {
                     const properties: (ESTree.Property | ESTree.RestElement)[] = node.properties;
 
                     for (const property of properties) {
-                        if (!NodeGuards.isPropertyNode(property)) {
-                            continue;
-                        }
-
-                        if (property.computed || !property.shorthand) {
-                            continue;
-                        }
+                        isProhibitedVariableDeclaration = NodeGuards.isPropertyNode(property)
+                            && !property.computed
+                            && property.shorthand
+                            && NodeGuards.isIdentifierNode(property.key)
+                            && identifierNode.name === property.key.name;
 
-                        if (!NodeGuards.isIdentifierNode(property.key)) {
+                        if (!isProhibitedVariableDeclaration) {
                             continue;
                         }
 
-                        if (identifierNode.name !== property.key.name) {
-                            continue;
-                        }
-
-                        isProhibitedVariableDeclaration = true;
-
                         return estraverse.VisitorOption.Break;
                     }
                 }

+ 14 - 19
src/node-transformers/rename-identifiers-transformers/replacer/IdentifierReplacer.ts

@@ -26,9 +26,9 @@ export class IdentifierReplacer implements IIdentifierReplacer {
     private readonly identifierNamesGenerator: IIdentifierNamesGenerator;
 
     /**
-     * @type {Map<TNodeWithLexicalScope, Map<string, string>>}
+     * @type {WeakMap<TNodeWithLexicalScope, Map<string, string>>}
      */
-    private readonly blockScopesMap: Map<TNodeWithLexicalScope, Map<string, string>> = new Map();
+    private readonly blockScopesMap: WeakMap<TNodeWithLexicalScope, Map<string, string>> = new WeakMap();
 
     /**
      * @type {IOptions}
@@ -68,13 +68,10 @@ export class IdentifierReplacer implements IIdentifierReplacer {
 
         const newIdentifierName: string = this.identifierNamesGenerator.generateForGlobalScope();
 
-        if (!this.blockScopesMap.has(lexicalScopeNode)) {
-            this.blockScopesMap.set(lexicalScopeNode, new Map());
-        }
-
-        const namesMap: Map<string, string> = <Map<string, string>>this.blockScopesMap.get(lexicalScopeNode);
+        const namesMap: Map<string, string> = this.blockScopesMap.get(lexicalScopeNode) ?? new Map();
 
         namesMap.set(identifierName, newIdentifierName);
+        this.blockScopesMap.set(lexicalScopeNode, namesMap);
 
         // Have to write all global identifier names to the identifier names cache storage
         if (this.options.identifierNamesCache) {
@@ -97,14 +94,10 @@ export class IdentifierReplacer implements IIdentifierReplacer {
         }
 
         const newIdentifierName: string = this.identifierNamesGenerator.generateForLexicalScope(lexicalScopeNode);
-
-        if (!this.blockScopesMap.has(lexicalScopeNode)) {
-            this.blockScopesMap.set(lexicalScopeNode, new Map());
-        }
-
-        const namesMap: Map<string, string> = <Map<string, string>>this.blockScopesMap.get(lexicalScopeNode);
+        const namesMap: Map<string, string> | null = this.blockScopesMap.get(lexicalScopeNode) ?? new Map();
 
         namesMap.set(identifierName, newIdentifierName);
+        this.blockScopesMap.set(lexicalScopeNode, namesMap);
     }
 
     /**
@@ -113,14 +106,16 @@ export class IdentifierReplacer implements IIdentifierReplacer {
      * @returns {Identifier}
      */
     public replace (identifierNode: ESTree.Identifier, lexicalScopeNode: TNodeWithLexicalScope): ESTree.Identifier {
-        let identifierName: string = identifierNode.name;
+        const namesMap: Map<string, string> | null = this.blockScopesMap.get(lexicalScopeNode) ?? null;
+
+        if (!namesMap) {
+            return identifierNode;
+        }
 
-        if (this.blockScopesMap.has(lexicalScopeNode)) {
-            const namesMap: Map<string, string> = <Map<string, string>>this.blockScopesMap.get(lexicalScopeNode);
+        const identifierName: string | null = namesMap.get(identifierNode.name) ?? null;
 
-            if (namesMap.has(identifierName)) {
-                identifierName = <string>namesMap.get(identifierName);
-            }
+        if (!identifierName) {
+            return identifierNode;
         }
 
         return NodeFactory.identifierNode(identifierName);

+ 6 - 8
src/node/NodeAppender.ts

@@ -15,10 +15,9 @@ export class NodeAppender {
     public static append (nodeWithStatements: TNodeWithStatements, statements: TStatement[]): void {
         statements = NodeAppender.parentizeScopeStatementsBeforeAppend(nodeWithStatements, statements);
 
-        NodeAppender.setScopeStatements(nodeWithStatements, [
-            ...NodeAppender.getScopeStatements(nodeWithStatements),
-            ...statements
-        ]);
+        const updatedStatements: TStatement[] = NodeAppender.getScopeStatements(nodeWithStatements).concat(statements);
+
+        NodeAppender.setScopeStatements(nodeWithStatements, updatedStatements);
     }
 
     /**
@@ -154,10 +153,9 @@ export class NodeAppender {
     public static prepend (nodeWithStatements: TNodeWithStatements, statements: TStatement[]): void {
         statements = NodeAppender.parentizeScopeStatementsBeforeAppend(nodeWithStatements, statements);
 
-        NodeAppender.setScopeStatements(nodeWithStatements, [
-            ...statements,
-            ...NodeAppender.getScopeStatements(nodeWithStatements),
-        ]);
+        const updatedStatements: TStatement[] = statements.concat(NodeAppender.getScopeStatements(nodeWithStatements));
+
+        NodeAppender.setScopeStatements(nodeWithStatements, updatedStatements);
     }
 
     /**

+ 9 - 0
src/node/NodeLiteralUtils.ts

@@ -1,10 +1,19 @@
 import * as ESTree from 'estree';
 
+import { TNumberLiteralNode } from '../types/node/TNumberLiteralNode';
 import { TStringLiteralNode } from '../types/node/TStringLiteralNode';
 
 import { NodeGuards } from './NodeGuards';
 
 export class NodeLiteralUtils {
+    /**
+     * @param {Literal} literalNode
+     * @returns {literalNode is TNumberLiteralNode}
+     */
+    public static isNumberLiteralNode (literalNode: ESTree.Literal): literalNode is TNumberLiteralNode {
+        return typeof literalNode.value === 'number';
+    }
+
     /**
      * @param {Literal} literalNode
      * @returns {literalNode is TStringLiteralNode}

+ 103 - 0
src/storages/WeakMapStorage.ts

@@ -0,0 +1,103 @@
+import { inject, injectable, postConstruct } from 'inversify';
+import { ServiceIdentifiers } from '../container/ServiceIdentifiers';
+
+import { IOptions } from '../interfaces/options/IOptions';
+import { IRandomGenerator } from '../interfaces/utils/IRandomGenerator';
+import { IWeakMapStorage } from '../interfaces/storages/IWeakMapStorage';
+
+import { initializable } from '../decorators/Initializable';
+
+@injectable()
+export abstract class WeakMapStorage <K extends object, V> implements IWeakMapStorage <K, V> {
+    /**
+     * @type {string}
+     */
+    @initializable()
+    protected storageId!: string;
+
+    /**
+     * @type {WeakMap <K, V>}
+     */
+    @initializable()
+    protected storage!: WeakMap <K, V>;
+
+    /**
+     * @type {IOptions}
+     */
+    protected readonly options: IOptions;
+
+    /**
+     * @type {IRandomGenerator}
+     */
+    protected readonly randomGenerator: IRandomGenerator;
+
+    /**
+     * @param {IRandomGenerator} randomGenerator
+     * @param {IOptions} options
+     */
+    public constructor (
+        @inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
+        @inject(ServiceIdentifiers.IOptions) options: IOptions
+    ) {
+        this.randomGenerator = randomGenerator;
+        this.options = options;
+    }
+
+    @postConstruct()
+    public initialize (): void {
+        this.storage = new Map <K, V>();
+        this.storageId = this.randomGenerator.getRandomString(6);
+    }
+
+    /**
+     * @param {K} key
+     * @returns {V | undefined}
+     */
+    public get (key: K): V | undefined {
+        return this.storage.get(key);
+    }
+
+    /**
+     * @param {K} key
+     * @returns {V}
+     */
+    public getOrThrow (key: K): V {
+        const value: V | undefined = this.get(key);
+
+        if (!value) {
+            throw new Error(`No value found in weak map storage with key \`${key}\``);
+        }
+
+        return value;
+    }
+
+    /**
+     * @returns {WeakMap<K, V>}
+     */
+    public getStorage (): WeakMap <K, V> {
+        return this.storage;
+    }
+
+    /**
+     * @returns {string}
+     */
+    public getStorageId (): string {
+        return this.storageId;
+    }
+
+    /**
+     * @param {K} key
+     * @returns {boolean}
+     */
+    public has (key: K): boolean {
+        return this.storage.has(key);
+    }
+
+    /**
+     * @param {K} key
+     * @param {V} value
+     */
+    public set (key: K, value: V): void {
+        this.storage.set(key, value);
+    }
+}

+ 2 - 2
src/storages/string-array-transformers/StringArrayScopeCallsWrappersDataStorage.ts

@@ -8,10 +8,10 @@ import { IOptions } from '../../interfaces/options/IOptions';
 import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
 import { IStringArrayScopeCallsWrappersDataStorage } from '../../interfaces/storages/string-array-transformers/IStringArrayScopeCallsWrappersDataStorage';
 
-import { MapStorage } from '../MapStorage';
+import { WeakMapStorage } from '../WeakMapStorage';
 
 @injectable()
-export class StringArrayScopeCallsWrappersDataStorage extends MapStorage <
+export class StringArrayScopeCallsWrappersDataStorage extends WeakMapStorage <
     TNodeWithLexicalScopeStatements,
     TStringArrayScopeCallsWrappersDataByEncoding
 > implements IStringArrayScopeCallsWrappersDataStorage {

+ 3 - 0
src/types/node/TNumberLiteralNode.ts

@@ -0,0 +1,3 @@
+import * as ESTree from 'estree';
+
+export type TNumberLiteralNode = ESTree.Literal & {value: number};

+ 3 - 1
test/functional-tests/node-transformers/preparing-transformers/eval-call-expression-transformer/EvalCallExpressionTransformer.spec.ts

@@ -326,7 +326,9 @@ describe('EvalCallExpressionTransformer', () => {
             `\\};` +
         ``;
         const controlFlowStorageNodeRegExp: RegExp = new RegExp(controlFlowStorageNodeMatch);
-        const evalExpressionRegExp: RegExp = /eval *\('_0x([a-f0-9]){4,6}\[\\'\w{5}\\']\(_0x([a-f0-9]){4,6}, *_0x([a-f0-9]){4,6}\);'\);/;
+        const evalExpressionRegExp: RegExp = new RegExp(
+            `eval *\\('${variableMatch}\\[\\\\'\\w{5}\\\\']\\(${variableMatch}, *${variableMatch}\\);'\\);`
+        );
 
         let obfuscatedCode: string;