Sfoglia il codice sorgente

Improved rename of `deadCodeInjection` dead code identifiers. Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/708

sanex 4 anni fa
parent
commit
0f2f0c2c34

+ 4 - 0
CHANGELOG.md

@@ -1,5 +1,9 @@
 Change Log
 
+v1.11.0
+---
+* Improved rename of `deadCodeInjection` dead code identifiers. Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/708
+
 v1.10.2
 ---
 * Fixed obfuscation of literals of `ExportNamedDeclaration` and `ExportAllDeclaration` nodes

File diff suppressed because it is too large
+ 0 - 0
dist/index.browser.js


File diff suppressed because it is too large
+ 0 - 0
dist/index.cli.js


File diff suppressed because it is too large
+ 0 - 0
dist/index.js


+ 7 - 7
package.json

@@ -1,6 +1,6 @@
 {
   "name": "javascript-obfuscator",
-  "version": "1.10.2",
+  "version": "1.11.0",
   "description": "JavaScript obfuscator",
   "keywords": [
     "obfuscator",
@@ -55,25 +55,25 @@
     "@types/estree": "0.0.44",
     "@types/md5": "2.2.0",
     "@types/mkdirp": "1.0.1",
-    "@types/mocha": "8.0.2",
+    "@types/mocha": "8.0.3",
     "@types/multimatch": "4.0.0",
-    "@types/node": "14.0.27",
+    "@types/node": "14.6.0",
     "@types/rimraf": "3.0.0",
     "@types/sinon": "9.0.4",
     "@types/string-template": "1.0.2",
     "@types/webpack-env": "1.15.2",
-    "@typescript-eslint/eslint-plugin": "3.9.0",
-    "@typescript-eslint/parser": "3.9.0",
+    "@typescript-eslint/eslint-plugin": "3.9.1",
+    "@typescript-eslint/parser": "3.9.1",
     "chai": "4.2.0",
     "coveralls": "3.1.0",
     "eslint": "7.7.0",
     "eslint-plugin-import": "2.22.0",
-    "eslint-plugin-jsdoc": "30.2.3",
+    "eslint-plugin-jsdoc": "30.2.4",
     "eslint-plugin-no-null": "1.0.2",
     "eslint-plugin-prefer-arrow": "1.2.2",
     "eslint-plugin-unicorn": "21.0.0",
     "fork-ts-checker-notifier-webpack-plugin": "3.0.0",
-    "fork-ts-checker-webpack-plugin": "5.0.14",
+    "fork-ts-checker-webpack-plugin": "5.1.0",
     "mocha": "8.1.1",
     "nyc": "15.1.0",
     "pjson": "1.0.9",

+ 2 - 0
src/container/InversifyContainerFacade.ts

@@ -7,6 +7,7 @@ import { controlFlowTransformersModule } from './modules/node-transformers/Contr
 import { convertingTransformersModule } from './modules/node-transformers/ConvertingTransformersModule';
 import { customCodeHelpersModule } from './modules/custom-code-helpers/CustomCodeHelpersModule';
 import { customNodesModule } from './modules/custom-nodes/CustomNodesModule';
+import { deadCodeInjectionTransformersModule } from './modules/node-transformers/DeadCodeInjectionTransformersModule';
 import { finalizingTransformersModule } from './modules/node-transformers/FinalizingTransformersModule';
 import { generatorsModule } from './modules/generators/GeneratorsModule';
 import { initializingTransformersModule } from './modules/node-transformers/InitializingTransformersModule';
@@ -209,6 +210,7 @@ export class InversifyContainerFacade implements IInversifyContainerFacade {
         this.container.load(convertingTransformersModule);
         this.container.load(customCodeHelpersModule);
         this.container.load(customNodesModule);
+        this.container.load(deadCodeInjectionTransformersModule);
         this.container.load(finalizingTransformersModule);
         this.container.load(generatorsModule);
         this.container.load(initializingTransformersModule);

+ 0 - 5
src/container/modules/node-transformers/ControlFlowTransformersModule.ts

@@ -11,7 +11,6 @@ import { NodeTransformer } from '../../../enums/node-transformers/NodeTransforme
 import { BinaryExpressionControlFlowReplacer } from '../../../node-transformers/control-flow-transformers/control-flow-replacers/BinaryExpressionControlFlowReplacer';
 import { BlockStatementControlFlowTransformer } from '../../../node-transformers/control-flow-transformers/BlockStatementControlFlowTransformer';
 import { CallExpressionControlFlowReplacer } from '../../../node-transformers/control-flow-transformers/control-flow-replacers/CallExpressionControlFlowReplacer';
-import { DeadCodeInjectionTransformer } from '../../../node-transformers/dead-code-injection-transformers/DeadCodeInjectionTransformer';
 import { FunctionControlFlowTransformer } from '../../../node-transformers/control-flow-transformers/FunctionControlFlowTransformer';
 import { LogicalExpressionControlFlowReplacer } from '../../../node-transformers/control-flow-transformers/control-flow-replacers/LogicalExpressionControlFlowReplacer';
 import { StringLiteralControlFlowReplacer } from '../../../node-transformers/control-flow-transformers/control-flow-replacers/StringLiteralControlFlowReplacer';
@@ -22,10 +21,6 @@ export const controlFlowTransformersModule: interfaces.ContainerModule = new Con
         .to(BlockStatementControlFlowTransformer)
         .whenTargetNamed(NodeTransformer.BlockStatementControlFlowTransformer);
 
-    bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
-        .to(DeadCodeInjectionTransformer)
-        .whenTargetNamed(NodeTransformer.DeadCodeInjectionTransformer);
-
     bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
         .to(FunctionControlFlowTransformer)
         .whenTargetNamed(NodeTransformer.FunctionControlFlowTransformer);

+ 20 - 0
src/container/modules/node-transformers/DeadCodeInjectionTransformersModule.ts

@@ -0,0 +1,20 @@
+import { ContainerModule, interfaces } from 'inversify';
+import { ServiceIdentifiers } from '../../ServiceIdentifiers';
+
+import { INodeTransformer } from '../../../interfaces/node-transformers/INodeTransformer';
+
+import { NodeTransformer } from '../../../enums/node-transformers/NodeTransformer';
+
+import { DeadCodeInjectionTransformer } from '../../../node-transformers/dead-code-injection-transformers/DeadCodeInjectionTransformer';
+import { ScopeThroughIdentifiersTransformer } from '../../../node-transformers/dead-code-injection-transformers/ScopeThroughIdentifiersTransformer';
+
+export const deadCodeInjectionTransformersModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
+    // dead code injection
+    bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
+        .to(DeadCodeInjectionTransformer)
+        .whenTargetNamed(NodeTransformer.DeadCodeInjectionTransformer);
+
+    bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
+        .to(ScopeThroughIdentifiersTransformer)
+        .whenTargetNamed(NodeTransformer.ScopeThroughIdentifiersTransformer);
+});

+ 1 - 0
src/enums/node-transformers/NodeTransformer.ts

@@ -21,6 +21,7 @@ export enum NodeTransformer {
     ParentificationTransformer = 'ParentificationTransformer',
     RenamePropertiesTransformer = 'RenamePropertiesTransformer',
     ScopeIdentifiersTransformer = 'ScopeIdentifiersTransformer',
+    ScopeThroughIdentifiersTransformer = 'ScopeThroughIdentifiersTransformer',
     SplitStringTransformer = 'SplitStringTransformer',
     TemplateLiteralTransformer = 'TemplateLiteralTransformer',
     VariableDeclarationsMergeTransformer = 'VariableDeclarationsMergeTransformer',

+ 17 - 4
src/interfaces/node/IScopeIdentifiersTraverser.ts

@@ -1,17 +1,30 @@
 import * as ESTree from 'estree';
 
-import { TScopeIdentifiersTraverserVariableCallback } from '../../types/node/TScopeIdentifiersTraverserVariableCallback';
+import { TScopeIdentifiersTraverserCallback } from '../../types/node/TScopeIdentifiersTraverserCallback';
+import { IScopeIdentifiersTraverserCallbackData } from './IScopeIdentifiersTraverserCallbackData';
+import { IScopeThroughIdentifiersTraverserCallbackData } from './IScopeThroughIdentifiersTraverserCallbackData';
 
 export interface IScopeIdentifiersTraverser {
     /**
      * @param {Program} programNode
      * @param {Node | null} parentNode
-     * @param {TScopeIdentifiersTraverserVariableCallback} callback
+     * @param {TScopeIdentifiersTraverserCallback<IScopeIdentifiersTraverserCallbackData>} callback
      */
-    traverseScopeVariables (
+    traverseScopeIdentifiers (
         programNode: ESTree.Program,
         parentNode: ESTree.Node | null,
-        callback: TScopeIdentifiersTraverserVariableCallback
+        callback: TScopeIdentifiersTraverserCallback<IScopeIdentifiersTraverserCallbackData>
+    ): void;
+
+    /**
+     * @param {Node} node
+     * @param {Node | null} parentNode
+     * @param {TScopeIdentifiersTraverserCallback<IScopeThroughIdentifiersTraverserCallbackData>} callback
+     */
+    traverseScopeThroughIdentifiers (
+        node: ESTree.Node,
+        parentNode: ESTree.Node | null,
+        callback: TScopeIdentifiersTraverserCallback<IScopeThroughIdentifiersTraverserCallbackData>
     ): void;
 
 }

+ 1 - 1
src/interfaces/node/IScopeIdentifiersTraverserVariableCallbackData.ts → src/interfaces/node/IScopeIdentifiersTraverserCallbackData.ts

@@ -2,7 +2,7 @@ import * as eslintScope from 'eslint-scope';
 
 import { TNodeWithLexicalScope } from '../../types/node/TNodeWithLexicalScope';
 
-export interface IScopeIdentifiersTraverserVariableCallbackData {
+export interface IScopeIdentifiersTraverserCallbackData {
     isGlobalDeclaration: boolean;
     isBubblingDeclaration: boolean;
     rootScope: eslintScope.Scope;

+ 8 - 0
src/interfaces/node/IScopeThroughIdentifiersTraverserCallbackData.ts

@@ -0,0 +1,8 @@
+import * as eslintScope from 'eslint-scope';
+
+import { TNodeWithLexicalScope } from '../../types/node/TNodeWithLexicalScope';
+
+export interface IScopeThroughIdentifiersTraverserCallbackData {
+    reference: eslintScope.Reference;
+    variableLexicalScopeNode: TNodeWithLexicalScope;
+}

+ 8 - 1
src/node-transformers/dead-code-injection-transformers/DeadCodeInjectionTransformer.ts

@@ -48,7 +48,8 @@ export class DeadCodeInjectionTransformer extends AbstractNodeTransformer {
      */
     private static readonly transformersToRenameBlockScopeIdentifiers: NodeTransformer[] = [
         NodeTransformer.LabeledStatementTransformer,
-        NodeTransformer.ScopeIdentifiersTransformer
+        NodeTransformer.ScopeIdentifiersTransformer,
+        NodeTransformer.ScopeThroughIdentifiersTransformer
     ];
 
     /**
@@ -362,6 +363,12 @@ export class DeadCodeInjectionTransformer extends AbstractNodeTransformer {
         NodeUtils.parentizeAst(hostNode);
         NodeUtils.parentizeNode(hostNode, hostNode);
 
+        this.transformersRunner.transform(
+            hostNode,
+            DeadCodeInjectionTransformer.transformersToRenameBlockScopeIdentifiers,
+            NodeTransformationStage.DeadCodeInjection
+        );
+
         this.transformersRunner.transform(
             hostNode,
             DeadCodeInjectionTransformer.transformersToRenameBlockScopeIdentifiers,

+ 146 - 0
src/node-transformers/dead-code-injection-transformers/ScopeThroughIdentifiersTransformer.ts

@@ -0,0 +1,146 @@
+import { inject, injectable, } from 'inversify';
+import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
+
+import * as eslintScope from 'eslint-scope';
+import * as ESTree from 'estree';
+
+import { TIdentifierObfuscatingReplacerFactory } from '../../types/container/node-transformers/TIdentifierObfuscatingReplacerFactory';
+import { TNodeWithLexicalScope } from '../../types/node/TNodeWithLexicalScope';
+
+import { IIdentifierObfuscatingReplacer } from '../../interfaces/node-transformers/obfuscating-transformers/obfuscating-replacers/IIdentifierObfuscatingReplacer';
+import { IOptions } from '../../interfaces/options/IOptions';
+import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
+import { IScopeIdentifiersTraverser } from '../../interfaces/node/IScopeIdentifiersTraverser';
+import { IScopeThroughIdentifiersTraverserCallbackData } from '../../interfaces/node/IScopeThroughIdentifiersTraverserCallbackData';
+import { IVisitor } from '../../interfaces/node-transformers/IVisitor';
+
+import { IdentifierObfuscatingReplacer } from '../../enums/node-transformers/obfuscating-transformers/obfuscating-replacers/IdentifierObfuscatingReplacer';
+import { NodeTransformationStage } from '../../enums/node-transformers/NodeTransformationStage';
+
+import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
+import { NodeGuards } from '../../node/NodeGuards';
+
+/**
+ * Renames all through identifiers for Dead Code Injection
+ */
+@injectable()
+export class ScopeThroughIdentifiersTransformer extends AbstractNodeTransformer {
+    /**
+     * @type {IIdentifierObfuscatingReplacer}
+     */
+    private readonly identifierObfuscatingReplacer: IIdentifierObfuscatingReplacer;
+
+    /**
+     * @type {IScopeIdentifiersTraverser}
+     */
+    private readonly scopeIdentifiersTraverser: IScopeIdentifiersTraverser;
+
+    /**
+     * @param {TIdentifierObfuscatingReplacerFactory} identifierObfuscatingReplacerFactory
+     * @param {IRandomGenerator} randomGenerator
+     * @param {IOptions} options
+     * @param {IScopeIdentifiersTraverser} scopeIdentifiersTraverser
+     */
+    public constructor (
+        @inject(ServiceIdentifiers.Factory__IIdentifierObfuscatingReplacer)
+            identifierObfuscatingReplacerFactory: TIdentifierObfuscatingReplacerFactory,
+        @inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
+        @inject(ServiceIdentifiers.IOptions) options: IOptions,
+        @inject(ServiceIdentifiers.IScopeIdentifiersTraverser) scopeIdentifiersTraverser: IScopeIdentifiersTraverser
+    ) {
+        super(randomGenerator, options);
+
+        this.identifierObfuscatingReplacer = identifierObfuscatingReplacerFactory(
+            IdentifierObfuscatingReplacer.BaseIdentifierObfuscatingReplacer
+        );
+        this.scopeIdentifiersTraverser = scopeIdentifiersTraverser;
+    }
+
+    /**
+     * @param {NodeTransformationStage} nodeTransformationStage
+     * @returns {IVisitor | null}
+     */
+    public getVisitor (nodeTransformationStage: NodeTransformationStage): IVisitor | null {
+        switch (nodeTransformationStage) {
+            case NodeTransformationStage.DeadCodeInjection:
+                return {
+                    enter: (node: ESTree.Node, parentNode: ESTree.Node | null): ESTree.Node | undefined => {
+                        if (parentNode && NodeGuards.isProgramNode(node)) {
+                            return this.transformNode(node, parentNode);
+                        }
+                    }
+                };
+
+            default:
+                return null;
+        }
+    }
+
+    /**
+     * @param {VariableDeclaration} programNode
+     * @param {NodeGuards} parentNode
+     * @returns {NodeGuards}
+     */
+    public transformNode (programNode: ESTree.Program, parentNode: ESTree.Node): ESTree.Node {
+        this.scopeIdentifiersTraverser.traverseScopeThroughIdentifiers(
+            programNode,
+            parentNode,
+            (data: IScopeThroughIdentifiersTraverserCallbackData) => {
+                const {
+                    reference,
+                    variableLexicalScopeNode
+                } = data;
+
+                this.transformScopeThroughIdentifiers(reference, variableLexicalScopeNode);
+            }
+        );
+
+        return programNode;
+    }
+
+    /**
+     * @param {Reference} reference
+     * @param {TNodeWithLexicalScope} lexicalScopeNode
+     */
+    private transformScopeThroughIdentifiers (
+        reference: eslintScope.Reference,
+        lexicalScopeNode: TNodeWithLexicalScope,
+    ): void {
+        if (reference.resolved) {
+            return;
+        }
+
+        const identifier: ESTree.Identifier = reference.identifier;
+
+        this.storeIdentifierName(identifier, lexicalScopeNode);
+        this.replaceIdentifierName(identifier, lexicalScopeNode, reference);
+    }
+
+    /**
+     * @param {Identifier} identifierNode
+     * @param {TNodeWithLexicalScope} lexicalScopeNode
+     */
+    private storeIdentifierName (
+        identifierNode: ESTree.Identifier,
+        lexicalScopeNode: TNodeWithLexicalScope
+    ): void {
+        this.identifierObfuscatingReplacer.storeLocalName(identifierNode, lexicalScopeNode);
+    }
+
+    /**
+     * @param {Identifier} identifierNode
+     * @param {TNodeWithLexicalScope} lexicalScopeNode
+     * @param {Variable} reference
+     */
+    private replaceIdentifierName (
+        identifierNode: ESTree.Identifier,
+        lexicalScopeNode: TNodeWithLexicalScope,
+        reference: eslintScope.Reference
+    ): void {
+        const newIdentifier: ESTree.Identifier = this.identifierObfuscatingReplacer
+            .replace(identifierNode, lexicalScopeNode);
+
+        // rename of identifier
+        reference.identifier.name = newIdentifier.name;
+    }
+}

+ 3 - 3
src/node-transformers/obfuscating-transformers/ScopeIdentifiersTransformer.ts

@@ -12,7 +12,7 @@ import { IIdentifierObfuscatingReplacer } from '../../interfaces/node-transforme
 import { IOptions } from '../../interfaces/options/IOptions';
 import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
 import { IScopeIdentifiersTraverser } from '../../interfaces/node/IScopeIdentifiersTraverser';
-import { IScopeIdentifiersTraverserVariableCallbackData } from '../../interfaces/node/IScopeIdentifiersTraverserVariableCallbackData';
+import { IScopeIdentifiersTraverserCallbackData } from '../../interfaces/node/IScopeIdentifiersTraverserCallbackData';
 import { IVisitor } from '../../interfaces/node-transformers/IVisitor';
 
 import { IdentifierObfuscatingReplacer } from '../../enums/node-transformers/obfuscating-transformers/obfuscating-replacers/IdentifierObfuscatingReplacer';
@@ -89,10 +89,10 @@ export class ScopeIdentifiersTransformer extends AbstractNodeTransformer {
      * @returns {NodeGuards}
      */
     public transformNode (programNode: ESTree.Program, parentNode: ESTree.Node): ESTree.Node {
-        this.scopeIdentifiersTraverser.traverseScopeVariables(
+        this.scopeIdentifiersTraverser.traverseScopeIdentifiers(
             programNode,
             parentNode,
-            (data: IScopeIdentifiersTraverserVariableCallbackData) => {
+            (data: IScopeIdentifiersTraverserCallbackData) => {
                 const {
                     isGlobalDeclaration,
                     variable,

+ 4 - 4
src/node-transformers/preparing-transformers/VariablePreserveTransformer.ts

@@ -9,7 +9,7 @@ import { IIdentifierObfuscatingReplacer } from '../../interfaces/node-transforme
 import { IOptions } from '../../interfaces/options/IOptions';
 import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
 import { IScopeIdentifiersTraverser } from '../../interfaces/node/IScopeIdentifiersTraverser';
-import { IScopeIdentifiersTraverserVariableCallbackData } from '../../interfaces/node/IScopeIdentifiersTraverserVariableCallbackData';
+import { IScopeIdentifiersTraverserCallbackData } from '../../interfaces/node/IScopeIdentifiersTraverserCallbackData';
 import { IVisitor } from '../../interfaces/node-transformers/IVisitor';
 
 import { NodeTransformer } from '../../enums/node-transformers/NodeTransformer';
@@ -93,7 +93,7 @@ export class VariablePreserveTransformer extends AbstractNodeTransformer {
      * @returns {NodeGuards}
      */
     public transformNode (programNode: ESTree.Program, parentNode: ESTree.Node): ESTree.Node {
-        this.scopeIdentifiersTraverser.traverseScopeVariables(
+        this.scopeIdentifiersTraverser.traverseScopeIdentifiers(
             programNode,
             parentNode,
             this.preserveScopeVariableIdentifiers
@@ -103,9 +103,9 @@ export class VariablePreserveTransformer extends AbstractNodeTransformer {
     }
 
     /**
-     * @param {IScopeIdentifiersTraverserVariableCallbackData} data
+     * @param {IScopeIdentifiersTraverserCallbackData} data
      */
-    private preserveScopeVariableIdentifiers (data: IScopeIdentifiersTraverserVariableCallbackData): void {
+    private preserveScopeVariableIdentifiers (data: IScopeIdentifiersTraverserCallbackData): void {
         const {
             isGlobalDeclaration,
             isBubblingDeclaration,

+ 59 - 9
src/node/ScopeIdentifiersTraverser.ts

@@ -5,10 +5,12 @@ import * as eslintScope from 'eslint-scope';
 import * as ESTree from 'estree';
 
 import { TNodeWithLexicalScope } from '../types/node/TNodeWithLexicalScope';
-import { TScopeIdentifiersTraverserVariableCallback } from '../types/node/TScopeIdentifiersTraverserVariableCallback';
+import { TScopeIdentifiersTraverserCallback } from '../types/node/TScopeIdentifiersTraverserCallback';
 
 import { IScopeAnalyzer } from '../interfaces/analyzers/scope-analyzer/IScopeAnalyzer';
 import { IScopeIdentifiersTraverser } from '../interfaces/node/IScopeIdentifiersTraverser';
+import { IScopeIdentifiersTraverserCallbackData } from '../interfaces/node/IScopeIdentifiersTraverserCallbackData';
+import { IScopeThroughIdentifiersTraverserCallbackData } from '../interfaces/node/IScopeThroughIdentifiersTraverserCallbackData';
 
 import { NodeGuards } from './NodeGuards';
 
@@ -47,29 +49,46 @@ export class ScopeIdentifiersTraverser implements IScopeIdentifiersTraverser {
     /**
      * @param {Program} programNode
      * @param {Node | null} parentNode
-     * @param {TScopeIdentifiersTraverserVariableCallback} callback
+     * @param {TScopeIdentifiersTraverserCallback<IScopeIdentifiersTraverserCallbackData>} callback
      */
-    public traverseScopeVariables (
+    public traverseScopeIdentifiers (
         programNode: ESTree.Program,
         parentNode: ESTree.Node | null,
-        callback: TScopeIdentifiersTraverserVariableCallback
+        callback: TScopeIdentifiersTraverserCallback<IScopeIdentifiersTraverserCallbackData>
     ): void {
         this.scopeAnalyzer.analyze(programNode);
 
         const globalScope: eslintScope.Scope = this.scopeAnalyzer.acquireScope(programNode);
 
-        this.traverseScopeVariablesRecursive(globalScope, globalScope, callback);
+        this.traverseScopeIdentifiersRecursive(globalScope, globalScope, callback);
+    }
+
+    /**
+     * @param {Program} programNode
+     * @param {Node | null} parentNode
+     * @param {TScopeIdentifiersTraverserCallback<IScopeThroughIdentifiersTraverserCallbackData>} callback
+     */
+    public traverseScopeThroughIdentifiers (
+        programNode: ESTree.Program,
+        parentNode: ESTree.Node | null,
+        callback: TScopeIdentifiersTraverserCallback<IScopeThroughIdentifiersTraverserCallbackData>
+    ): void {
+        this.scopeAnalyzer.analyze(programNode);
+
+        const globalScope: eslintScope.Scope = this.scopeAnalyzer.acquireScope(programNode);
+
+        this.traverseScopeThroughIdentifiersRecursive(globalScope, globalScope, callback);
     }
 
     /**
      * @param {Scope} rootScope
      * @param {Scope} currentScope
-     * @param {TScopeIdentifiersTraverserVariableCallback} callback
+     * @param {TScopeIdentifiersTraverserCallback<IScopeIdentifiersTraverserCallbackData>} callback
      */
-    private traverseScopeVariablesRecursive (
+    private traverseScopeIdentifiersRecursive (
         rootScope: eslintScope.Scope,
         currentScope: eslintScope.Scope,
-        callback: TScopeIdentifiersTraverserVariableCallback
+        callback: TScopeIdentifiersTraverserCallback<IScopeIdentifiersTraverserCallbackData>
     ): void {
         const variableScope: eslintScope.Scope = currentScope.variableScope;
         const variableLexicalScopeNode: TNodeWithLexicalScope | null = NodeGuards.isNodeWithBlockLexicalScope(variableScope.block)
@@ -105,7 +124,38 @@ export class ScopeIdentifiersTraverser implements IScopeIdentifiersTraverser {
         }
 
         for (const childScope of currentScope.childScopes) {
-            this.traverseScopeVariablesRecursive(rootScope, childScope, callback);
+            this.traverseScopeIdentifiersRecursive(rootScope, childScope, callback);
+        }
+    }
+
+    /**
+     * @param {Scope} rootScope
+     * @param {Scope} currentScope
+     * @param {TScopeIdentifiersTraverserCallback<IScopeThroughIdentifiersTraverserCallbackData>} callback
+     */
+    private traverseScopeThroughIdentifiersRecursive (
+        rootScope: eslintScope.Scope,
+        currentScope: eslintScope.Scope,
+        callback: TScopeIdentifiersTraverserCallback<IScopeThroughIdentifiersTraverserCallbackData>
+    ): void {
+        const variableScope: eslintScope.Scope = currentScope.variableScope;
+        const variableLexicalScopeNode: TNodeWithLexicalScope | null = NodeGuards.isNodeWithBlockLexicalScope(variableScope.block)
+            ? variableScope.block
+            : null;
+
+        if (!variableLexicalScopeNode) {
+            return;
+        }
+
+        for (const reference of currentScope.through) {
+            callback({
+                reference,
+                variableLexicalScopeNode
+            });
+        }
+
+        for (const childScope of currentScope.childScopes) {
+            this.traverseScopeThroughIdentifiersRecursive(rootScope, childScope, callback);
         }
     }
 }

+ 1 - 0
src/types/node/TScopeIdentifiersTraverserCallback.ts

@@ -0,0 +1 @@
+export type TScopeIdentifiersTraverserCallback <TData> = (data: TData) => void;

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

@@ -1,3 +0,0 @@
-import { IScopeIdentifiersTraverserVariableCallbackData } from '../../interfaces/node/IScopeIdentifiersTraverserVariableCallbackData';
-
-export type TScopeIdentifiersTraverserVariableCallback = (data: IScopeIdentifiersTraverserVariableCallbackData) => void;

+ 27 - 6
test/dev/dev.ts

@@ -7,17 +7,38 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../src/options/presets/NoCustomNo
 
     let obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
         `
-            const foo = {
-                bar: {
-                    baz: 1
+            function foo () {
+                function bar () {
+                    const a = [];
+                    const b = [];
+                    while (true) {
+                        for (const a of b) {}
+                    }
+                    return a;
                 }
-            };
             
-            console.log(foo.bar.baz);
+                function baz () {
+                    const a = 1;
+                }
+            
+                function bark () {
+                    const a = 1;
+                    
+                    if (true) {
+                        console.log(a);
+                    }
+                }
+            
+                function hawk () {
+                    const a = 1;
+                }
+            }
         `,
         {
             ...NO_ADDITIONAL_NODES_PRESET,
-            compact: false
+            compact: false,
+            deadCodeInjection: true,
+            deadCodeInjectionThreshold: 1
         }
     ).getObfuscatedCode();
 

+ 13 - 12
test/functional-tests/node-transformers/dead-code-injection-transformers/DeadCodeInjectionTransformer.spec.ts

@@ -12,6 +12,7 @@ import { JavaScriptObfuscator } from '../../../../src/JavaScriptObfuscatorFacade
 describe('DeadCodeInjectionTransformer', () => {
     const variableMatch: string = '_0x([a-f0-9]){4,6}';
     const hexMatch: string = '0x[a-f0-9]';
+    const stringArrayCallMatch: string = `${variableMatch}\\('${hexMatch}'\\)`;
 
     describe('transformNode', function () {
         this.timeout(100000);
@@ -448,31 +449,31 @@ describe('DeadCodeInjectionTransformer', () => {
             const functionMatch: string = `var ${variableMatch} *= *function *\\(\\) *\\{`;
 
             const match1: string = `` +
-                `if *\\(${variableMatch}\\('${hexMatch}'\\) *=== *${variableMatch}\\('${hexMatch}'\\)\\) *\\{` +
-                    `console.*` +
+                `if *\\(${stringArrayCallMatch} *=== *${stringArrayCallMatch}\\) *\\{` +
+                    `console\\[${stringArrayCallMatch}]\\(${stringArrayCallMatch}\\);` +
                 `\\} *else *\\{` +
-                    `alert.*` +
+                    `${variableMatch}\\(${stringArrayCallMatch}\\);` +
                 `\\}` +
             ``;
             const match2: string = `` +
-                `if *\\(${variableMatch}\\('${hexMatch}'\\) *!== *${variableMatch}\\('${hexMatch}'\\)\\) *\\{` +
-                    `console.*` +
+                `if *\\(${stringArrayCallMatch} *!== *${stringArrayCallMatch}\\) *\\{` +
+                    `console\\[${stringArrayCallMatch}]\\(${stringArrayCallMatch}\\);` +
                 `\\} *else *\\{` +
-                    `alert.*` +
+                    `${variableMatch}\\(${stringArrayCallMatch}\\);` +
                 `\\}` +
             ``;
             const match3: string = `` +
-                `if *\\(${variableMatch}\\('${hexMatch}'\\) *=== *${variableMatch}\\('${hexMatch}'\\)\\) *\\{` +
-                    `alert.*` +
+                `if *\\(${stringArrayCallMatch} *=== *${stringArrayCallMatch}\\) *\\{` +
+                    `${variableMatch}\\(${stringArrayCallMatch}\\);` +
                 `\\} *else *\\{` +
-                    `console.*` +
+                    `console\\[${stringArrayCallMatch}]\\(${stringArrayCallMatch}\\);` +
                 `\\}` +
             ``;
             const match4: string = `` +
-                `if *\\(${variableMatch}\\('${hexMatch}'\\) *!== *${variableMatch}\\('${hexMatch}'\\)\\) *\\{` +
-                    `alert.*` +
+                `if *\\(${stringArrayCallMatch} *!== *${stringArrayCallMatch}\\) *\\{` +
+                    `${variableMatch}\\(${stringArrayCallMatch}\\);` +
                 `\\} *else *\\{` +
-                    `console.*` +
+                    `console\\[${stringArrayCallMatch}]\\(${stringArrayCallMatch}\\);` +
                 `\\}` +
             ``;
 

+ 48 - 48
yarn.lock

@@ -366,10 +366,10 @@
   dependencies:
     "@types/node" "*"
 
-"@types/[email protected].2":
-  version "8.0.2"
-  resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-8.0.2.tgz#cdd160767c5a445bedef94ea8cfc8ab760fff42b"
-  integrity sha512-5cv8rmqT3KX9XtWDvSgGYfS4OwrKM2eei90GWLnTYz+AXRiBv5uYcKBjnkQ4katNvfYk3+o2bHGZUsDhdcoUyg==
+"@types/[email protected].3":
+  version "8.0.3"
+  resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-8.0.3.tgz#51b21b6acb6d1b923bbdc7725c38f9f455166402"
+  integrity sha512-vyxR57nv8NfcU0GZu8EUXZLTbCMupIUwy95LJ6lllN+JRPG25CwMHoB1q5xKh8YKhQnHYRAn4yW2yuHbf/5xgg==
 
 "@types/[email protected]":
   version "4.0.0"
@@ -383,10 +383,10 @@
   resolved "https://registry.yarnpkg.com/@types/node/-/node-13.9.3.tgz#6356df2647de9eac569f9a52eda3480fa9e70b4d"
   integrity sha512-01s+ac4qerwd6RHD+mVbOEsraDHSgUaefQlEdBbUolnQFjKwCr7luvAlEwW1RFojh67u0z4OUTjPn9LEl4zIkA==
 
-"@types/[email protected].27":
-  version "14.0.27"
-  resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.27.tgz#a151873af5a5e851b51b3b065c9e63390a9e0eb1"
-  integrity sha512-kVrqXhbclHNHGu9ztnAwSncIgJv/FaxmzXJvGXNdcCpV1b8u1/Mi6z6m0vwy0LzKeXFTPLH0NzwmoJ3fNCIq0g==
+"@types/node@14.6.0":
+  version "14.6.0"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-14.6.0.tgz#7d4411bf5157339337d7cff864d9ff45f177b499"
+  integrity sha512-mikldZQitV94akrc4sCcSjtJfsTKt4p+e/s0AGscVA6XArQ9kFclP+ZiYUMnq987rc6QlYxXv/EivqlfSLxpKA==
 
 "@types/normalize-package-data@^2.4.0":
   version "2.4.0"
@@ -433,52 +433,52 @@
   resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.15.2.tgz#927997342bb9f4a5185a86e6579a0a18afc33b0a"
   integrity sha512-67ZgZpAlhIICIdfQrB5fnDvaKFcDxpKibxznfYRVAT4mQE41Dido/3Ty+E3xGBmTogc5+0Qb8tWhna+5B8z1iQ==
 
-"@typescript-eslint/[email protected].0":
-  version "3.9.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.9.0.tgz#0fe529b33d63c9a94f7503ca2bb12c84b9477ff3"
-  integrity sha512-UD6b4p0/hSe1xdTvRCENSx7iQ+KR6ourlZFfYuPC7FlXEzdHuLPrEmuxZ23b2zW96KJX9Z3w05GE/wNOiEzrVg==
+"@typescript-eslint/[email protected].1":
+  version "3.9.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.9.1.tgz#8cf27b6227d12d66dd8dc1f1a4b04d1daad51c2e"
+  integrity sha512-XIr+Mfv7i4paEdBf0JFdIl9/tVxyj+rlilWIfZ97Be0lZ7hPvUbS5iHt9Glc8kRI53dsr0PcAEudbf8rO2wGgg==
   dependencies:
-    "@typescript-eslint/experimental-utils" "3.9.0"
+    "@typescript-eslint/experimental-utils" "3.9.1"
     debug "^4.1.1"
     functional-red-black-tree "^1.0.1"
     regexpp "^3.0.0"
     semver "^7.3.2"
     tsutils "^3.17.1"
 
-"@typescript-eslint/[email protected].0":
-  version "3.9.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-3.9.0.tgz#3171d8ddba0bf02a8c2034188593630914fcf5ee"
-  integrity sha512-/vSHUDYizSOhrOJdjYxPNGfb4a3ibO8zd4nUKo/QBFOmxosT3cVUV7KIg8Dwi6TXlr667G7YPqFK9+VSZOorNA==
+"@typescript-eslint/[email protected].1":
+  version "3.9.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-3.9.1.tgz#b140b2dc7a7554a44f8a86fb6fe7cbfe57ca059e"
+  integrity sha512-lkiZ8iBBaYoyEKhCkkw4SAeatXyBq9Ece5bZXdLe1LWBUwTszGbmbiqmQbwWA8cSYDnjWXp9eDbXpf9Sn0hLAg==
   dependencies:
     "@types/json-schema" "^7.0.3"
-    "@typescript-eslint/types" "3.9.0"
-    "@typescript-eslint/typescript-estree" "3.9.0"
+    "@typescript-eslint/types" "3.9.1"
+    "@typescript-eslint/typescript-estree" "3.9.1"
     eslint-scope "^5.0.0"
     eslint-utils "^2.0.0"
 
-"@typescript-eslint/[email protected].0":
-  version "3.9.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-3.9.0.tgz#344978a265d9a5c7c8f13e62c78172a4374dabea"
-  integrity sha512-rDHOKb6uW2jZkHQniUQVZkixQrfsZGUCNWWbKWep4A5hGhN5dLHMUCNAWnC4tXRlHedXkTDptIpxs6e4Pz8UfA==
+"@typescript-eslint/[email protected].1":
+  version "3.9.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-3.9.1.tgz#ab7983abaea0ae138ff5671c7c7739d8a191b181"
+  integrity sha512-y5QvPFUn4Vl4qM40lI+pNWhTcOWtpZAJ8pOEQ21fTTW4xTJkRplMjMRje7LYTXqVKKX9GJhcyweMz2+W1J5bMg==
   dependencies:
     "@types/eslint-visitor-keys" "^1.0.0"
-    "@typescript-eslint/experimental-utils" "3.9.0"
-    "@typescript-eslint/types" "3.9.0"
-    "@typescript-eslint/typescript-estree" "3.9.0"
+    "@typescript-eslint/experimental-utils" "3.9.1"
+    "@typescript-eslint/types" "3.9.1"
+    "@typescript-eslint/typescript-estree" "3.9.1"
     eslint-visitor-keys "^1.1.0"
 
-"@typescript-eslint/[email protected].0":
-  version "3.9.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-3.9.0.tgz#be9d0aa451e1bf3ce99f2e6920659e5b2e6bfe18"
-  integrity sha512-rb6LDr+dk9RVVXO/NJE8dT1pGlso3voNdEIN8ugm4CWM5w5GimbThCMiMl4da1t5u3YwPWEwOnKAULCZgBtBHg==
+"@typescript-eslint/[email protected].1":
+  version "3.9.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-3.9.1.tgz#b2a6eaac843cf2f2777b3f2464fb1fbce5111416"
+  integrity sha512-15JcTlNQE1BsYy5NBhctnEhEoctjXOjOK+Q+rk8ugC+WXU9rAcS2BYhoh6X4rOaXJEpIYDl+p7ix+A5U0BqPTw==
 
-"@typescript-eslint/[email protected].0":
-  version "3.9.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-3.9.0.tgz#c6abbb50fa0d715cab46fef67ca6378bf2eaca13"
-  integrity sha512-N+158NKgN4rOmWVfvKOMoMFV5n8XxAliaKkArm/sOypzQ0bUL8MSnOEBW3VFIeffb/K5ce/cAV0yYhR7U4ALAA==
+"@typescript-eslint/[email protected].1":
+  version "3.9.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-3.9.1.tgz#fd81cada74bc8a7f3a2345b00897acb087935779"
+  integrity sha512-IqM0gfGxOmIKPhiHW/iyAEXwSVqMmR2wJ9uXHNdFpqVvPaQ3dWg302vW127sBpAiqM9SfHhyS40NKLsoMpN2KA==
   dependencies:
-    "@typescript-eslint/types" "3.9.0"
-    "@typescript-eslint/visitor-keys" "3.9.0"
+    "@typescript-eslint/types" "3.9.1"
+    "@typescript-eslint/visitor-keys" "3.9.1"
     debug "^4.1.1"
     glob "^7.1.6"
     is-glob "^4.0.1"
@@ -486,10 +486,10 @@
     semver "^7.3.2"
     tsutils "^3.17.1"
 
-"@typescript-eslint/[email protected].0":
-  version "3.9.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-3.9.0.tgz#44de8e1b1df67adaf3b94d6b60b80f8faebc8dd3"
-  integrity sha512-O1qeoGqDbu0EZUC/MZ6F1WHTIzcBVhGqDj3LhTnj65WUA548RXVxUHbYhAW9bZWfb2rnX9QsbbP5nmeJ5Z4+ng==
+"@typescript-eslint/[email protected].1":
+  version "3.9.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-3.9.1.tgz#92af3747cdb71509199a8f7a4f00b41d636551d1"
+  integrity sha512-zxdtUjeoSh+prCpogswMwVUJfEFmCOjdzK9rpNjNBfm6EyPt99x3RrJoBOGZO23FCt0WPKUCOL5mb/9D5LjdwQ==
   dependencies:
     eslint-visitor-keys "^1.1.0"
 
@@ -1971,10 +1971,10 @@ [email protected]:
     resolve "^1.17.0"
     tsconfig-paths "^3.9.0"
 
[email protected].3:
-  version "30.2.3"
-  resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-30.2.3.tgz#5cdfac270144eec9a5fac60061923204082266fe"
-  integrity sha512-yj3EEjukab/PuspQRHKJuxFK6WP4RiZDklikQz5t4PJdwUo0I7hUA9GtcS8aY+IP5jvXs6HMlnjBwvVit8aG/A==
[email protected].4:
+  version "30.2.4"
+  resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-30.2.4.tgz#fab63c612d10f7f622ed6ebdd6d9919fc6cc4e0e"
+  integrity sha512-7TLp+1EK/ufnzlBUuzgDiPz5k2UUIa01cFkZTvvbJr8PE0iWVDqENg0yLhqGUYaZfYRFhHpqCML8SQR94omfrg==
   dependencies:
     comment-parser "^0.7.6"
     debug "^4.1.1"
@@ -2414,10 +2414,10 @@ [email protected]:
   dependencies:
     node-notifier "^6.0.0"
 
[email protected].14:
-  version "5.0.14"
-  resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-5.0.14.tgz#83758b733ccd5d6e5780a72a5d5f099c353c108d"
-  integrity sha512-iwRdjgZx1Ll0DAMhmtOF4ffoICpiUxOqOHLrbIHmeCtZiwCrL/qscm+EXOJyzj3a9X8hLRLDEHy9FOyD6Gm42g==
+fork-ts-checker-webpack-plugin@5.1.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-5.1.0.tgz#586fbee24aeea950c53bab529e32017f543e71cf"
+  integrity sha512-vuKyEjSLGbhQbEr5bifXXOkr9iV73L6n72mHoHIv7okvrf7O7z6RKeplM6C6ATPsukoQivij+Ba1vcptL60Z2g==
   dependencies:
     "@babel/code-frame" "^7.8.3"
     "@types/json-schema" "^7.0.5"

Some files were not shown because too many files changed in this diff