JavaScriptObfuscatorRuntime.spec.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. import { assert } from 'chai';
  2. import { TInputOptions } from '../../src/types/options/TInputOptions';
  3. import { StringArrayEncoding } from '../../src/enums/StringArrayEncoding';
  4. import { IdentifierNamesGenerator } from '../../src/enums/generators/identifier-names-generators/IdentifierNamesGenerator';
  5. import { evaluateInWorker } from '../helpers/evaluateInWorker';
  6. import { readFileAsString } from '../helpers/readFileAsString';
  7. import { JavaScriptObfuscator } from '../../src/JavaScriptObfuscatorFacade';
  8. const getEnvironmentCode = () => `
  9. global.document = {
  10. domain: 'obfuscator.io'
  11. };
  12. `;
  13. describe('JavaScriptObfuscator runtime eval', function () {
  14. const baseOptions: TInputOptions = {
  15. controlFlowFlattening: true,
  16. controlFlowFlatteningThreshold: 1,
  17. deadCodeInjection: true,
  18. deadCodeInjectionThreshold: 1,
  19. debugProtection: true,
  20. disableConsoleOutput: true,
  21. domainLock: ['obfuscator.io'],
  22. numbersToExpressions: true,
  23. simplify: true,
  24. renameProperties: true,
  25. reservedNames: ['generate', 'sha256'],
  26. rotateStringArray: true,
  27. selfDefending: true,
  28. splitStrings: true,
  29. splitStringsChunkLength: 1,
  30. stringArray: true,
  31. stringArrayEncoding: [
  32. StringArrayEncoding.None,
  33. StringArrayEncoding.Base64,
  34. StringArrayEncoding.Rc4
  35. ],
  36. stringArrayIntermediateCalls: 20,
  37. stringArrayThreshold: 1,
  38. transformObjectKeys: true,
  39. unicodeEscapeSequence: true
  40. };
  41. this.timeout(200000);
  42. [
  43. {
  44. identifierNamesGenerator: IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator,
  45. renameGlobals: false
  46. },
  47. {
  48. identifierNamesGenerator: IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator,
  49. renameGlobals: true
  50. },
  51. {
  52. identifierNamesGenerator: IdentifierNamesGenerator.MangledIdentifierNamesGenerator,
  53. renameGlobals: false
  54. },
  55. {
  56. identifierNamesGenerator: IdentifierNamesGenerator.MangledIdentifierNamesGenerator,
  57. renameGlobals: true
  58. },
  59. {
  60. identifierNamesGenerator: IdentifierNamesGenerator.MangledShuffledIdentifierNamesGenerator,
  61. renameGlobals: false
  62. },
  63. {
  64. identifierNamesGenerator: IdentifierNamesGenerator.MangledShuffledIdentifierNamesGenerator,
  65. renameGlobals: true
  66. }
  67. ].forEach((options: Partial<TInputOptions>) => {
  68. const detailedDescription: string = `Identifier names generator: ${options.identifierNamesGenerator}, rename globals: ${options.renameGlobals?.toString()}`;
  69. describe(`Astring. ${detailedDescription}`, () => {
  70. it('should obfuscate code without any runtime errors after obfuscation: Variant #1 astring', () => {
  71. const code: string = readFileAsString(__dirname + '/fixtures/astring.js');
  72. const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
  73. code,
  74. {
  75. ...baseOptions,
  76. ...options,
  77. renameProperties: false
  78. }
  79. ).getObfuscatedCode();
  80. let evaluationResult: string;
  81. try {
  82. evaluationResult = eval(`
  83. ${getEnvironmentCode()}
  84. ${obfuscatedCode}
  85. const code = generate({
  86. "type": "Program",
  87. "body": [
  88. {
  89. "type": "FunctionDeclaration",
  90. "id": {
  91. "type": "Identifier",
  92. "name": "test",
  93. "range": [
  94. 9,
  95. 13
  96. ]
  97. },
  98. "params": [],
  99. "body": {
  100. "type": "BlockStatement",
  101. "body": [
  102. {
  103. "type": "ReturnStatement",
  104. "argument": {
  105. "type": "Literal",
  106. "value": "foo",
  107. "raw": "'foo'",
  108. "range": [
  109. 30,
  110. 35
  111. ]
  112. },
  113. "range": [
  114. 23,
  115. 36
  116. ]
  117. }
  118. ],
  119. "range": [
  120. 17,
  121. 38
  122. ]
  123. },
  124. "generator": false,
  125. "expression": false,
  126. "async": false,
  127. "range": [
  128. 0,
  129. 38
  130. ]
  131. }
  132. ],
  133. "sourceType": "module",
  134. "range": [
  135. 0,
  136. 38
  137. ],
  138. "comments": []
  139. });
  140. eval(\`\${code} test();\`);
  141. `)
  142. } catch (e) {
  143. throw new Error(`Evaluation error: ${e.message}. Code: ${obfuscatedCode}`);
  144. }
  145. assert.equal(evaluationResult, 'foo');
  146. });
  147. });
  148. describe(`Sha256. ${detailedDescription}`, () => {
  149. it('should obfuscate code without any runtime errors after obfuscation: Variant #2 sha256', () => {
  150. const code: string = readFileAsString(__dirname + '/fixtures/sha256.js');
  151. const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
  152. code,
  153. {
  154. ...baseOptions,
  155. ...options
  156. }
  157. ).getObfuscatedCode();
  158. assert.equal(
  159. eval(`
  160. ${getEnvironmentCode()}
  161. ${obfuscatedCode}
  162. sha256('test');
  163. `),
  164. '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08'
  165. );
  166. });
  167. });
  168. describe(`Obfuscator. ${detailedDescription}`, () => {
  169. const evaluationTimeout: number = 50000;
  170. let evaluationResult: string;
  171. beforeEach(() => {
  172. const code: string = readFileAsString(process.cwd() + '/dist/index.js');
  173. const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
  174. code,
  175. {
  176. ...baseOptions,
  177. ...options,
  178. renameProperties: false
  179. }
  180. ).getObfuscatedCode();
  181. return evaluateInWorker(
  182. `
  183. ${getEnvironmentCode()}
  184. ${obfuscatedCode}
  185. module.exports.obfuscate('var foo = 1;').getObfuscatedCode();
  186. `,
  187. evaluationTimeout
  188. )
  189. .then((result: string | null) => {
  190. if (!result) {
  191. return;
  192. }
  193. evaluationResult = result;
  194. })
  195. .catch((error: Error) => {
  196. evaluationResult = `${error.message}. ${error.stack}. Code: ${obfuscatedCode}`;
  197. });
  198. });
  199. it('should obfuscate code without any runtime errors after obfuscation: Variant #3 obfuscator', () => {
  200. assert.equal(
  201. evaluationResult,
  202. 'var foo=0x1;'
  203. );
  204. });
  205. });
  206. [
  207. {
  208. debugProtection: false,
  209. selfDefending: false,
  210. stringArray: true
  211. },
  212. {
  213. debugProtection: false,
  214. selfDefending: true,
  215. stringArray: false
  216. },
  217. {
  218. debugProtection: true,
  219. selfDefending: false,
  220. stringArray: false
  221. },
  222. {
  223. debugProtection: true,
  224. selfDefending: true,
  225. stringArray: false
  226. },
  227. {
  228. debugProtection: true,
  229. selfDefending: true,
  230. stringArray: true
  231. }
  232. ].forEach((webpackBootstrapOptions: Partial<TInputOptions>) => {
  233. describe(`Webpack bootstrap code. ${detailedDescription}. ${JSON.stringify(webpackBootstrapOptions)}`, () => {
  234. let evaluationResult: string;
  235. beforeEach(() => {
  236. const code: string = readFileAsString(__dirname + '/fixtures/webpack-bootstrap.js');
  237. const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
  238. code,
  239. {
  240. ...baseOptions,
  241. ...options,
  242. ...webpackBootstrapOptions,
  243. reservedNames: ['^foo$']
  244. }
  245. ).getObfuscatedCode();
  246. try {
  247. evaluationResult = eval(`
  248. ${getEnvironmentCode()}
  249. ${obfuscatedCode}
  250. `);
  251. } catch (e) {
  252. throw new Error(`Evaluation error: ${e.message}. Code: ${obfuscatedCode}`);
  253. }
  254. });
  255. it('should obfuscate code without any runtime errors after obfuscation: Variant #4 webpack bootstrap', () => {
  256. assert.equal(evaluationResult, 'foo');
  257. });
  258. });
  259. });
  260. });
  261. });