JavaScriptObfuscatorRuntime.spec.ts 10 KB

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