simple-javascript-obf 0.1.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/.github/workflows/node.js.yml +31 -0
- package/LICENSE +21 -0
- package/README.md +92 -0
- package/THIRD_PARTY_NOTICES.md +82 -0
- package/bin/js-obf +228 -0
- package/bin/obf.sh +257 -0
- package/package.json +26 -0
- package/src/index.js +106 -0
- package/src/options.js +128 -0
- package/src/pipeline.js +56 -0
- package/src/plugins/antiHook.js +123 -0
- package/src/plugins/controlFlowFlatten.js +203 -0
- package/src/plugins/deadCode.js +82 -0
- package/src/plugins/encodeMembers.js +44 -0
- package/src/plugins/entry.js +31 -0
- package/src/plugins/rename.js +100 -0
- package/src/plugins/stringEncode.js +494 -0
- package/src/plugins/vm/ast-utils.js +58 -0
- package/src/plugins/vm/compiler.js +113 -0
- package/src/plugins/vm/constants.js +72 -0
- package/src/plugins/vm/emit.js +916 -0
- package/src/plugins/vm/encoding.js +252 -0
- package/src/plugins/vm/index.js +366 -0
- package/src/plugins/vm/mapping.js +24 -0
- package/src/plugins/vm/normalize.js +692 -0
- package/src/plugins/vm/runtime.js +1145 -0
- package/src/plugins/vm.js +1 -0
- package/src/utils/names.js +55 -0
- package/src/utils/reserved.js +57 -0
- package/src/utils/rng.js +55 -0
- package/src/utils/stream.js +97 -0
- package/src/utils/string.js +13 -0
- package/test/bench-runner.js +78 -0
- package/test/benchmark-source.js +35 -0
- package/test/benchmark-vm.js +160 -0
- package/test/dist/bench.obf.js +1 -0
- package/test/dist/bench.original.js +35 -0
- package/test/dist/bench.vm.js +1 -0
- package/test/dist/sample-input.obf.js +1 -0
- package/test/dist/sample-input.vm.js +1 -0
- package/test/generate-obf.js +38 -0
- package/test/obf-smoke.js +129 -0
- package/test/sample-input.js +23 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const _0x21CrC=[[[151,176,235,135,168],[129],[244],[176]],[5,1,1,1],[207,199],192,207],_0x22iJL=[[[221,218],[165,206,227,230,253,195]],[2,6],[36,44],148,36],_0x23gLx=[[[179,174],[136],[168]],[2,1,1],[119,115],228,119],_0x24EPn=[[[48,8,28,35,2,40],[45,31,24],[42],[62,94]],[6,3,1,2],[201,197],105,201],_0x25Xft=[[[214],[196,251],[223]],[1,2,1],[207,203],142,207],_0x16dyN=[0,1,3,4,2],_0x17MGx=[2,0,1,3,4],_0x18IkF=[0,0,0,0,0],_0x13oUe=[83,150,32,27,88,1,32,29],_0x15uWy=622,_0x14nCo=[],_0x19oDj=[35,23,60],_0x1afYh="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",_0x1fzVV=e=>{switch(e){case 0:default:return _0x21CrC;case 1:return _0x22iJL;case 2:return _0x23gLx;case 3:return _0x24EPn;case 4:return _0x25Xft}},_0x20VUx=(e,t)=>{const n=e[0],r=e[1],o=e[2],x=e[3],f=e[4];let a=o[2*t]^f,_=o[2*t+1]^f,u=0,l=a;for(;u<r.length&&l>=r[u];)l-=r[u],u+=1;let c="";for(let e=0;e<_;e+=1){const e=n[u][l]^x;c+=String.fromCharCode(e),l+=1,l>=r[u]&&(u+=1,l=0)}return c},_0x1ebXu=e=>{let t="";for(let n=0;n<e.length;n+=1){const r=e[n],o=_0x1afYh.indexOf(r);if(o<0){t+=r;continue}t+=_0x1afYh[(o-_0x19oDj[(n+495)%_0x19oDj.length]+65)%65]}return t},_0x1bbxZ=e=>{if("undefined"!=typeof Buffer)return Buffer.from(e,"base64");if(2!=(1&Date.now())){let e=208;if(Date.now(),2!=(1&Date.now())){let e=208;Date.now(),e^=1}e^=203}if("undefined"!=typeof atob){const t=atob(e),n=new Uint8Array(t.length);for(let e=0;e<t.length;e+=1)n[e]=t.charCodeAt(e);return n}throw new Error("No base64 support")},_0x1clmN=e=>{const t=Uint8Array.from(e),n=t.length||1,r=e=>255&t[e%n],o=1&r(0),x=r(1)%7+3,f=r(2)%7+5,a=r(3)%7+3,_=r(4)%7+5,u=(e,t)=>(e<<t|e>>>32-t)>>>0,l=(e,t)=>(e>>>t|e<<32-t)>>>0;let c=(r(5)<<24|r(6)<<16|r(7)<<8|r(8))>>>0,i=(r(9)<<24|r(10)<<16|r(11)<<8|r(12))>>>0;c^=n<<24>>>0,i^=n<<16>>>0;for(let e=0;e<n;e+=1){const t=r(e)+17*e&255;c=c+(255&(t<<(7&e)|t>>>8-(7&e)))>>>0,c=u(c,x),i=i+(c^t<<a)>>>0,i=l(i,f)}let s=0;return e=>{const r=t[s%n];let d;return 0===o?(c=c+(i^r+s+1)>>>0,c=u(c,x),i=i+(r^255&c)>>>0,i=l(i,f),d=255&(c^i^c>>>7)):(i=i+r+(255&c)>>>0,i=u(i,a),c=c+(i^r<<8)>>>0,c=l(c,_),d=c+i+(c>>>11)&255),s+=1,e^d}},_0x1dLXk=e=>{if("undefined"!=typeof TextDecoder){if(2!=(1&Date.now())){let e=134;Date.now(),e^=189}return(new TextDecoder).decode(e)}let t="";for(let n=0;n<e.length;n+=1)if(t+=String.fromCharCode(e[n]),2!=(1&Date.now())){let e=152;Date.now(),e^=9}try{return decodeURIComponent(escape(t))}catch{return t}};function _0x12Wdu(e){let t,n,r,o,x,f,a=0;for(;;)switch(a){case 0:x=_0x14nCo[e-=622],a=void 0!==x?5:1;break;case 1:t=_0x16dyN[e],n=_0x17MGx[t],r=_0x18IkF[t],a=2;break;case 2:o=_0x1fzVV(n),f=_0x1bbxZ(_0x1ebXu(_0x20VUx(o,r))),a=3;break;case 3:{const t=_0x1clmN(_0x13oUe);for(let e=0;e<f.length;e+=1)if(f[e]=t(f[e]),2!=(1&Date.now())){let e=204;Date.now(),e^=67}x=_0x1dLXk(f),_0x14nCo[e]=x,a=5;break}default:return x}}function fib(e){let t=0,n=1;if(2!=(1&Date.now())){let e=186;Date.now(),e^=111}for(let r=0;r<e;r++){const e=t+n;t=n,n=e}return t}function greet(e){if(Date.now(),2!=(1&Date.now())){let e=8;Date.now(),e^=20}return _0x12Wdu(622)+e}function main(){const e=fib(8),t=greet(_0x12Wdu(623));return globalThis[_0x12Wdu(624)][_0x12Wdu(625)](t+_0x12Wdu(626)+e),{value:e,msg:t}}globalThis.__result=main();
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const { obfuscate } = require("../src");
|
|
4
|
+
|
|
5
|
+
async function main() {
|
|
6
|
+
const inputPath = process.argv[2] || path.join(__dirname, "sample-input.js");
|
|
7
|
+
const outDir = process.argv[3] || path.join(__dirname, "dist");
|
|
8
|
+
|
|
9
|
+
const source = fs.readFileSync(inputPath, "utf8");
|
|
10
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
11
|
+
|
|
12
|
+
const baseName = path.basename(inputPath, path.extname(inputPath));
|
|
13
|
+
|
|
14
|
+
const obf = await obfuscate(source, {
|
|
15
|
+
preset: "high",
|
|
16
|
+
seed: "test-seed",
|
|
17
|
+
filename: path.basename(inputPath),
|
|
18
|
+
});
|
|
19
|
+
const obfPath = path.join(outDir, `${baseName}.obf.js`);
|
|
20
|
+
fs.writeFileSync(obfPath, obf.code);
|
|
21
|
+
|
|
22
|
+
const obfVm = await obfuscate(source, {
|
|
23
|
+
preset: "high",
|
|
24
|
+
seed: "test-seed",
|
|
25
|
+
filename: path.basename(inputPath),
|
|
26
|
+
vm: { enabled: true, include: ["fib"] },
|
|
27
|
+
});
|
|
28
|
+
const vmPath = path.join(outDir, `${baseName}.vm.js`);
|
|
29
|
+
fs.writeFileSync(vmPath, obfVm.code);
|
|
30
|
+
|
|
31
|
+
console.log("wrote:", obfPath);
|
|
32
|
+
console.log("wrote:", vmPath);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
main().catch((err) => {
|
|
36
|
+
process.stderr.write(`${err && err.stack ? err.stack : err}\n`);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
});
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
const assert = require("assert");
|
|
2
|
+
const vm = require("vm");
|
|
3
|
+
const { obfuscate } = require("../src");
|
|
4
|
+
|
|
5
|
+
function runCode(code, timeoutMs = 5000) {
|
|
6
|
+
const logs = [];
|
|
7
|
+
const context = {
|
|
8
|
+
console: {
|
|
9
|
+
log: (...args) => logs.push(args.join(" ")),
|
|
10
|
+
},
|
|
11
|
+
Buffer,
|
|
12
|
+
TextDecoder,
|
|
13
|
+
Uint8Array,
|
|
14
|
+
};
|
|
15
|
+
context.globalThis = context;
|
|
16
|
+
vm.createContext(context);
|
|
17
|
+
vm.runInContext(code, context, { timeout: timeoutMs });
|
|
18
|
+
const result =
|
|
19
|
+
context.__result === undefined
|
|
20
|
+
? undefined
|
|
21
|
+
: JSON.parse(JSON.stringify(context.__result));
|
|
22
|
+
return { result, logs };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const source = `
|
|
26
|
+
function sum(arr) {
|
|
27
|
+
let total = 0;
|
|
28
|
+
for (let i = 0; i < arr.length; i++) {
|
|
29
|
+
total += arr[i];
|
|
30
|
+
}
|
|
31
|
+
return total;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function vmTarget(x) {
|
|
35
|
+
let y = x + 1;
|
|
36
|
+
for (let i = 0; i < 3; i++) {
|
|
37
|
+
y += i;
|
|
38
|
+
}
|
|
39
|
+
if (y % 2 === 0) {
|
|
40
|
+
y += 5;
|
|
41
|
+
} else {
|
|
42
|
+
y -= 5;
|
|
43
|
+
}
|
|
44
|
+
switch (y % 3) {
|
|
45
|
+
case 0:
|
|
46
|
+
y += 7;
|
|
47
|
+
break;
|
|
48
|
+
case 1:
|
|
49
|
+
y += 11;
|
|
50
|
+
break;
|
|
51
|
+
default:
|
|
52
|
+
y += 13;
|
|
53
|
+
}
|
|
54
|
+
return y;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function superTarget() {
|
|
58
|
+
const base = { value: 10, get() { return this.value; } };
|
|
59
|
+
const obj = {
|
|
60
|
+
get() {
|
|
61
|
+
return super.get() + 1;
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
Object.setPrototypeOf(obj, base);
|
|
65
|
+
return obj.get();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function main(input) {
|
|
69
|
+
const map = { a: 1, b: 2 };
|
|
70
|
+
let label = "len:" + input.length;
|
|
71
|
+
let res =
|
|
72
|
+
sum(input) + map.a + map.b + vmTarget(input.length) + superTarget();
|
|
73
|
+
if (res > 10) {
|
|
74
|
+
res -= 3;
|
|
75
|
+
} else {
|
|
76
|
+
res += 3;
|
|
77
|
+
}
|
|
78
|
+
switch (res % 3) {
|
|
79
|
+
case 0:
|
|
80
|
+
res += 7;
|
|
81
|
+
break;
|
|
82
|
+
case 1:
|
|
83
|
+
res += 11;
|
|
84
|
+
break;
|
|
85
|
+
default:
|
|
86
|
+
res += 13;
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
if (input[0] === 99) {
|
|
90
|
+
throw new Error("boom");
|
|
91
|
+
}
|
|
92
|
+
} catch (err) {
|
|
93
|
+
res += err.message.length;
|
|
94
|
+
}
|
|
95
|
+
const out = { res, label };
|
|
96
|
+
globalThis.__result = out;
|
|
97
|
+
console.log(label);
|
|
98
|
+
return out;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
main([1, 2, 3, 4]);
|
|
102
|
+
`;
|
|
103
|
+
|
|
104
|
+
async function main() {
|
|
105
|
+
const baseline = runCode(source);
|
|
106
|
+
|
|
107
|
+
const obfHigh = await obfuscate(source, { preset: "high", seed: "test-seed" });
|
|
108
|
+
const obfHighResult = runCode(obfHigh.code);
|
|
109
|
+
|
|
110
|
+
assert.deepStrictEqual(obfHighResult.result, baseline.result);
|
|
111
|
+
assert.deepStrictEqual(obfHighResult.logs, baseline.logs);
|
|
112
|
+
|
|
113
|
+
const obfVm = await obfuscate(source, {
|
|
114
|
+
preset: "low",
|
|
115
|
+
seed: "test-seed",
|
|
116
|
+
vm: { enabled: true, include: ["vmTarget", "superTarget"] },
|
|
117
|
+
});
|
|
118
|
+
const obfVmResult = runCode(obfVm.code, 20000);
|
|
119
|
+
|
|
120
|
+
assert.deepStrictEqual(obfVmResult.result, baseline.result);
|
|
121
|
+
assert.deepStrictEqual(obfVmResult.logs, baseline.logs);
|
|
122
|
+
|
|
123
|
+
console.log("obfuscation smoke test passed");
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
main().catch((err) => {
|
|
127
|
+
process.stderr.write(`${err && err.stack ? err.stack : err}\n`);
|
|
128
|
+
process.exit(1);
|
|
129
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
function fib(n) {
|
|
2
|
+
let a = 0;
|
|
3
|
+
let b = 1;
|
|
4
|
+
for (let i = 0; i < n; i++) {
|
|
5
|
+
const next = a + b;
|
|
6
|
+
a = b;
|
|
7
|
+
b = next;
|
|
8
|
+
}
|
|
9
|
+
return a;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function greet(name) {
|
|
13
|
+
return "hi " + name;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function main() {
|
|
17
|
+
const value = fib(8);
|
|
18
|
+
const msg = greet("js-obf");
|
|
19
|
+
console.log(msg + " -> " + value);
|
|
20
|
+
return { value, msg };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
globalThis.__result = main();
|