StringArrayStorage.spec.ts 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  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('StringArrayStorage', () => {
  6. describe('Rotate string array', function () {
  7. this.timeout(100000);
  8. describe('Variant #1: single string array value', () => {
  9. const samples: number = 1000;
  10. const delta: number = 0.1;
  11. const expectedVariantProbability: number = 1;
  12. const stringArrayVariant1RegExp1: RegExp = /var _0x([a-f0-9]){4} *= *\['test'];/g;
  13. const literalNodeVariant1RegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\('0x0'\);/g;
  14. let stringArrayVariant1Probability: number,
  15. literalNodeVariant1Probability: number;
  16. before(() => {
  17. const code: string = readFileAsString(__dirname + '/fixtures/one-string.js');
  18. let stringArrayVariant1MatchesLength: number = 0;
  19. let literalNodeVariant1MatchesLength: number = 0;
  20. for (let i = 0; i < samples; i++) {
  21. const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
  22. code,
  23. {
  24. ...NO_ADDITIONAL_NODES_PRESET,
  25. rotateStringArray: true,
  26. stringArray: true,
  27. stringArrayThreshold: 1
  28. }
  29. ).getObfuscatedCode();
  30. if (obfuscatedCode.match(stringArrayVariant1RegExp1)) {
  31. stringArrayVariant1MatchesLength++;
  32. }
  33. if (obfuscatedCode.match(literalNodeVariant1RegExp)) {
  34. literalNodeVariant1MatchesLength++;
  35. }
  36. }
  37. stringArrayVariant1Probability = stringArrayVariant1MatchesLength / samples;
  38. literalNodeVariant1Probability = literalNodeVariant1MatchesLength / samples;
  39. });
  40. describe('String array probability', () => {
  41. it('Variant #1: should create single string array variant', () => {
  42. assert.closeTo(stringArrayVariant1Probability, expectedVariantProbability, delta);
  43. });
  44. });
  45. describe('Literal node probability', () => {
  46. it('Variant #1: should replace literal node with call to string array variant', () => {
  47. assert.closeTo(literalNodeVariant1Probability, expectedVariantProbability, delta);
  48. });
  49. });
  50. });
  51. describe('Variant #2: Three string array values', () => {
  52. const samples: number = 1000;
  53. const delta: number = 0.1;
  54. const expectedStringArrayVariantProbability: number = 0.33;
  55. const expectedLiteralNodeVariantProbability: number = 1;
  56. const stringArrayVariantsCount: number = 3;
  57. const literalNodeVariantsCount: number = 1;
  58. const stringArrayVariantRegExps: RegExp[] = [
  59. /var _0x([a-f0-9]){4} *= *\['foo', *'bar', *'baz'];/g,
  60. /var _0x([a-f0-9]){4} *= *\['bar', *'baz', *'foo'];/g,
  61. /var _0x([a-f0-9]){4} *= *\['baz', *'foo', *'bar'];/g
  62. ];
  63. const literalNodeVariantRegExps: RegExp[] = [
  64. new RegExp(
  65. `var foo *= *_0x([a-f0-9]){4}\\('0x0'\\); *` +
  66. `var bar *= *_0x([a-f0-9]){4}\\('0x1'\\); *` +
  67. `var baz *= *_0x([a-f0-9]){4}\\('0x2'\\);`
  68. )
  69. ];
  70. const stringArrayVariantProbabilities: number[] = new Array(stringArrayVariantsCount).fill(0);
  71. const literalNodeVariantProbabilities: number[] = new Array(literalNodeVariantsCount).fill(0);
  72. const stringArrayVariantMatchesLength: number[] = new Array(stringArrayVariantsCount).fill(0);
  73. const literalNodeVariantMatchesLength: number[] = new Array(literalNodeVariantsCount).fill(0);
  74. before(() => {
  75. const code: string = readFileAsString(__dirname + '/fixtures/three-strings.js');
  76. for (let i = 0; i < samples; i++) {
  77. const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
  78. code,
  79. {
  80. ...NO_ADDITIONAL_NODES_PRESET,
  81. rotateStringArray: true,
  82. stringArray: true,
  83. stringArrayThreshold: 1
  84. }
  85. ).getObfuscatedCode();
  86. for (let variantIndex = 0; variantIndex < stringArrayVariantsCount; variantIndex++) {
  87. if (obfuscatedCode.match(stringArrayVariantRegExps[variantIndex])) {
  88. stringArrayVariantMatchesLength[variantIndex]++;
  89. }
  90. if (obfuscatedCode.match(literalNodeVariantRegExps[variantIndex])) {
  91. literalNodeVariantMatchesLength[variantIndex]++;
  92. }
  93. }
  94. }
  95. for (let variantIndex = 0; variantIndex < stringArrayVariantsCount; variantIndex++) {
  96. stringArrayVariantProbabilities[variantIndex] = stringArrayVariantMatchesLength[variantIndex] / samples;
  97. }
  98. for (let variantIndex = 0; variantIndex < literalNodeVariantsCount; variantIndex++) {
  99. literalNodeVariantProbabilities[variantIndex] = literalNodeVariantMatchesLength[variantIndex] / samples;
  100. }
  101. });
  102. describe('String array probability', () => {
  103. for (let variantIndex = 0; variantIndex < stringArrayVariantsCount; variantIndex++) {
  104. const variantNumber: number = variantIndex + 1;
  105. it(`Variant #${variantNumber}: should create string array variant`, () => {
  106. assert.closeTo(stringArrayVariantProbabilities[variantIndex], expectedStringArrayVariantProbability, delta);
  107. });
  108. }
  109. });
  110. describe('Literal node probability', () => {
  111. for (let variantIndex = 0; variantIndex < literalNodeVariantsCount; variantIndex++) {
  112. const variantNumber: number = variantIndex + 1;
  113. it(`Variant #${variantNumber}: should replace literal node with call to string array variant`, () => {
  114. assert.closeTo(literalNodeVariantProbabilities[variantIndex], expectedLiteralNodeVariantProbability, delta);
  115. });
  116. }
  117. });
  118. });
  119. });
  120. describe('Shuffle string array', function () {
  121. this.timeout(100000);
  122. describe('Variant #1: single string array value', () => {
  123. const samples: number = 1000;
  124. const delta: number = 0.1;
  125. const expectedVariantProbability: number = 1;
  126. const stringArrayVariantRegExp1: RegExp = /var _0x([a-f0-9]){4} *= *\['test'];/g;
  127. const literalNodeVariant1RegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\('0x0'\);/g;
  128. let stringArrayVariant1Probability: number,
  129. literalNodeVariant1Probability: number;
  130. before(() => {
  131. const code: string = readFileAsString(__dirname + '/fixtures/one-string.js');
  132. let stringArrayVariant1MatchesLength: number = 0;
  133. let literalNodeVariant1MatchesLength: number = 0;
  134. for (let i = 0; i < samples; i++) {
  135. const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
  136. code,
  137. {
  138. ...NO_ADDITIONAL_NODES_PRESET,
  139. shuffleStringArray: true,
  140. stringArray: true,
  141. stringArrayThreshold: 1
  142. }
  143. ).getObfuscatedCode();
  144. if (obfuscatedCode.match(stringArrayVariantRegExp1)) {
  145. stringArrayVariant1MatchesLength++;
  146. }
  147. if (obfuscatedCode.match(literalNodeVariant1RegExp)) {
  148. literalNodeVariant1MatchesLength++;
  149. }
  150. }
  151. stringArrayVariant1Probability = stringArrayVariant1MatchesLength / samples;
  152. literalNodeVariant1Probability = literalNodeVariant1MatchesLength / samples;
  153. });
  154. describe('String array probability', () => {
  155. it('Variant #1: should create string array variant', () => {
  156. assert.closeTo(stringArrayVariant1Probability, expectedVariantProbability, delta);
  157. });
  158. });
  159. describe('Literal node probability', () => {
  160. it('Variant #1: should replace literal node with call to string array variant', () => {
  161. assert.closeTo(literalNodeVariant1Probability, expectedVariantProbability, delta);
  162. });
  163. });
  164. });
  165. describe('Variant #2: Three string array values', () => {
  166. const samples: number = 1000;
  167. const delta: number = 0.1;
  168. const expectedVariantProbability: number = 0.166;
  169. const variantsCount: number = 6;
  170. const stringArrayVariantRegExps: RegExp[] = [
  171. /var _0x([a-f0-9]){4} *= *\['foo', *'bar', *'baz'];/g,
  172. /var _0x([a-f0-9]){4} *= *\['foo', *'baz', *'bar'];/g,
  173. /var _0x([a-f0-9]){4} *= *\['bar', *'foo', *'baz'];/g,
  174. /var _0x([a-f0-9]){4} *= *\['bar', *'baz', *'foo'];/g,
  175. /var _0x([a-f0-9]){4} *= *\['baz', *'foo', *'bar'];/g,
  176. /var _0x([a-f0-9]){4} *= *\['baz', *'bar', *'foo'];/g
  177. ];
  178. const literalNodeVariantRegExps: RegExp[] = [
  179. new RegExp(
  180. `var foo *= *_0x([a-f0-9]){4}\\('0x0'\\); *` +
  181. `var bar *= *_0x([a-f0-9]){4}\\('0x1'\\); *` +
  182. `var baz *= *_0x([a-f0-9]){4}\\('0x2'\\);`
  183. ),
  184. new RegExp(
  185. `var foo *= *_0x([a-f0-9]){4}\\('0x0'\\); *` +
  186. `var bar *= *_0x([a-f0-9]){4}\\('0x2'\\); *` +
  187. `var baz *= *_0x([a-f0-9]){4}\\('0x1'\\);`
  188. ),
  189. new RegExp(
  190. `var foo *= *_0x([a-f0-9]){4}\\('0x1'\\); *` +
  191. `var bar *= *_0x([a-f0-9]){4}\\('0x0'\\); *` +
  192. `var baz *= *_0x([a-f0-9]){4}\\('0x2'\\);`
  193. ),
  194. new RegExp(
  195. `var foo *= *_0x([a-f0-9]){4}\\('0x1'\\); *` +
  196. `var bar *= *_0x([a-f0-9]){4}\\('0x2'\\); *` +
  197. `var baz *= *_0x([a-f0-9]){4}\\('0x0'\\);`
  198. ),
  199. new RegExp(
  200. `var foo *= *_0x([a-f0-9]){4}\\('0x2'\\); *` +
  201. `var bar *= *_0x([a-f0-9]){4}\\('0x0'\\); *` +
  202. `var baz *= *_0x([a-f0-9]){4}\\('0x1'\\);`
  203. ),
  204. new RegExp(
  205. `var foo *= *_0x([a-f0-9]){4}\\('0x2'\\); *` +
  206. `var bar *= *_0x([a-f0-9]){4}\\('0x1'\\); *` +
  207. `var baz *= *_0x([a-f0-9]){4}\\('0x0'\\);`
  208. )
  209. ];
  210. const stringArrayVariantProbabilities: number[] = new Array(variantsCount).fill(0);
  211. const literalNodeVariantProbabilities: number[] = new Array(variantsCount).fill(0);
  212. const stringArrayVariantMatchesLength: number[] = new Array(variantsCount).fill(0);
  213. const literalNodeVariantMatchesLength: number[] = new Array(variantsCount).fill(0);
  214. before(() => {
  215. const code: string = readFileAsString(__dirname + '/fixtures/three-strings.js');
  216. for (let i = 0; i < samples; i++) {
  217. const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
  218. code,
  219. {
  220. ...NO_ADDITIONAL_NODES_PRESET,
  221. shuffleStringArray: true,
  222. stringArray: true,
  223. stringArrayThreshold: 1
  224. }
  225. ).getObfuscatedCode();
  226. for (let variantIndex = 0; variantIndex < variantsCount; variantIndex++) {
  227. if (obfuscatedCode.match(stringArrayVariantRegExps[variantIndex])) {
  228. stringArrayVariantMatchesLength[variantIndex]++;
  229. }
  230. if (obfuscatedCode.match(literalNodeVariantRegExps[variantIndex])) {
  231. literalNodeVariantMatchesLength[variantIndex]++;
  232. }
  233. }
  234. }
  235. for (let variantIndex = 0; variantIndex < variantsCount; variantIndex++) {
  236. stringArrayVariantProbabilities[variantIndex] = stringArrayVariantMatchesLength[variantIndex] / samples;
  237. literalNodeVariantProbabilities[variantIndex] = literalNodeVariantMatchesLength[variantIndex] / samples;
  238. }
  239. });
  240. for (let variantIndex = 0; variantIndex < variantsCount; variantIndex++) {
  241. const variantNumber: number = variantIndex + 1;
  242. it(`Variant #${variantNumber}: should create string array variant`, () => {
  243. assert.closeTo(stringArrayVariantProbabilities[variantIndex], expectedVariantProbability, delta);
  244. });
  245. it(`Variant #${variantNumber}: should replace literal node with call to string array variant`, () => {
  246. assert.closeTo(literalNodeVariantProbabilities[variantIndex], expectedVariantProbability, delta);
  247. });
  248. }
  249. });
  250. });
  251. });