JavaScriptObfuscatorRuntime.spec.ts 11 KB

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