StringArrayCallsWrapperTemplate.spec.ts 15 KB

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