FunctionControlFlowTransformer.spec.ts 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  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('FunctionControlFlowTransformer', () => {
  7. const variableMatch: string = '_0x([a-z0-9]){4,6}';
  8. const rootControlFlowStorageNodeMatch: string = `` +
  9. `var *${variableMatch} *= *\\{` +
  10. `'(\\\\x[a-f0-9]*){3}' *: *function *${variableMatch} *\\(${variableMatch}, *${variableMatch}\\) *\\{` +
  11. `return *${variableMatch} *\\+ *${variableMatch};` +
  12. `\\}` +
  13. `\\};` +
  14. ``;
  15. const innerControlFlowStorageNodeMatch: string = `` +
  16. `var *${variableMatch} *= *\\{` +
  17. `'(\\\\x[a-f0-9]*){3}' *: *function *${variableMatch} *\\(${variableMatch}, *${variableMatch}\\) *\\{` +
  18. `return *${variableMatch}\\['(\\\\x[a-f0-9]*){3}'\\]\\(${variableMatch}, *${variableMatch}\\);` +
  19. `\\}` +
  20. `\\};` +
  21. ``;
  22. describe('transformNode (functionNode: ESTree.Function): ESTree.Node', () => {
  23. describe('variant #1 - single `control flow storage` node with single item', () => {
  24. const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
  25. readFileAsString(
  26. './test/fixtures/node-transformers/control-flow-transformers/function-control-flow-transformer-1.js'
  27. ),
  28. {
  29. ...NO_CUSTOM_NODES_PRESET,
  30. controlFlowFlattening: true,
  31. controlFlowFlatteningThreshold: 1
  32. }
  33. );
  34. const obfuscatedCode: string = obfuscationResult.getObfuscatedCode();
  35. const regexp: RegExp = new RegExp(rootControlFlowStorageNodeMatch);
  36. it('should add `control flow storage` node to the obfuscated code', () => {
  37. assert.match(obfuscatedCode, regexp);
  38. });
  39. });
  40. describe('variant #2 - two `control flow storage` nodes: root and inner', () => {
  41. const samplesCount: number = 200;
  42. const delta: number = 0.1;
  43. const expectedValue: number = 0.5;
  44. const regExp1: RegExp = new RegExp(
  45. `\\(function\\(\\) *\\{ *${rootControlFlowStorageNodeMatch}`,
  46. 'g'
  47. );
  48. const regExp2: RegExp = new RegExp(
  49. `function *${variableMatch} *\\(\\) *\\{ *${innerControlFlowStorageNodeMatch}`,
  50. 'g'
  51. );
  52. let totalValue: number = 0;
  53. for (let i = 0; i < samplesCount; i++) {
  54. const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
  55. readFileAsString(
  56. './test/fixtures/node-transformers/control-flow-transformers/function-control-flow-transformer-2.js'
  57. ),
  58. {
  59. ...NO_CUSTOM_NODES_PRESET,
  60. controlFlowFlattening: true,
  61. controlFlowFlatteningThreshold: 1
  62. }
  63. );
  64. const obfuscatedCode: string = obfuscationResult.getObfuscatedCode();
  65. if (regExp1.test(obfuscatedCode)) {
  66. totalValue += obfuscatedCode.match(regExp1)!.length;
  67. if (regExp2.test(obfuscatedCode)) {
  68. totalValue += obfuscatedCode.match(regExp2)!.length;
  69. }
  70. }
  71. }
  72. it('should add two `control flow storage` nodes (root and inner) to the obfuscated code in different scopes', () => {
  73. assert.closeTo((totalValue - samplesCount) / samplesCount, expectedValue, delta);
  74. });
  75. });
  76. describe('variant #3 - single `control flow storage` node with multiple items', () => {
  77. const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
  78. readFileAsString(
  79. './test/fixtures/node-transformers/control-flow-transformers/function-control-flow-transformer-multiple-items-1.js'
  80. ),
  81. {
  82. ...NO_CUSTOM_NODES_PRESET,
  83. controlFlowFlattening: true,
  84. controlFlowFlatteningThreshold: 1
  85. }
  86. );
  87. const obfuscatedCode: string = obfuscationResult.getObfuscatedCode();
  88. const regexp: RegExp = new RegExp(
  89. `var *${variableMatch} *= *\\{` +
  90. `'(\\\\x[a-f0-9]*){3}' *: *function *${variableMatch} *\\(${variableMatch}, *${variableMatch}\\) *\\{` +
  91. `return *${variableMatch} *\\+ *${variableMatch};` +
  92. `\\}, *` +
  93. `'(\\\\x[a-f0-9]*){3}' *: *function *${variableMatch} *\\(${variableMatch}, *${variableMatch}\\) *\\{` +
  94. `return *${variableMatch} *- *${variableMatch};` +
  95. `\\}` +
  96. `\\};`
  97. );
  98. it('should add `control flow storage` node with multiple items to the obfuscated code', () => {
  99. assert.match(obfuscatedCode, regexp);
  100. });
  101. });
  102. describe('variant #4 - no `control flow storage` node to the root block scope', () => {
  103. const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
  104. readFileAsString(
  105. './test/fixtures/node-transformers/control-flow-transformers/function-control-flow-transformer-root-block-scope-1.js'
  106. ),
  107. {
  108. ...NO_CUSTOM_NODES_PRESET,
  109. controlFlowFlattening: true,
  110. controlFlowFlatteningThreshold: 1
  111. }
  112. );
  113. const obfuscatedCode: string = obfuscationResult.getObfuscatedCode();
  114. it('should\'t add control flow storage node when transformed node in the root block scope', () => {
  115. assert.match(obfuscatedCode, /^var *test *= *0x1 *\+ *0x2;$/);
  116. });
  117. });
  118. describe('variant #5 - no `control flow storage` node in the root block scope', () => {
  119. const samplesCount: number = 20;
  120. const expectedValue: number = 0;
  121. const regExp: RegExp = new RegExp(
  122. `var *[a-zA-Z]{6} *= *\\{` +
  123. `'(\\\\x[a-f0-9]*){3}' *: *function *_0x[0-9] *\\(${variableMatch}, *${variableMatch}\\) *\\{` +
  124. `return *${variableMatch} *\\+ *${variableMatch};` +
  125. `\\}` +
  126. `\\};`
  127. );
  128. it('should\'t add control flow storage node to the root block scope when transformed nodes not in the root block scope', () => {
  129. let totalValue: number = 0;
  130. for (let i = 0; i < samplesCount; i++) {
  131. const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
  132. readFileAsString(
  133. './test/fixtures/node-transformers/control-flow-transformers/function-control-flow-transformer-root-block-scope-2.js'
  134. ),
  135. {
  136. ...NO_CUSTOM_NODES_PRESET,
  137. controlFlowFlattening: true,
  138. controlFlowFlatteningThreshold: 1
  139. }
  140. );
  141. const obfuscatedCode: string = obfuscationResult.getObfuscatedCode();
  142. if (regExp.test(obfuscatedCode)) {
  143. totalValue++;
  144. }
  145. }
  146. assert.equal(totalValue, expectedValue);
  147. });
  148. });
  149. describe('variant #6 - no single `control flow storage` node when threshold is 0', () => {
  150. const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
  151. readFileAsString(
  152. './test/fixtures/node-transformers/control-flow-transformers/function-control-flow-transformer-zero-threshold.js'
  153. ),
  154. {
  155. ...NO_CUSTOM_NODES_PRESET,
  156. controlFlowFlattening: true,
  157. controlFlowFlatteningThreshold: 0
  158. }
  159. );
  160. const obfuscatedCode: string = obfuscationResult.getObfuscatedCode();
  161. const controlFlowStorageMatch: RegExp = new RegExp(rootControlFlowStorageNodeMatch);
  162. const regexp: RegExp = /var *_0x([a-z0-9]){4,6} *= *0x1 *\+ *0x2;/;
  163. it('shouldn\'t add `control flow storage` node to the obfuscated code when threshold is 0', () => {
  164. assert.match(obfuscatedCode, regexp);
  165. assert.notMatch(obfuscatedCode, controlFlowStorageMatch);
  166. });
  167. });
  168. });
  169. });