DeadCodeInjectionTransformer.spec.ts 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. import { assert } from 'chai';
  2. import { IObfuscationResult } from '../../../../src/interfaces/IObfuscationResult';
  3. import { NO_CUSTOM_NODES_PRESET } from '../../../../src/options/presets/NoCustomNodes';
  4. import { readFileAsString } from '../../../helpers/readFileAsString';
  5. import { JavaScriptObfuscator } from '../../../../src/JavaScriptObfuscator';
  6. describe('DeadCodeInjectionTransformer', () => {
  7. const variableMatch: string = '_0x([a-f0-9]){4,6}';
  8. const hexMatch: string = '0x[a-f0-9]';
  9. describe('transformNode (programNode: ESTree.Program, parentNode: ESTree.Node): ESTree.Node', () => {
  10. describe('variant #1 - 5 simple block statements', () => {
  11. const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
  12. readFileAsString(__dirname + '/fixtures/input-1.js'),
  13. {
  14. ...NO_CUSTOM_NODES_PRESET,
  15. deadCodeInjection: true,
  16. deadCodeInjectionThreshold: 1,
  17. stringArray: true,
  18. stringArrayThreshold: 1
  19. }
  20. );
  21. const obfuscatedCode: string = obfuscationResult.getObfuscatedCode();
  22. const deadCodeMatch: string = `` +
  23. `if *\\(${variableMatch}\\('${hexMatch}'\\) *[=|!]== *${variableMatch}\\('${hexMatch}'\\)\\) *\\{`+
  24. `console\\[${variableMatch}\\('${hexMatch}'\\)\\]\\(${variableMatch}\\('${hexMatch}'\\)\\);` +
  25. `\\} *else *\\{`+
  26. `console\\[${variableMatch}\\('${hexMatch}'\\)\\]\\(${variableMatch}\\('${hexMatch}'\\)\\);` +
  27. `\\}` +
  28. ``;
  29. const regexp: RegExp = new RegExp(deadCodeMatch, 'g');
  30. const matches: RegExpMatchArray = <RegExpMatchArray>obfuscatedCode.match(regexp);
  31. it('should replace block statements with condition with original block statements and dead code', () => {
  32. assert.isNotNull(matches);
  33. assert.equal(matches.length, 5);
  34. });
  35. });
  36. describe('variant #2 - 4 simple block statements', () => {
  37. const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
  38. readFileAsString(__dirname + '/fixtures/block-statements-min-count.js'),
  39. {
  40. ...NO_CUSTOM_NODES_PRESET,
  41. deadCodeInjection: true,
  42. deadCodeInjectionThreshold: 1,
  43. stringArray: true,
  44. stringArrayThreshold: 1
  45. }
  46. );
  47. const obfuscatedCode: string = obfuscationResult.getObfuscatedCode();
  48. const codeMatch: string = `` +
  49. `var *${variableMatch} *= *function *\\(\\) *\\{` +
  50. `console\\[${variableMatch}\\('${hexMatch}'\\)\\]\\(${variableMatch}\\('${hexMatch}'\\)\\);` +
  51. `\\};` +
  52. ``;
  53. const regexp: RegExp = new RegExp(codeMatch, 'g');
  54. const matches: RegExpMatchArray = <RegExpMatchArray>obfuscatedCode.match(regexp);
  55. it('shouldn\'t add dead code if block statements count is less than 5', () => {
  56. assert.isNotNull(matches);
  57. assert.equal(matches.length, 4);
  58. });
  59. });
  60. describe('variant #3 - deadCodeInjectionThreshold: 0', () => {
  61. const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
  62. readFileAsString(__dirname + '/fixtures/input-1.js'),
  63. {
  64. ...NO_CUSTOM_NODES_PRESET,
  65. deadCodeInjection: true,
  66. deadCodeInjectionThreshold: 0,
  67. stringArray: true,
  68. stringArrayThreshold: 1
  69. }
  70. );
  71. const obfuscatedCode: string = obfuscationResult.getObfuscatedCode();
  72. const codeMatch: string = `` +
  73. `var *${variableMatch} *= *function *\\(\\) *\\{` +
  74. `console\\[${variableMatch}\\('${hexMatch}'\\)\\]\\(${variableMatch}\\('${hexMatch}'\\)\\);` +
  75. `\\};` +
  76. ``;
  77. const regexp: RegExp = new RegExp(codeMatch, 'g');
  78. const matches: RegExpMatchArray = <RegExpMatchArray>obfuscatedCode.match(regexp);
  79. it('shouldn\'t add dead code if `deadCodeInjectionThreshold` option value is `0`', () => {
  80. assert.isNotNull(matches);
  81. assert.equal(matches.length, 5);
  82. });
  83. });
  84. describe('variant #4 - break or continue statement in block statement', () => {
  85. const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
  86. readFileAsString(__dirname + '/fixtures/break-continue-statement.js'),
  87. {
  88. ...NO_CUSTOM_NODES_PRESET,
  89. deadCodeInjection: true,
  90. deadCodeInjectionThreshold: 1,
  91. stringArray: true,
  92. stringArrayThreshold: 1
  93. }
  94. );
  95. const obfuscatedCode: string = obfuscationResult.getObfuscatedCode();
  96. const functionMatch: string = `` +
  97. `var *${variableMatch} *= *function *\\(\\) *\\{` +
  98. `console\\[${variableMatch}\\('${hexMatch}'\\)\\]\\(${variableMatch}\\('${hexMatch}'\\)\\);` +
  99. `\\};` +
  100. ``;
  101. const loopMatch: string = `` +
  102. `for *\\(var *${variableMatch} *= *${hexMatch}; *${variableMatch} *< *${hexMatch}; *${variableMatch}\\+\\+\\) *\\{` +
  103. `(?:continue|break);` +
  104. `\\}` +
  105. ``;
  106. const functionRegExp: RegExp = new RegExp(functionMatch, 'g');
  107. const loopRegExp: RegExp = new RegExp(loopMatch, 'g');
  108. const functionMatches: RegExpMatchArray = <RegExpMatchArray>obfuscatedCode.match(functionRegExp);
  109. const loopMatches: RegExpMatchArray = <RegExpMatchArray>obfuscatedCode.match(loopRegExp);
  110. it('shouldn\'t add dead code if block statement contains `continue` or `break` statements', () => {
  111. assert.isNotNull(functionMatches);
  112. assert.isNotNull(loopMatches);
  113. assert.equal(functionMatches.length, 4);
  114. assert.equal(loopMatches.length, 2);
  115. });
  116. });
  117. });
  118. });