js-confuser 1.2.1 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/CHANGELOG.md +171 -0
  2. package/README.md +7 -6
  3. package/dist/options.js +5 -1
  4. package/dist/parser.js +1 -2
  5. package/dist/presets.js +2 -2
  6. package/dist/transforms/calculator.js +48 -60
  7. package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +482 -95
  8. package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +4 -0
  9. package/dist/transforms/controlFlowFlattening/{switchCaseObfucation.js → switchCaseObfuscation.js} +2 -2
  10. package/dist/transforms/deadCode.js +1 -1
  11. package/dist/transforms/dispatcher.js +14 -13
  12. package/dist/transforms/extraction/duplicateLiteralsRemoval.js +5 -10
  13. package/dist/transforms/flatten.js +5 -1
  14. package/dist/transforms/hideInitializingCode.js +17 -2
  15. package/dist/transforms/identifier/globalConcealing.js +46 -25
  16. package/dist/transforms/identifier/movedDeclarations.js +69 -68
  17. package/dist/transforms/identifier/renameVariables.js +22 -98
  18. package/dist/transforms/identifier/variableAnalysis.js +133 -0
  19. package/dist/transforms/label.js +11 -2
  20. package/dist/transforms/lock/antiDebug.js +32 -13
  21. package/dist/transforms/lock/lock.js +13 -2
  22. package/dist/transforms/minify.js +117 -120
  23. package/dist/transforms/opaquePredicates.js +4 -2
  24. package/dist/transforms/preparation/preparation.js +8 -0
  25. package/dist/transforms/renameLabels.js +17 -3
  26. package/dist/transforms/rgf.js +8 -3
  27. package/dist/transforms/shuffle.js +25 -9
  28. package/dist/transforms/stack.js +5 -9
  29. package/dist/transforms/string/encoding.js +209 -0
  30. package/dist/transforms/string/stringCompression.js +10 -10
  31. package/dist/transforms/string/stringConcealing.js +94 -65
  32. package/dist/transforms/string/stringSplitting.js +7 -7
  33. package/dist/transforms/transform.js +10 -0
  34. package/dist/traverse.js +1 -35
  35. package/dist/util/gen.js +3 -1
  36. package/dist/util/identifiers.js +9 -19
  37. package/dist/util/insert.js +6 -40
  38. package/dist/util/scope.js +17 -0
  39. package/package.json +2 -2
  40. package/src/options.ts +19 -3
  41. package/src/parser.ts +1 -2
  42. package/src/presets.ts +2 -2
  43. package/src/transforms/calculator.ts +87 -91
  44. package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +742 -142
  45. package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +6 -0
  46. package/src/transforms/controlFlowFlattening/{switchCaseObfucation.ts → switchCaseObfuscation.ts} +6 -2
  47. package/src/transforms/deadCode.ts +8 -0
  48. package/src/transforms/dispatcher.ts +29 -14
  49. package/src/transforms/extraction/duplicateLiteralsRemoval.ts +43 -19
  50. package/src/transforms/flatten.ts +15 -2
  51. package/src/transforms/hideInitializingCode.ts +432 -406
  52. package/src/transforms/identifier/globalConcealing.ts +148 -46
  53. package/src/transforms/identifier/movedDeclarations.ts +78 -101
  54. package/src/transforms/identifier/renameVariables.ts +21 -96
  55. package/src/transforms/identifier/variableAnalysis.ts +124 -0
  56. package/src/transforms/label.ts +20 -2
  57. package/src/transforms/lock/antiDebug.ts +69 -26
  58. package/src/transforms/lock/lock.ts +37 -3
  59. package/src/transforms/minify.ts +154 -130
  60. package/src/transforms/opaquePredicates.ts +25 -3
  61. package/src/transforms/preparation/preparation.ts +8 -1
  62. package/src/transforms/renameLabels.ts +26 -3
  63. package/src/transforms/rgf.ts +6 -1
  64. package/src/transforms/shuffle.ts +87 -29
  65. package/src/transforms/stack.ts +6 -8
  66. package/src/transforms/string/encoding.ts +310 -0
  67. package/src/transforms/string/stringCompression.ts +37 -24
  68. package/src/transforms/string/stringConcealing.ts +157 -160
  69. package/src/transforms/string/stringSplitting.ts +12 -8
  70. package/src/transforms/transform.ts +15 -2
  71. package/src/traverse.ts +1 -31
  72. package/src/util/gen.ts +5 -3
  73. package/src/util/identifiers.ts +20 -20
  74. package/src/util/insert.ts +12 -78
  75. package/src/util/scope.ts +9 -0
  76. package/test/{transforms/compare.test.ts → compare.test.ts} +2 -2
  77. package/test/index.test.ts +109 -1
  78. package/test/templates/template.test.ts +14 -0
  79. package/test/transforms/controlFlowFlattening/controlFlowFlattening.test.ts +392 -10
  80. package/test/transforms/dispatcher.test.ts +30 -0
  81. package/test/transforms/flatten.test.ts +28 -0
  82. package/test/transforms/hideInitializingCode.test.ts +336 -336
  83. package/test/transforms/identifier/globalConcealing.test.ts +1 -2
  84. package/test/transforms/identifier/movedDeclarations.test.ts +137 -112
  85. package/test/transforms/identifier/renameVariables.test.ts +124 -13
  86. package/test/transforms/lock/antiDebug.test.ts +43 -0
  87. package/test/transforms/lock/selfDefending.test.ts +68 -0
  88. package/test/transforms/minify.test.ts +137 -0
  89. package/test/transforms/renameLabels.test.ts +33 -0
  90. package/test/transforms/rgf.test.ts +29 -0
  91. package/test/transforms/string/stringSplitting.test.ts +33 -0
  92. package/test/util/identifiers.test.ts +105 -17
  93. package/dist/util/expr.js +0 -60
  94. package/src/util/expr.ts +0 -56
@@ -1,6 +1,6 @@
1
1
  import JsConfuser from "../../../src/index";
2
2
 
3
- it("should execute in the correct order (ControlFlowFlattening)", async () => {
3
+ test("Variant #1: Execute in the correct order (ControlFlowFlattening)", async () => {
4
4
  var code = `
5
5
  var array = [];
6
6
 
@@ -30,7 +30,7 @@ it("should execute in the correct order (ControlFlowFlattening)", async () => {
30
30
  eval(output);
31
31
  });
32
32
 
33
- it("should obfuscate for loops (ControlFlowObfuscation)", async () => {
33
+ test("Variant #2: Obfuscate for loops (ControlFlowObfuscation)", async () => {
34
34
  var code = `
35
35
  var array = [];
36
36
 
@@ -55,7 +55,7 @@ it("should obfuscate for loops (ControlFlowObfuscation)", async () => {
55
55
  eval(output);
56
56
  });
57
57
 
58
- it("should obfuscate while loops (ControlFlowObfuscation)", async () => {
58
+ test("Variant #3: Obfuscate while loops (ControlFlowObfuscation)", async () => {
59
59
  var code = `
60
60
  var array = [];
61
61
  var i = 1;
@@ -82,7 +82,7 @@ it("should obfuscate while loops (ControlFlowObfuscation)", async () => {
82
82
  eval(output);
83
83
  });
84
84
 
85
- it("should work with break statements", async () => {
85
+ test("Variant #4: Work with break statements", async () => {
86
86
  var code = `
87
87
 
88
88
  var TEST_ARRAY = [];
@@ -112,7 +112,7 @@ it("should work with break statements", async () => {
112
112
  eval(output);
113
113
  });
114
114
 
115
- it("should not obfuscate code with `let` (Lexically bound variables, ControlFlowFlattening)", async () => {
115
+ test("Variant #5: Don't obfuscate code with `let` (Lexically bound variables, ControlFlowFlattening)", async () => {
116
116
  var code = `
117
117
  let array = [];
118
118
 
@@ -138,7 +138,7 @@ it("should not obfuscate code with `let` (Lexically bound variables, ControlFlow
138
138
  expect(output).not.toContain("switch");
139
139
  });
140
140
 
141
- it("should not obfuscate code with `let` (Lexically bound variables, ControlFlowObfuscation)", async () => {
141
+ test("Variant #6: Don't obfuscate code with `let` (Lexically bound variables, ControlFlowObfuscation)", async () => {
142
142
  var code = `
143
143
  var array=[];
144
144
  for ( let i =1; i <= 10; i++ ) {
@@ -156,7 +156,7 @@ it("should not obfuscate code with `let` (Lexically bound variables, ControlFlow
156
156
  expect(output).not.toContain("switch");
157
157
  });
158
158
 
159
- it("should accept percentages", async () => {
159
+ test("Variant #7: Accept percentages", async () => {
160
160
  var code = `
161
161
  var array = [];
162
162
  var i = 1;
@@ -184,7 +184,7 @@ it("should accept percentages", async () => {
184
184
  eval(output);
185
185
  });
186
186
 
187
- it("should work when obfuscated multiple times", async () => {
187
+ it("Variant #8: Work when obfuscated multiple times", async () => {
188
188
  var code = `
189
189
  var array = [];
190
190
  var i = 1;
@@ -217,7 +217,7 @@ it("should work when obfuscated multiple times", async () => {
217
217
  eval(doublyObfuscated);
218
218
  });
219
219
 
220
- it("should not entangle floats or NaN", async () => {
220
+ test("Variant #9: Don't entangle floats or NaN", async () => {
221
221
  var output = await JsConfuser(
222
222
  `
223
223
  function TEST_FUNCTION(){
@@ -251,7 +251,7 @@ it("should not entangle floats or NaN", async () => {
251
251
  expect(value).toStrictEqual(25.02);
252
252
  });
253
253
 
254
- it("should correctly entangle property keys", async () => {
254
+ test("Variant #10: Correctly entangle property keys", async () => {
255
255
  var output = await JsConfuser(
256
256
  `
257
257
  function TEST_FUNCTION(){
@@ -290,3 +290,385 @@ it("should correctly entangle property keys", async () => {
290
290
  eval(output);
291
291
  expect(value).toStrictEqual(10);
292
292
  });
293
+
294
+ test("Variant #11: Flatten nested if statements", async () => {
295
+ var output = await JsConfuser(
296
+ `
297
+ TEST_ARRAY = [];
298
+
299
+ if(true){
300
+ TEST_ARRAY.push(1);
301
+ } else {
302
+ TEST_ARRAY.push(-1);
303
+ }
304
+
305
+ if(true){
306
+ TEST_ARRAY.push(2);
307
+ }
308
+
309
+ if(false){
310
+ TEST_ARRAY.push(-1);
311
+ }
312
+
313
+ if(true){
314
+ TEST_ARRAY.push(3);
315
+ if(true){
316
+ TEST_ARRAY.push(4);
317
+ } else {
318
+ TEST_ARRAY.push(-1);
319
+ }
320
+ TEST_ARRAY.push(5);
321
+ }
322
+ var fillerExpr1;
323
+ var fillerExpr2;
324
+ var fillerExpr3;
325
+ var fillerExpr4;
326
+ var fillerExpr5;
327
+ `,
328
+ {
329
+ target: "node",
330
+ controlFlowFlattening: true,
331
+ }
332
+ );
333
+
334
+ var TEST_ARRAY;
335
+
336
+ eval(output);
337
+ expect(TEST_ARRAY).toStrictEqual([1, 2, 3, 4, 5]);
338
+ });
339
+
340
+ test("Variant #12: Flatten nested for loops", async () => {
341
+ var output = await JsConfuser(
342
+ `
343
+ TEST_ARRAY = [];
344
+
345
+ for ( var i = -5; i < 0; i++ ) {
346
+ var o = 0;
347
+ for ( var j = 1; j < 4; j++ ) {
348
+ o += j;
349
+ }
350
+
351
+ // o is 6
352
+ TEST_ARRAY.push(i + o);
353
+ }
354
+ var fillerExpr1;
355
+ var fillerExpr2;
356
+ var fillerExpr3;
357
+ var fillerExpr4;
358
+ var fillerExpr5;
359
+ `,
360
+ {
361
+ target: "node",
362
+ controlFlowFlattening: true,
363
+ }
364
+ );
365
+
366
+ expect(output).not.toContain("for(var i)");
367
+ expect(output).not.toContain("for(var j)");
368
+
369
+ var TEST_ARRAY;
370
+
371
+ eval(output);
372
+ expect(TEST_ARRAY).toStrictEqual([1, 2, 3, 4, 5]);
373
+ });
374
+
375
+ test("Variant #13: Flatten nested while loops", async () => {
376
+ var output = await JsConfuser(
377
+ `
378
+ TEST_ARRAY = [];
379
+
380
+ var i = -5
381
+ while ( i < 0 ) {
382
+ var o = 0;
383
+ var j = 1;
384
+
385
+ while( j < 4 ){
386
+ o += j;
387
+
388
+ j++;
389
+ }
390
+
391
+ // o is 6
392
+ TEST_ARRAY.push(i + o);
393
+ i++;
394
+ }
395
+ var fillerExpr1;
396
+ var fillerExpr2;
397
+ var fillerExpr3;
398
+ var fillerExpr4;
399
+ var fillerExpr5;
400
+ `,
401
+ {
402
+ target: "node",
403
+ controlFlowFlattening: true,
404
+ }
405
+ );
406
+
407
+ var TEST_ARRAY;
408
+
409
+ expect(output).not.toContain("while(i<0)");
410
+ expect(output).not.toContain("while(j<4)");
411
+
412
+ eval(output);
413
+ expect(TEST_ARRAY).toStrictEqual([1, 2, 3, 4, 5]);
414
+ });
415
+
416
+ test("Variant #14: Flatten nested switch statements", async () => {
417
+ var output = await JsConfuser(
418
+ `
419
+ TEST_ARRAY = [];
420
+
421
+ var i = 0;
422
+ switch(i){
423
+ case 1: TEST_ARRAY.push(-1); break;
424
+ case 2: TEST_ARRAY.push(-1); break;
425
+ case 0:
426
+ TEST_ARRAY.push(1);
427
+
428
+ var j = 0;
429
+ var i = 0;
430
+ switch(j){
431
+ case 1: TEST_ARRAY.push(-1); break;
432
+ case 2: TEST_ARRAY.push(-1); break;
433
+ case 0:
434
+ TEST_ARRAY.push(2);
435
+ break;
436
+ case 4: TEST_ARRAY.push(-1); break;
437
+ case 8: TEST_ARRAY.push(-1); break;
438
+ }
439
+
440
+ TEST_ARRAY.push(3);
441
+
442
+ break;
443
+ case 4: TEST_ARRAY.push(-1); break;
444
+ case 8: TEST_ARRAY.push(-1); break;
445
+ }
446
+
447
+ TEST_ARRAY.push(4);
448
+ TEST_ARRAY.push(5);
449
+ `,
450
+ {
451
+ target: "node",
452
+ controlFlowFlattening: true,
453
+ }
454
+ );
455
+
456
+ expect(output).not.toContain("switch(i");
457
+ expect(output).not.toContain("switch(j");
458
+
459
+ var TEST_ARRAY;
460
+
461
+ eval(output);
462
+ expect(TEST_ARRAY).toStrictEqual([1, 2, 3, 4, 5]);
463
+ });
464
+
465
+ test("Variant #16: Flatten with nested break and continue statements", async () => {
466
+ var output = await JsConfuser(
467
+ `
468
+ TEST_ARRAY = [];
469
+
470
+ for ( var i =1; i < 10; i++ ) {
471
+ if(i%2==0){
472
+ continue;
473
+ }
474
+ if(i==7){
475
+ break;
476
+ }
477
+ TEST_ARRAY.push(i);
478
+ }
479
+
480
+ var j;
481
+
482
+ a: for ( var i = 0; i < 5; i++ ) {
483
+ if ( i == 3 ) {
484
+ for ( j = 0; j < 5; j++ ) {
485
+ if ( j == 1 ) {break a;}
486
+ if ( j % 2 == 0 ) { continue a;}
487
+ }
488
+ TEST_ARRAY.push(-1);
489
+ }
490
+ }
491
+
492
+ var fillerExpr1;
493
+ var fillerExpr2;
494
+ var fillerExpr3;
495
+ var fillerExpr4;
496
+ var fillerExpr5;
497
+ `,
498
+ {
499
+ target: "node",
500
+ controlFlowFlattening: true,
501
+ }
502
+ );
503
+
504
+ var TEST_ARRAY;
505
+
506
+ eval(output);
507
+ expect(TEST_ARRAY).toStrictEqual([1, 3, 5]);
508
+ });
509
+
510
+ test("Variant #17: Flatten with infinite for loop and break", async () => {
511
+ var output = await JsConfuser(
512
+ `
513
+ TEST_ARRAY = [];
514
+ var i = 1;
515
+
516
+ for ( ;; ) {
517
+ if (i == 6){break;}
518
+
519
+ TEST_ARRAY.push(i), i++;
520
+ }
521
+
522
+ var fillerExpr1;
523
+ var fillerExpr2;
524
+ var fillerExpr3;
525
+ var fillerExpr4;
526
+ var fillerExpr5;
527
+ `,
528
+ {
529
+ target: "node",
530
+ controlFlowFlattening: true,
531
+ }
532
+ );
533
+
534
+ expect(output).not.toContain("for(;");
535
+
536
+ var TEST_ARRAY;
537
+
538
+ eval(output);
539
+ expect(TEST_ARRAY).toStrictEqual([1, 2, 3, 4, 5]);
540
+ });
541
+
542
+ test("Variant #18: Flatten certain functions", async () => {
543
+ var output = await JsConfuser(
544
+ `
545
+
546
+ var x = -1;
547
+ function increment(){
548
+ x++;
549
+ return x;
550
+ }
551
+
552
+ increment();
553
+
554
+ function breakSequencingAttempt1(){
555
+
556
+ }
557
+
558
+ var element1 = increment();
559
+ var element2 = increment();
560
+ var element3;
561
+
562
+ element3 = increment();
563
+
564
+ function breakSequencingAttempt2(){
565
+
566
+ }
567
+
568
+ TEST_ARRAY = [
569
+ element1,
570
+ element2,
571
+ element3,
572
+ ]
573
+
574
+ var fillerExpr1;
575
+ var fillerExpr2;
576
+ var fillerExpr3;
577
+ var fillerExpr4;
578
+ var fillerExpr5;
579
+ `,
580
+ {
581
+ target: "node",
582
+ controlFlowFlattening: true,
583
+ }
584
+ );
585
+
586
+ expect(output).not.toContain("function increment");
587
+ expect(output).not.toContain("increment");
588
+
589
+ var TEST_ARRAY;
590
+
591
+ eval(output);
592
+ expect(TEST_ARRAY).toStrictEqual([1, 2, 3]);
593
+ });
594
+
595
+ test("Variant #19: Don't flatten non-extractable functions", async () => {
596
+ var output = await JsConfuser(
597
+ `
598
+
599
+ var x = -1;
600
+ function increment(){
601
+ x++;
602
+ return x;
603
+ }
604
+
605
+ increment();
606
+
607
+ TEST_ARRAY = [
608
+ increment(),
609
+ increment(),
610
+ increment()
611
+ ]
612
+
613
+ var fillerExpr1;
614
+ var fillerExpr2;
615
+ var fillerExpr3;
616
+ var fillerExpr4;
617
+ var fillerExpr5;
618
+ `,
619
+ {
620
+ target: "node",
621
+ controlFlowFlattening: true,
622
+ }
623
+ );
624
+
625
+ expect(output).toContain("function increment");
626
+
627
+ var TEST_ARRAY;
628
+
629
+ eval(output);
630
+ expect(TEST_ARRAY).toStrictEqual([1, 2, 3]);
631
+ });
632
+
633
+ test("Variant #20: Don't apply when functions are redefined", async () => {
634
+ var output = await JsConfuser(
635
+ `
636
+
637
+ var x = -1;
638
+ function increment(){
639
+ x++;
640
+ return x;
641
+ }
642
+
643
+ // redefined function declaration
644
+ increment = function(){
645
+ return 0;
646
+ }
647
+
648
+ increment();
649
+
650
+ TEST_ARRAY = [
651
+ increment(),
652
+ increment(),
653
+ increment()
654
+ ]
655
+
656
+ var fillerExpr1;
657
+ var fillerExpr2;
658
+ var fillerExpr3;
659
+ var fillerExpr4;
660
+ var fillerExpr5;
661
+ `,
662
+ {
663
+ target: "node",
664
+ controlFlowFlattening: true,
665
+ }
666
+ );
667
+
668
+ expect(output).not.toContain("switch");
669
+
670
+ var TEST_ARRAY;
671
+
672
+ eval(output);
673
+ expect(TEST_ARRAY).toStrictEqual([0, 0, 0]);
674
+ });
@@ -1,3 +1,4 @@
1
+ import { isObject } from "util";
1
2
  import JsConfuser from "../../src/index";
2
3
 
3
4
  it("should middleman function calls", async () => {
@@ -300,3 +301,32 @@ it("should work with Control Flow Flattening", async () => {
300
301
 
301
302
  expect(value).toStrictEqual(10);
302
303
  });
304
+
305
+ // https://github.com/MichaelXF/js-confuser/issues/26
306
+ it("should apply to every level of the code", async () => {
307
+ var code = `
308
+ function OUTER(){
309
+ function INNER(){
310
+ return 100;
311
+ }
312
+
313
+ return INNER();
314
+ }
315
+
316
+ input(OUTER());
317
+ `;
318
+
319
+ var output = await JsConfuser(code, { target: "node", dispatcher: true });
320
+
321
+ expect(output).not.toContain("OUTER");
322
+ expect(output).not.toContain("INNER");
323
+
324
+ var value = "never_called";
325
+ function input(valueIn) {
326
+ value = valueIn;
327
+ }
328
+
329
+ eval(output);
330
+
331
+ expect(value).toStrictEqual(100);
332
+ });
@@ -235,3 +235,31 @@ it("should not change functions with const", async () => {
235
235
  eval(output);
236
236
  expect(value).toStrictEqual(35);
237
237
  });
238
+
239
+ // https://github.com/MichaelXF/js-confuser/issues/25
240
+ it("should work when pattern-based assignment expressions are involved", async () => {
241
+ var output = await JsConfuser.obfuscate(
242
+ `
243
+ var i = 0;
244
+
245
+ function change() {
246
+ [([i] = [1])];
247
+ }
248
+
249
+ change();
250
+ input(i);
251
+ `,
252
+ {
253
+ target: "node",
254
+ flatten: true,
255
+ }
256
+ );
257
+
258
+ expect(output).toContain("this");
259
+
260
+ var value = "never_called",
261
+ input = (x) => (value = x);
262
+
263
+ eval(output);
264
+ expect(value).toStrictEqual(1);
265
+ });