VariableDeclarationTransformer.ts 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. import { injectable, inject } from 'inversify';
  2. import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
  3. import * as estraverse from 'estraverse';
  4. import * as ESTree from 'estree';
  5. import { TNodeWithBlockStatement } from '../../types/node/TNodeWithBlockStatement';
  6. import { IOptions } from '../../interfaces/options/IOptions';
  7. import { IObfuscationReplacer } from '../../interfaces/node-transformers/IObfuscationReplacer';
  8. import { IObfuscationReplacerWithStorage } from '../../interfaces/node-transformers/IObfuscationReplacerWithStorage';
  9. import { NodeObfuscatorsReplacers } from '../../enums/container/NodeObfuscationReplacers';
  10. import { NodeType } from '../../enums/NodeType';
  11. import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
  12. import { Node } from '../../node/Node';
  13. import { NodeUtils } from '../../node/NodeUtils';
  14. /**
  15. * replaces:
  16. * var variable = 1;
  17. * variable++;
  18. *
  19. * on:
  20. * var _0x12d45f = 1;
  21. * _0x12d45f++;
  22. *
  23. */
  24. @injectable()
  25. export class VariableDeclarationTransformer extends AbstractNodeTransformer {
  26. /**
  27. * @type {IObfuscationReplacerWithStorage}
  28. */
  29. private readonly identifierReplacer: IObfuscationReplacerWithStorage;
  30. /**
  31. * @type {Map<ESTree.Node, ESTree.Identifier[]>}
  32. */
  33. private readonly replaceableIdentifiers: Map <ESTree.Node, ESTree.Identifier[]> = new Map();
  34. /**
  35. * @param replacersFactory
  36. * @param options
  37. */
  38. constructor (
  39. @inject(ServiceIdentifiers.Factory__IObfuscatorReplacer) replacersFactory: (replacer: NodeObfuscatorsReplacers) => IObfuscationReplacer,
  40. @inject(ServiceIdentifiers.IOptions) options: IOptions
  41. ) {
  42. super(options);
  43. this.identifierReplacer = <IObfuscationReplacerWithStorage>replacersFactory(NodeObfuscatorsReplacers.IdentifierReplacer);
  44. }
  45. /**
  46. * @return {estraverse.Visitor}
  47. */
  48. public getVisitor (): estraverse.Visitor {
  49. return {
  50. enter: (node: ESTree.Node, parentNode: ESTree.Node) => {
  51. if (Node.isVariableDeclarationNode(node)) {
  52. this.transformNode(node, parentNode);
  53. }
  54. }
  55. };
  56. }
  57. /**
  58. * @param variableDeclarationNode
  59. * @param parentNode
  60. * @returns {ESTree.Node}
  61. */
  62. private transformNode (variableDeclarationNode: ESTree.VariableDeclaration, parentNode: ESTree.Node): ESTree.Node {
  63. const blockScopeOfVariableDeclarationNode: TNodeWithBlockStatement = NodeUtils
  64. .getBlockScopesOfNode(variableDeclarationNode)[0];
  65. if (blockScopeOfVariableDeclarationNode.type === NodeType.Program) {
  66. return variableDeclarationNode;
  67. }
  68. const nodeIdentifier: number = this.nodeIdentifier++;
  69. const scopeNode: ESTree.Node = variableDeclarationNode.kind === 'var'
  70. ? blockScopeOfVariableDeclarationNode
  71. : parentNode;
  72. this.storeVariableNames(variableDeclarationNode, nodeIdentifier);
  73. this.replaceVariableNames(scopeNode, nodeIdentifier);
  74. return variableDeclarationNode;
  75. }
  76. /**
  77. * @param variableDeclarationNode
  78. * @param nodeIdentifier
  79. */
  80. private storeVariableNames (variableDeclarationNode: ESTree.VariableDeclaration, nodeIdentifier: number): void {
  81. variableDeclarationNode.declarations
  82. .forEach((declarationNode: ESTree.VariableDeclarator) => {
  83. if (Node.isObjectPatternNode(declarationNode.id)) {
  84. return estraverse.VisitorOption.Skip;
  85. }
  86. NodeUtils.typedTraverse(declarationNode.id, NodeType.Identifier, {
  87. enter: (node: ESTree.Identifier) => this.identifierReplacer.storeNames(node.name, nodeIdentifier)
  88. });
  89. });
  90. }
  91. /**
  92. * @param scopeNode
  93. * @param nodeIdentifier
  94. */
  95. private replaceVariableNames (scopeNode: ESTree.Node, nodeIdentifier: number): void {
  96. let replaceableIdentifiersForCurrentScope: ESTree.Identifier[];
  97. // check for cached identifiers for current scope node. If exist - loop through them.
  98. if (this.replaceableIdentifiers.has(scopeNode)) {
  99. replaceableIdentifiersForCurrentScope = <ESTree.Identifier[]>this.replaceableIdentifiers.get(scopeNode);
  100. for (const replaceableIdentifier of replaceableIdentifiersForCurrentScope) {
  101. replaceableIdentifier.name = this.identifierReplacer.replace(replaceableIdentifier.name, nodeIdentifier);
  102. }
  103. return;
  104. }
  105. replaceableIdentifiersForCurrentScope = [];
  106. estraverse.replace(scopeNode, {
  107. enter: (node: ESTree.Node, parentNode: ESTree.Node): any => {
  108. if (!node.obfuscatedNode && Node.isReplaceableIdentifierNode(node, parentNode)) {
  109. const newNodeName: string = this.identifierReplacer.replace(node.name, nodeIdentifier);
  110. if (node.name !== newNodeName) {
  111. node.name = newNodeName;
  112. } else {
  113. replaceableIdentifiersForCurrentScope.push(node);
  114. }
  115. }
  116. }
  117. });
  118. this.replaceableIdentifiers.set(scopeNode, replaceableIdentifiersForCurrentScope);
  119. }
  120. }