JavaScriptObfuscatorRuntime.spec.ts 11 KB

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