BinaryExpressionControlFlowReplacer.spec.ts 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. import { assert } from 'chai';
  2. import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../../src/options/presets/NoCustomNodes';
  3. import { readFileAsString } from '../../../../../helpers/readFileAsString';
  4. import { JavaScriptObfuscator } from '../../../../../../src/JavaScriptObfuscatorFacade';
  5. describe('BinaryExpressionControlFlowReplacer', function () {
  6. this.timeout(100000);
  7. describe('replace', () => {
  8. const variableMatch: string = '_0x([a-f0-9]){4,6}';
  9. describe('Variant #1 - single binary expression', () => {
  10. const controlFlowStorageCallRegExp: RegExp = new RegExp(
  11. `var ${variableMatch} *= *${variableMatch}\\['\\w{5}'\\]\\(0x1, *0x2\\);`
  12. );
  13. let obfuscatedCode: string;
  14. before(() => {
  15. const code: string = readFileAsString(__dirname + '/fixtures/input-1.js');
  16. obfuscatedCode = JavaScriptObfuscator.obfuscate(
  17. code,
  18. {
  19. ...NO_ADDITIONAL_NODES_PRESET,
  20. controlFlowFlattening: true,
  21. controlFlowFlatteningThreshold: 1
  22. }
  23. ).getObfuscatedCode();
  24. });
  25. it('should replace binary expression node with call to control flow storage node', () => {
  26. assert.match(obfuscatedCode, controlFlowStorageCallRegExp);
  27. });
  28. });
  29. describe('Variant #2 - multiple binary expressions with threshold = 1', () => {
  30. const expectedMatchErrorsCount: number = 0;
  31. const expectedChance: number = 0.5;
  32. const samplesCount: number = 1000;
  33. const delta: number = 0.1;
  34. const controlFlowStorageCallRegExp1: RegExp = new RegExp(
  35. `var _0x(?:[a-f0-9]){4,6} *= *(${variableMatch}\\['\\w{5}'\\])\\(0x1, *0x2\\);`
  36. );
  37. const controlFlowStorageCallRegExp2: RegExp = new RegExp(
  38. `var _0x(?:[a-f0-9]){4,6} *= *(${variableMatch}\\['\\w{5}'\\])\\(0x2, *0x3\\);`
  39. );
  40. let matchErrorsCount: number = 0,
  41. usingExistingIdentifierChance: number;
  42. before(() => {
  43. const code: string = readFileAsString(__dirname + '/fixtures/input-2.js');
  44. let obfuscatedCode: string,
  45. firstMatchArray: RegExpMatchArray | null,
  46. secondMatchArray: RegExpMatchArray | null,
  47. firstMatch: string | undefined,
  48. secondMatch: string | undefined,
  49. equalsValue: number = 0;
  50. for (let i = 0; i < samplesCount; i++) {
  51. obfuscatedCode = JavaScriptObfuscator.obfuscate(
  52. code,
  53. {
  54. ...NO_ADDITIONAL_NODES_PRESET,
  55. controlFlowFlattening: true,
  56. controlFlowFlatteningThreshold: 1
  57. }
  58. ).getObfuscatedCode();
  59. firstMatchArray = obfuscatedCode.match(controlFlowStorageCallRegExp1);
  60. secondMatchArray = obfuscatedCode.match(controlFlowStorageCallRegExp2);
  61. if (!firstMatchArray || !secondMatchArray) {
  62. matchErrorsCount++;
  63. continue;
  64. }
  65. firstMatch = firstMatchArray ? firstMatchArray[1] : undefined;
  66. secondMatch = secondMatchArray ? secondMatchArray[1] : undefined;
  67. if (firstMatch === secondMatch) {
  68. equalsValue++;
  69. }
  70. }
  71. usingExistingIdentifierChance = equalsValue / samplesCount;
  72. });
  73. it('should replace binary expression node with call to control flow storage node', () => {
  74. assert.equal(matchErrorsCount, expectedMatchErrorsCount);
  75. });
  76. it('should use existing identifier for control flow storage with expected chance', () => {
  77. assert.closeTo(usingExistingIdentifierChance, expectedChance, delta);
  78. });
  79. });
  80. });
  81. });