FunctionDeclarationObfuscator.ts 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  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 { IObfuscatorReplacer } from '../../interfaces/node-transformers/IObfuscatorReplacer';
  8. import { IObfuscatorReplacerWithStorage } from '../../interfaces/node-transformers/IObfuscatorReplacerWithStorage';
  9. import { NodeObfuscatorsReplacers } from '../../enums/container/NodeObfuscatorsReplacers';
  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. * function foo () { //... };
  17. * foo();
  18. *
  19. * on:
  20. * function _0x12d45f () { //... };
  21. * _0x12d45f();
  22. */
  23. @injectable()
  24. export class FunctionDeclarationObfuscator extends AbstractNodeTransformer {
  25. /**
  26. * @type {IObfuscatorReplacerWithStorage}
  27. */
  28. private readonly identifierReplacer: IObfuscatorReplacerWithStorage;
  29. /**
  30. * @type {Map<ESTree.Node, ESTree.Identifier[]>}
  31. */
  32. private readonly replaceableIdentifiers: Map <ESTree.Node, ESTree.Identifier[]> = new Map();
  33. /**
  34. * @param nodeObfuscatorsReplacersFactory
  35. * @param options
  36. */
  37. constructor(
  38. @inject(ServiceIdentifiers.Factory__IObfuscatorReplacer) nodeObfuscatorsReplacersFactory: (replacer: NodeObfuscatorsReplacers) => IObfuscatorReplacer,
  39. @inject(ServiceIdentifiers.IOptions) options: IOptions
  40. ) {
  41. super(options);
  42. this.identifierReplacer = <IObfuscatorReplacerWithStorage>nodeObfuscatorsReplacersFactory(NodeObfuscatorsReplacers.IdentifierReplacer);
  43. }
  44. /**
  45. * @param functionDeclarationNode
  46. * @param parentNode
  47. * @returns {ESTree.Node}
  48. */
  49. public transformNode (functionDeclarationNode: ESTree.FunctionDeclaration, parentNode: ESTree.Node): ESTree.Node {
  50. const nodeIdentifier: number = this.nodeIdentifier++;
  51. const blockScopeOfFunctionDeclarationNode: TNodeWithBlockStatement = NodeUtils
  52. .getBlockScopesOfNode(functionDeclarationNode)[0];
  53. if (blockScopeOfFunctionDeclarationNode.type === NodeType.Program) {
  54. return functionDeclarationNode;
  55. }
  56. this.storeFunctionName(functionDeclarationNode, nodeIdentifier);
  57. this.replaceFunctionName(blockScopeOfFunctionDeclarationNode, nodeIdentifier);
  58. return functionDeclarationNode;
  59. }
  60. /**
  61. * @param functionDeclarationNode
  62. * @param nodeIdentifier
  63. */
  64. private storeFunctionName (functionDeclarationNode: ESTree.FunctionDeclaration, nodeIdentifier: number): void {
  65. NodeUtils.typedTraverse(functionDeclarationNode.id, NodeType.Identifier, {
  66. enter: (node: ESTree.Identifier) => this.identifierReplacer.storeNames(node.name, nodeIdentifier)
  67. });
  68. }
  69. /**
  70. * @param scopeNode
  71. * @param nodeIdentifier
  72. */
  73. private replaceFunctionName (scopeNode: ESTree.Node, nodeIdentifier: number): void {
  74. let replaceableIdentifiersForCurrentScope: ESTree.Identifier[];
  75. // check for cached identifiers for current scope node. If exist - loop through them.
  76. if (this.replaceableIdentifiers.has(scopeNode)) {
  77. replaceableIdentifiersForCurrentScope = <ESTree.Identifier[]>this.replaceableIdentifiers.get(scopeNode);
  78. for (const replaceableIdentifier of replaceableIdentifiersForCurrentScope) {
  79. replaceableIdentifier.name = this.identifierReplacer.replace(replaceableIdentifier.name, nodeIdentifier);
  80. }
  81. return;
  82. }
  83. replaceableIdentifiersForCurrentScope = [];
  84. estraverse.replace(scopeNode, {
  85. enter: (node: ESTree.Node, parentNode: ESTree.Node): any => {
  86. if (Node.isReplaceableIdentifierNode(node, parentNode)) {
  87. const newNodeName: string = this.identifierReplacer.replace(node.name, nodeIdentifier);
  88. if (node.name !== newNodeName) {
  89. node.name = newNodeName;
  90. } else {
  91. replaceableIdentifiersForCurrentScope.push(node);
  92. }
  93. }
  94. }
  95. });
  96. this.replaceableIdentifiers.set(scopeNode, replaceableIdentifiersForCurrentScope);
  97. }
  98. }