StringArrayCallsWrapperTemplate.spec.ts 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. import 'reflect-metadata';
  2. import format from 'string-template';
  3. import { assert } from 'chai';
  4. import { ServiceIdentifiers } from '../../../../../../src/container/ServiceIdentifiers';
  5. import { ICryptUtilsStringArray } from '../../../../../../src/interfaces/utils/ICryptUtilsStringArray';
  6. import { IInversifyContainerFacade } from '../../../../../../src/interfaces/container/IInversifyContainerFacade';
  7. import { IObfuscatedCode } from '../../../../../../src/interfaces/source-code/IObfuscatedCode';
  8. import { IRandomGenerator } from '../../../../../../src/interfaces/utils/IRandomGenerator';
  9. import { AtobTemplate } from '../../../../../../src/custom-code-helpers/string-array/templates/string-array-calls-wrapper/AtobTemplate';
  10. import { Rc4Template } from '../../../../../../src/custom-code-helpers/string-array/templates/string-array-calls-wrapper/Rc4Template';
  11. import { StringArrayBase64DecodeTemplate } from '../../../../../../src/custom-code-helpers/string-array/templates/string-array-calls-wrapper/StringArrayBase64DecodeTemplate';
  12. import { StringArrayCallsWrapperTemplate } from '../../../../../../src/custom-code-helpers/string-array/templates/string-array-calls-wrapper/StringArrayCallsWrapperTemplate';
  13. import { StringArrayRC4DecodeTemplate } from '../../../../../../src/custom-code-helpers/string-array/templates/string-array-calls-wrapper/StringArrayRC4DecodeTemplate';
  14. import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../../src/options/presets/NoCustomNodes';
  15. import { InversifyContainerFacade } from '../../../../../../src/container/InversifyContainerFacade';
  16. import { JavaScriptObfuscator } from '../../../../../../src/JavaScriptObfuscatorFacade';
  17. import { readFileAsString } from '../../../../../helpers/readFileAsString';
  18. import { swapLettersCase } from '../../../../../helpers/swapLettersCase';
  19. describe('StringArrayCallsWrapperTemplate', () => {
  20. const stringArrayName: string = 'stringArrayName';
  21. const stringArrayCallsWrapperName: string = 'stringArrayCallsWrapperName';
  22. const atobFunctionName: string = 'atob';
  23. let cryptUtilsSwappedAlphabet: ICryptUtilsStringArray,
  24. randomGenerator: IRandomGenerator;
  25. before(() => {
  26. const inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade();
  27. inversifyContainerFacade.load('', '', {});
  28. cryptUtilsSwappedAlphabet = inversifyContainerFacade
  29. .get<ICryptUtilsStringArray>(ServiceIdentifiers.ICryptUtilsStringArray);
  30. randomGenerator = inversifyContainerFacade
  31. .get<IRandomGenerator>(ServiceIdentifiers.IRandomGenerator);
  32. });
  33. describe('Variant #1: `base64` encoding', () => {
  34. describe('Variant #1: index shift amount is `0`', () => {
  35. const index: string = '0x0';
  36. const indexShiftAmount: number = 0;
  37. const expectedDecodedValue: string = 'test1';
  38. let decodedValue: string;
  39. before(() => {
  40. const atobPolyfill = format(AtobTemplate(), {
  41. atobFunctionName
  42. });
  43. const atobDecodeTemplate: string = format(
  44. StringArrayBase64DecodeTemplate(randomGenerator),
  45. {
  46. atobPolyfill,
  47. atobFunctionName,
  48. selfDefendingCode: '',
  49. stringArrayCallsWrapperName
  50. }
  51. );
  52. const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), {
  53. decodeCodeHelperTemplate: atobDecodeTemplate,
  54. indexShiftAmount,
  55. stringArrayCallsWrapperName,
  56. stringArrayName
  57. });
  58. decodedValue = Function(`
  59. var ${stringArrayName} = ['${cryptUtilsSwappedAlphabet.btoa('test1')}'];
  60. ${stringArrayCallsWrapperTemplate}
  61. return ${stringArrayCallsWrapperName}(${index});
  62. `)();
  63. });
  64. it('should correctly return decoded value', () => {
  65. assert.deepEqual(decodedValue, expectedDecodedValue);
  66. });
  67. });
  68. describe('Variant #2: index shift amount is `5`', () => {
  69. const index: string = '0x5';
  70. const indexShiftAmount: number = 5;
  71. const expectedDecodedValue: string = 'test1';
  72. let decodedValue: string;
  73. before(() => {
  74. const atobPolyfill = format(AtobTemplate(), {
  75. atobFunctionName
  76. });
  77. const atobDecodeTemplate: string = format(
  78. StringArrayBase64DecodeTemplate(randomGenerator),
  79. {
  80. atobPolyfill,
  81. atobFunctionName,
  82. selfDefendingCode: '',
  83. stringArrayCallsWrapperName
  84. }
  85. );
  86. const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), {
  87. decodeCodeHelperTemplate: atobDecodeTemplate,
  88. indexShiftAmount,
  89. stringArrayCallsWrapperName,
  90. stringArrayName
  91. });
  92. decodedValue = Function(`
  93. var ${stringArrayName} = ['${cryptUtilsSwappedAlphabet.btoa('test1')}'];
  94. ${stringArrayCallsWrapperTemplate}
  95. return ${stringArrayCallsWrapperName}(${index});
  96. `)();
  97. });
  98. it('should correctly return decoded value', () => {
  99. assert.deepEqual(decodedValue, expectedDecodedValue);
  100. });
  101. });
  102. describe('Variant #3: no regexp inside atob template', () => {
  103. const indexShiftAmount: number = 0;
  104. const expectedRegExpTestValue: string = '12345';
  105. let decodedValue: string;
  106. before(() => {
  107. const atobPolyfill = format(AtobTemplate(), {
  108. atobFunctionName
  109. });
  110. const atobDecodeTemplate: string = format(
  111. StringArrayBase64DecodeTemplate(randomGenerator),
  112. {
  113. atobPolyfill,
  114. atobFunctionName,
  115. selfDefendingCode: '',
  116. stringArrayCallsWrapperName
  117. }
  118. );
  119. const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), {
  120. decodeCodeHelperTemplate: atobDecodeTemplate,
  121. indexShiftAmount,
  122. stringArrayCallsWrapperName,
  123. stringArrayName
  124. });
  125. decodedValue = Function(`
  126. var ${stringArrayName} = ['${swapLettersCase('c3RyaQ==')}'];
  127. ${stringArrayCallsWrapperTemplate}
  128. /(.+)/.test("12345");
  129. ${stringArrayCallsWrapperName}(0x0);
  130. return RegExp.$1;
  131. `)();
  132. });
  133. it('should correctly return RegExp.$1 match without mutation by atob template', () => {
  134. assert.deepEqual(decodedValue, expectedRegExpTestValue);
  135. });
  136. });
  137. });
  138. describe('Variant #2: `rc4` encoding', () => {
  139. describe('Variant #1: index shift amount is `0`', () => {
  140. const index: string = '0x0';
  141. const key: string = 'key';
  142. const indexShiftAmount: number = 0;
  143. const expectedDecodedValue: string = 'test1';
  144. let decodedValue: string;
  145. before(() => {
  146. const atobPolyfill = format(AtobTemplate(), {
  147. atobFunctionName
  148. });
  149. const rc4Polyfill = format(Rc4Template(), {
  150. atobFunctionName
  151. });
  152. const rc4decodeCodeHelperTemplate: string = format(
  153. StringArrayRC4DecodeTemplate(randomGenerator),
  154. {
  155. atobPolyfill,
  156. rc4Polyfill,
  157. selfDefendingCode: '',
  158. stringArrayCallsWrapperName
  159. }
  160. );
  161. const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), {
  162. decodeCodeHelperTemplate: rc4decodeCodeHelperTemplate,
  163. indexShiftAmount,
  164. stringArrayCallsWrapperName,
  165. stringArrayName
  166. });
  167. decodedValue = Function(`
  168. var ${stringArrayName} = ['${cryptUtilsSwappedAlphabet.btoa(cryptUtilsSwappedAlphabet.rc4('test1', key))}'];
  169. ${stringArrayCallsWrapperTemplate}
  170. return ${stringArrayCallsWrapperName}('${index}', '${key}');
  171. `)();
  172. });
  173. it('should correctly return decoded value', () => {
  174. assert.deepEqual(decodedValue, expectedDecodedValue);
  175. });
  176. });
  177. describe('Variant #2: index shift amount is `5`', () => {
  178. const index: string = '0x5';
  179. const key: string = 'key';
  180. const indexShiftAmount: number = 5;
  181. const expectedDecodedValue: string = 'test1';
  182. let decodedValue: string;
  183. before(() => {
  184. const atobPolyfill = format(AtobTemplate(), {
  185. atobFunctionName
  186. });
  187. const rc4Polyfill = format(Rc4Template(), {
  188. atobFunctionName
  189. });
  190. const rc4decodeCodeHelperTemplate: string = format(
  191. StringArrayRC4DecodeTemplate(randomGenerator),
  192. {
  193. atobPolyfill,
  194. rc4Polyfill,
  195. selfDefendingCode: '',
  196. stringArrayCallsWrapperName
  197. }
  198. );
  199. const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), {
  200. decodeCodeHelperTemplate: rc4decodeCodeHelperTemplate,
  201. indexShiftAmount,
  202. stringArrayCallsWrapperName,
  203. stringArrayName
  204. });
  205. decodedValue = Function(`
  206. var ${stringArrayName} = ['${cryptUtilsSwappedAlphabet.btoa(cryptUtilsSwappedAlphabet.rc4('test1', key))}'];
  207. ${stringArrayCallsWrapperTemplate}
  208. return ${stringArrayCallsWrapperName}('${index}', '${key}');
  209. `)();
  210. });
  211. it('should correctly return decoded value', () => {
  212. assert.deepEqual(decodedValue, expectedDecodedValue);
  213. });
  214. });
  215. });
  216. describe('Prevailing kind of variables', () => {
  217. describe('`var` kind', () => {
  218. let obfuscatedCode: string,
  219. stringArrayCallsWrapperVariableRegExp: RegExp = /var (_0x(\w){4,6}) *= *(_0x(\w){4,6})\[(_0x(\w){4,6})];/;
  220. beforeEach(() => {
  221. const code: string = readFileAsString(__dirname + '/fixtures/prevailing-kind-of-variables-var.js');
  222. const obfuscatedCodeObject: IObfuscatedCode = JavaScriptObfuscator.obfuscate(
  223. code,
  224. {
  225. ...NO_ADDITIONAL_NODES_PRESET,
  226. stringArray: true,
  227. stringArrayThreshold: 1
  228. }
  229. );
  230. obfuscatedCode = obfuscatedCodeObject.getObfuscatedCode();
  231. });
  232. it('Should return correct kind of variables for string array calls wrapper code', () => {
  233. assert.match(obfuscatedCode, stringArrayCallsWrapperVariableRegExp);
  234. });
  235. it('Should does not break on obfuscating', () => {
  236. assert.doesNotThrow(() => obfuscatedCode);
  237. });
  238. });
  239. describe('`const` kind', () => {
  240. let obfuscatedCode: string,
  241. stringArrayCallsWrapperVariableRegExp: RegExp = /let (_0x(\w){4,6}) *= *(_0x(\w){4,6})\[(_0x(\w){4,6})];/;
  242. beforeEach(() => {
  243. const code: string = readFileAsString(__dirname + '/fixtures/prevailing-kind-of-variables-const.js');
  244. const obfuscatedCodeObject: IObfuscatedCode = JavaScriptObfuscator.obfuscate(
  245. code,
  246. {
  247. ...NO_ADDITIONAL_NODES_PRESET,
  248. stringArray: true,
  249. stringArrayThreshold: 1
  250. }
  251. );
  252. obfuscatedCode = obfuscatedCodeObject.getObfuscatedCode();
  253. });
  254. it('Should return correct kind of variables for string array calls wrapper code', () => {
  255. assert.match(obfuscatedCode, stringArrayCallsWrapperVariableRegExp);
  256. });
  257. it('Should does not break on obfuscating', () => {
  258. assert.doesNotThrow(() => obfuscatedCode);
  259. });
  260. });
  261. describe('`let` kind', () => {
  262. let obfuscatedCode: string,
  263. stringArrayCallsWrapperVariableRegExp: RegExp = /let (_0x(\w){4,6}) *= *(_0x(\w){4,6})\[(_0x(\w){4,6})];/;
  264. beforeEach(() => {
  265. const code: string = readFileAsString(__dirname + '/fixtures/prevailing-kind-of-variables-let.js');
  266. const obfuscatedCodeObject: IObfuscatedCode = JavaScriptObfuscator.obfuscate(
  267. code,
  268. {
  269. ...NO_ADDITIONAL_NODES_PRESET,
  270. stringArray: true,
  271. stringArrayThreshold: 1
  272. }
  273. );
  274. obfuscatedCode = obfuscatedCodeObject.getObfuscatedCode();
  275. });
  276. it('Should return correct kind of variables for string array calls wrapper code', () => {
  277. assert.match(obfuscatedCode, stringArrayCallsWrapperVariableRegExp);
  278. });
  279. it('Should does not break on obfuscating', () => {
  280. assert.doesNotThrow(() => obfuscatedCode);
  281. });
  282. });
  283. });
  284. });