jsarmor 1.0.7 → 2.0.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.
package/cli/index.js CHANGED
@@ -19,6 +19,9 @@ import { injectDeadCode, generateDeadRuntime } from "../core/deadcode.js";
19
19
  import { injectAntiDebug } from "../core/antidebug.js";
20
20
  import { antiBeautify } from "../core/beautifyGuard.js";
21
21
  import { selfDefend } from "../core/selfdefend.js";
22
+ import { unicodeIdentifiers } from "../core/unicodeIdentifier.js";
23
+ import { buildStringRuntime } from "../core/stringRuntime.js";
24
+ import { antiVM } from "../core/antivm.js";
22
25
 
23
26
  import { watermark } from "../utils/watermark.js";
24
27
 
@@ -107,7 +110,7 @@ barCompleteChar:"█",
107
110
  barIncompleteChar:"░"
108
111
  });
109
112
 
110
- bar.start(6,0);
113
+ bar.start(7,0);
111
114
 
112
115
  const ast = parseCode(code);
113
116
  bar.increment();
@@ -115,6 +118,9 @@ bar.increment();
115
118
  renameVariables(ast);
116
119
  bar.increment();
117
120
 
121
+ unicodeIdentifiers(ast);
122
+ bar.increment();
123
+
118
124
  const pool = encodeStrings(ast);
119
125
  bar.increment();
120
126
 
@@ -143,8 +149,9 @@ const final =
143
149
  watermark(user) +
144
150
  injectAntiDebug() +
145
151
  antiBeautify() +
152
+ antiVM() +
146
153
  selfDefend() +
147
- `var _STRINGS=${JSON.stringify(pool)};\n` +
154
+ buildStringRuntime(pool) +
148
155
  runtimeJunk +
149
156
  generateJunk() +
150
157
  output;
package/core/antidebug.js CHANGED
@@ -1,15 +1,13 @@
1
1
  export function injectAntiDebug(){
2
-
3
2
  return `
4
3
 
5
- (function(){
4
+ ;(function(){
6
5
  setInterval(function(){
7
6
  try{
8
- (function(){debugger})()
7
+ debugger;
9
8
  }catch(e){}
10
- },2000)
9
+ },3000)
11
10
  })();
12
11
 
13
12
  `;
14
-
15
13
  }
package/core/antivm.js ADDED
@@ -0,0 +1,19 @@
1
+ export function antiVM(){
2
+ return `
3
+
4
+ ;(function(){
5
+
6
+ var s=(typeof navigator!="undefined"?navigator.userAgent:"node").toLowerCase()
7
+
8
+ if(
9
+ s.includes("vmware")||
10
+ s.includes("virtualbox")||
11
+ s.includes("qemu")
12
+ ){
13
+ console.warn("VM detected");
14
+ }
15
+
16
+ })()
17
+
18
+ `
19
+ }
@@ -1,21 +1,17 @@
1
1
  export function antiBeautify(){
2
-
3
2
  return `
4
3
 
5
- (function(){
4
+ ;(function(){
6
5
 
7
6
  const start=Date.now()
8
-
9
7
  debugger
10
-
11
8
  const end=Date.now()
12
9
 
13
- if(end-start>100){
14
- while(true){}
10
+ if(end-start>1000){
11
+ console.warn("Debug detected")
15
12
  }
16
13
 
17
14
  })();
18
15
 
19
16
  `;
20
-
21
17
  }
@@ -93,24 +93,13 @@ Function(path){
93
93
  });
94
94
 
95
95
  const whileLoop = t.whileStatement(
96
- t.booleanLiteral(true),
97
- t.blockStatement([
98
-
99
- t.switchStatement(
100
- t.identifier("_s"),
101
- cases
102
- ),
103
-
104
- t.ifStatement(
105
- t.binaryExpression(
106
- ">=",
107
- t.identifier("_s"),
108
- t.numericLiteral(body.length)
109
- ),
110
- t.breakStatement()
111
- )
112
-
113
- ])
96
+ t.binaryExpression("<", t.identifier("_s"), t.numericLiteral(body.length)),
97
+ t.blockStatement([
98
+ t.switchStatement(
99
+ t.identifier("_s"),
100
+ cases
101
+ )
102
+ ])
114
103
  );
115
104
 
116
105
  const newBody = [];
package/core/deadcode.js CHANGED
@@ -1,7 +1,9 @@
1
- import traverse from "@babel/traverse";
1
+ import traverseModule from "@babel/traverse";
2
2
  import * as t from "@babel/types";
3
3
  import { randomInt } from "../utils/random.js";
4
4
 
5
+ const traverse = traverseModule.default;
6
+
5
7
  const patterns = [
6
8
 
7
9
  "var _a=Math.random();if(_a>2){console.log(_a)}",
@@ -17,7 +19,9 @@ const patterns = [
17
19
 
18
20
  ];
19
21
 
20
- for(let i=0;i<90;i++){
22
+ /* generate nhiều pattern */
23
+
24
+ for(let i=0;i<20;i++){
21
25
 
22
26
  patterns.push(`
23
27
  var _junk${i}=Math.random()*${randomInt(1,999)};
@@ -34,9 +38,11 @@ return patterns[Math.floor(Math.random()*patterns.length)];
34
38
 
35
39
  }
36
40
 
41
+ /* AST deadcode */
42
+
37
43
  export function injectDeadCode(ast){
38
44
 
39
- traverse.default(ast,{
45
+ traverse(ast,{
40
46
 
41
47
  BlockStatement(path){
42
48
 
@@ -76,14 +82,14 @@ path.node.body.unshift(fake);
76
82
 
77
83
  }
78
84
 
85
+ /* runtime deadcode */
86
+
79
87
  export function generateDeadRuntime(){
80
88
 
81
89
  let out="";
82
90
 
83
- for(let i=0;i<30;i++){
84
-
91
+ for(let i=0;i<10;i++){
85
92
  out+=randomPattern()+"\n";
86
-
87
93
  }
88
94
 
89
95
  return out;
package/core/junkcode.js CHANGED
@@ -1,18 +1,19 @@
1
- export function generateJunk() {
1
+ export function generateJunk(){
2
2
 
3
- const junk = [];
3
+ return `
4
4
 
5
- for (let i = 0; i < 20; i++) {
5
+ var _假=Math.random()
6
6
 
7
- junk.push(`
8
- var _junk${i} = Math.random() * ${i};
9
- if(_junk${i} > 9999){
10
- console.log(_junk${i});
7
+ function _伪(){
8
+ try{
9
+ return Function("return 1+1")()
10
+ }catch(e){}
11
11
  }
12
- `);
13
12
 
14
- }
13
+ if(_假>2){
14
+ console.log(_伪())
15
+ }
15
16
 
16
- return junk.join("\n");
17
+ `
17
18
 
18
19
  }
package/core/rc4.js CHANGED
@@ -1,42 +1,33 @@
1
1
  export function rc4(key, str){
2
2
 
3
- let s=[]
4
- let j=0
5
- let x
6
- let res=""
3
+ if(!key) throw new Error("RC4 key empty")
7
4
 
8
- for(let i=0;i<256;i++){
9
- s[i]=i
10
- }
11
-
12
- for(let i=0;i<256;i++){
13
-
14
- j=(j+s[i]+key.charCodeAt(i%key.length))%256
5
+ let s=[],j=0,x,res=""
15
6
 
16
- x=s[i]
17
- s[i]=s[j]
18
- s[j]=x
7
+ for(let i=0;i<256;i++) s[i]=i
19
8
 
9
+ for(let i=0;i<256;i++){
10
+ j=(j+s[i]+key.charCodeAt(i%key.length))&255
11
+ x=s[i]
12
+ s[i]=s[j]
13
+ s[j]=x
20
14
  }
21
15
 
22
16
  let i=0
23
17
  j=0
24
18
 
25
19
  for(let y=0;y<str.length;y++){
20
+ i=(i+1)&255
21
+ j=(j+s[i])&255
26
22
 
27
- i=(i+1)%256
28
- j=(j+s[i])%256
29
-
30
- x=s[i]
31
- s[i]=s[j]
32
- s[j]=x
23
+ x=s[i]
24
+ s[i]=s[j]
25
+ s[j]=x
33
26
 
34
- let k=s[(s[i]+s[j])%256]
35
-
36
- res+=String.fromCharCode(str.charCodeAt(y)^k)
27
+ let k=s[(s[i]+s[j])&255]
37
28
 
29
+ res += String.fromCharCode(str.charCodeAt(y) ^ k)
38
30
  }
39
31
 
40
32
  return res
41
-
42
33
  }
package/core/renamer.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import traverseModule from "@babel/traverse";
2
+ import * as t from "@babel/types";
2
3
 
3
4
  const traverse = traverseModule.default;
4
5
 
@@ -15,50 +16,127 @@ const reserved = new Set([
15
16
  "setInterval"
16
17
  ]);
17
18
 
19
+ /* multilingual identifier */
20
+
21
+ const jp = "あいうえおかきくけこさしすせそたちつてと";
22
+ const kr = "가나다라마바사아자차카타파하";
23
+ const cn = "的一是在不了有和人这中大为上个国我以要他";
24
+ const latin = "abcdefghijklmnopqrstuvwxyz";
25
+
26
+ const pool = jp + kr + cn + latin;
27
+
18
28
  function randomName(){
19
- const chars="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
20
- let name="_";
29
+ let name="_0x";
21
30
  for(let i=0;i<6;i++){
22
- name+=chars[Math.floor(Math.random()*chars.length)];
31
+ name+=pool[Math.floor(Math.random()*pool.length)];
23
32
  }
24
33
  return name;
25
34
  }
26
35
 
27
36
  export function renameVariables(ast){
28
37
 
38
+ const renamed = new Map();
39
+
29
40
  traverse(ast,{
30
- Program(path){
31
41
 
32
- const bindings = path.scope.bindings;
42
+ Identifier(path){
43
+
44
+ // chỉ rename binding identifier
45
+ if(!path.isBindingIdentifier()) return;
46
+
47
+ const name = path.node.name;
48
+
49
+ // skip reserved
50
+ if(reserved.has(name)) return;
51
+
52
+ // skip already obfuscated
53
+ if(name.startsWith("_0x")) return;
33
54
 
34
- for(const key in bindings){
55
+ // skip short names (tránh phá scope nhỏ)
56
+ if(name.length < 3) return;
35
57
 
36
- const binding = bindings[key];
58
+ const binding = path.scope.getBinding(name);
59
+ if(!binding) return;
37
60
 
38
- if(reserved.has(key)) continue;
61
+ // skip params
62
+ if(binding.kind === "param") return;
39
63
 
40
- // skip imports
41
- if(binding.path.isImportSpecifier?.()) continue;
42
- if(binding.path.isImportDefaultSpecifier?.()) continue;
43
- if(binding.path.isImportNamespaceSpecifier?.()) continue;
64
+ // skip global scope
65
+ if(!binding.scope.parent) return;
44
66
 
45
- // skip function parameters
46
- if(binding.kind === "param") continue;
67
+ // skip mutated variables (tránh break logic)
68
+ if(binding.constantViolations && binding.constantViolations.length > 0){
69
+ return;
70
+ }
71
+
72
+ // skip if already renamed
73
+ if(renamed.has(binding)){
74
+ return;
75
+ }
76
+
77
+ const newName = randomName();
47
78
 
48
- // skip destructuring
49
- if(binding.path.isObjectPattern?.()) continue;
50
- if(binding.path.isArrayPattern?.()) continue;
79
+ try{
80
+ path.scope.rename(name,newName);
81
+ renamed.set(binding,newName);
82
+ }catch{}
51
83
 
52
- // skip globals
53
- if(!binding.scope.parent) continue;
84
+ },
54
85
 
55
- const newName=randomName();
86
+ FunctionDeclaration(path){
56
87
 
57
- path.scope.rename(key,newName);
88
+ if(!path.node.id) return;
58
89
 
59
- }
90
+ const name = path.node.id.name;
60
91
 
92
+ if(reserved.has(name)) return;
93
+ if(name.startsWith("_0x")) return;
94
+
95
+ const binding = path.scope.getBinding(name);
96
+ if(!binding) return;
97
+
98
+ if(binding.constantViolations && binding.constantViolations.length > 0){
99
+ return;
61
100
  }
101
+
102
+ if(renamed.has(binding)) return;
103
+
104
+ const newName = randomName();
105
+
106
+ try{
107
+ path.scope.rename(name,newName);
108
+ renamed.set(binding,newName);
109
+ }catch{}
110
+
111
+ },
112
+
113
+ ClassDeclaration(path){
114
+
115
+ if(!path.node.id) return;
116
+
117
+ const name = path.node.id.name;
118
+
119
+ if(reserved.has(name)) return;
120
+ if(name.startsWith("_0x")) return;
121
+
122
+ const binding = path.scope.getBinding(name);
123
+ if(!binding) return;
124
+
125
+ if(binding.constantViolations && binding.constantViolations.length > 0){
126
+ return;
127
+ }
128
+
129
+ if(renamed.has(binding)) return;
130
+
131
+ const newName = randomName();
132
+
133
+ try{
134
+ path.scope.rename(name,newName);
135
+ renamed.set(binding,newName);
136
+ }catch{}
137
+
138
+ }
139
+
62
140
  });
63
141
 
64
142
  }
@@ -1,23 +1,20 @@
1
1
  export function selfDefend(){
2
-
3
2
  return `
4
3
 
5
- (function(){
4
+ ;(function(){
6
5
 
7
6
  function guard(){
8
-
9
- const src=guard.toString()
10
-
7
+ try{
8
+ const src = guard.toString()
11
9
  if(!src.includes("guard")){
12
- while(true){}
10
+ console.warn("Tamper detected")
13
11
  }
14
-
12
+ }catch(e){}
15
13
  }
16
14
 
17
- setInterval(guard,4000)
15
+ setInterval(guard,5000)
18
16
 
19
17
  })();
20
18
 
21
19
  `;
22
-
23
20
  }
@@ -8,15 +8,52 @@ export function encodeStrings(ast){
8
8
  const pool = [];
9
9
  const map = new Map();
10
10
 
11
+ function rand(a,b){
12
+ return Math.floor(Math.random()*(b-a))+a;
13
+ }
14
+
15
+ function buildIndexExpression(index){
16
+
17
+ const mode = rand(0,3);
18
+
19
+ if(mode===0){
20
+
21
+ const key = rand(1,50);
22
+
23
+ return t.binaryExpression(
24
+ "^",
25
+ t.numericLiteral(index ^ key),
26
+ t.numericLiteral(key)
27
+ );
28
+
29
+ }
30
+
31
+ if(mode===1){
32
+
33
+ const key = rand(1,20);
34
+
35
+ return t.binaryExpression(
36
+ "-",
37
+ t.numericLiteral(index + key),
38
+ t.numericLiteral(key)
39
+ );
40
+
41
+ }
42
+
43
+ return t.numericLiteral(index);
44
+
45
+ }
46
+
11
47
  function getIndex(value){
12
48
 
13
49
  if(map.has(value)){
14
- return map.get(value);
50
+ return map.get(value);
15
51
  }
16
52
 
17
53
  const index = pool.length;
18
54
 
19
55
  pool.push(value);
56
+
20
57
  map.set(value,index);
21
58
 
22
59
  return index;
@@ -24,52 +61,75 @@ return index;
24
61
  }
25
62
 
26
63
  traverse(ast,{
64
+
27
65
  StringLiteral(path){
28
66
 
29
- const value = path.node.value;
30
-
31
- /* skip unsafe places */
32
-
33
- if(path.parent.type === "Directive") return;
34
-
35
- if(
36
- path.parent.type === "CallExpression" &&
37
- path.parent.callee.name === "require"
38
- ){
39
- return;
40
- }
41
-
42
- if(path.parent.type === "ImportDeclaration"){
43
- return;
44
- }
45
-
46
- if(
47
- path.parent.type === "ObjectProperty" &&
48
- path.parent.key === path.node
49
- ){
50
- return;
51
- }
52
-
53
- if(
54
- path.parent.type === "MemberExpression" &&
55
- path.parent.property === path.node
56
- ){
57
- return;
58
- }
59
-
60
- if(path.parent.type === "TemplateLiteral"){
61
- return;
62
- }
63
-
64
- const index = getIndex(value);
65
-
66
- path.replaceWith(
67
- t.memberExpression(
68
- t.identifier("_STRINGS"),
69
- t.numericLiteral(index),
70
- true
71
- )
72
- );
67
+ const value = path.node.value;
68
+
69
+ if(!value) return;
70
+
71
+ /* skip directives */
72
+
73
+ if(path.parent.type === "Directive") return;
74
+
75
+ if(value === "use strict") return;
76
+
77
+ /* skip require */
78
+
79
+ if(
80
+ path.parent.type === "CallExpression" &&
81
+ path.parent.callee &&
82
+ path.parent.callee.name === "require"
83
+ ){
84
+ return;
85
+ }
86
+
87
+ /* skip import */
88
+
89
+ if(path.parent.type === "ImportDeclaration") return;
90
+
91
+ /* skip object key */
92
+
93
+ if(
94
+ path.parent.type === "ObjectProperty" &&
95
+ path.parent.key === path.node
96
+ ){
97
+ return;
98
+ }
99
+
100
+ /* skip member property */
101
+
102
+ if(
103
+ path.parent.type === "MemberExpression" &&
104
+ path.parent.property === path.node
105
+ ){
106
+ return;
107
+ }
108
+
109
+ /* skip template */
110
+
111
+ if(path.parent.type === "TemplateLiteral") return;
112
+
113
+ /* skip inside decrypt runtime */
114
+
115
+ if(path.findParent(p =>
116
+ p.isCallExpression() &&
117
+ p.node.callee &&
118
+ p.node.callee.name === "_解密"
119
+ )){
120
+ return;
121
+ }
122
+
123
+ const index = getIndex(value);
124
+
125
+ const expr = buildIndexExpression(index);
126
+
127
+ path.replaceWith(
128
+ t.callExpression(
129
+ t.identifier("_解密"),
130
+ [expr]
131
+ )
132
+ );
73
133
 
74
134
  }
75
135
 
@@ -0,0 +1,56 @@
1
+ import { rc4 } from "./rc4.js"
2
+
3
+ export function buildStringRuntime(pool){
4
+
5
+ const key = Math.random().toString(36).slice(2)
6
+
7
+ const encrypted = pool.map(s=>{
8
+ const enc = rc4(key, s)
9
+ return Buffer.from(enc, "binary").toString("base64")
10
+ })
11
+
12
+ return `
13
+
14
+ var _池 = ${JSON.stringify(encrypted)};
15
+ var _缓存 = {};
16
+
17
+ function _解密(i){
18
+
19
+ if(_缓存[i]) return _缓存[i];
20
+
21
+ var b64 = _池[i];
22
+
23
+ var data = typeof atob === "function"
24
+ ? atob(b64)
25
+ : Buffer.from(b64,"base64").toString("binary");
26
+
27
+ var s=[],j=0,x,res="";
28
+
29
+ for(var k=0;k<256;k++) s[k]=k;
30
+
31
+ for(k=0;k<256;k++){
32
+ j=(j+s[k]+"${key}".charCodeAt(k%"${key}".length))%256;
33
+ x=s[k];s[k]=s[j];s[j]=x;
34
+ }
35
+
36
+ k=0;j=0;
37
+
38
+ for(var y=0;y<data.length;y++){
39
+
40
+ k=(k+1)%256;
41
+ j=(j+s[k])%256;
42
+
43
+ x=s[k];s[k]=s[j];s[j]=x;
44
+
45
+ var t=s[(s[k]+s[j])%256];
46
+
47
+ res+=String.fromCharCode(data.charCodeAt(y)^t);
48
+
49
+ }
50
+
51
+ _缓存[i]=res;
52
+ return res;
53
+
54
+ }
55
+ `
56
+ }
package/core/unicode.js CHANGED
@@ -17,11 +17,7 @@ export function unicodeEscape(ast){
17
17
  StringLiteral(path){
18
18
 
19
19
  const val = path.node.value;
20
-
21
- path.node.extra = {
22
- raw: `"${toUnicode(val)}"`,
23
- rawValue: val
24
- };
20
+ if(val.includes("_解密")) return;
25
21
 
26
22
  }
27
23
  });
@@ -0,0 +1,67 @@
1
+ import traverseModule from "@babel/traverse";
2
+
3
+ const traverse = traverseModule.default;
4
+
5
+ const reserved = new Set([
6
+ "require",
7
+ "module",
8
+ "exports",
9
+ "console",
10
+ "process",
11
+ "Buffer"
12
+ ]);
13
+
14
+ const jp="あいうえおかきくけこ";
15
+ const kr="가나다라마바사";
16
+ const cn="的一是在不了有和";
17
+
18
+ const pool = jp + kr + cn;
19
+
20
+ function randChar(){
21
+ return pool[Math.floor(Math.random()*pool.length)];
22
+ }
23
+
24
+ function randomName(){
25
+
26
+ let name="_0x";
27
+
28
+ for(let i=0;i<4;i++){
29
+ name+=randChar();
30
+ }
31
+
32
+ return name;
33
+
34
+ }
35
+
36
+ export function unicodeIdentifiers(ast){
37
+
38
+ traverse(ast,{
39
+
40
+ Identifier(path){
41
+
42
+ if(!path.isBindingIdentifier()) return;
43
+
44
+ const name = path.node.name;
45
+
46
+ if(name.length < 3) return;
47
+ if(name.startsWith("_0x")) return;
48
+ if(reserved.has(name)) return;
49
+
50
+ const binding = path.scope.getBinding(name);
51
+
52
+ if(!binding) return;
53
+ if(binding.identifier !== path.node) return;
54
+
55
+ if(binding.constantViolations.length > 0) return;
56
+
57
+ const newName = randomName();
58
+
59
+ try{
60
+ path.scope.rename(name,newName);
61
+ }catch{}
62
+
63
+ }
64
+
65
+ });
66
+
67
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jsarmor",
3
- "version": "1.0.7",
3
+ "version": "2.0.1",
4
4
  "description": "Advanced JavaScript Obfuscator",
5
5
  "type": "module",
6
6
  "main": "cli/index.js",
@@ -9,10 +9,11 @@ return `
9
9
 
10
10
  __OWN__ = "_kingktn - Trương Nhật Bảo Nam"
11
11
  __OBF__ = "JSarmor"
12
- __USR__ = "${user}"
13
- __VER__ = "1.7.0"
12
+ __USR__ = "${user} - Requests Protect"
13
+ __VER__ = "2.0.0"
14
14
  __DATE__ = "${date}"
15
15
 
16
+ Discord: _kingktn | Ig: _kingktn | https://eboy.asia/p.n
16
17
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
17
18
  */
18
19
 
File without changes