From b9240d2695167f800406f76c786eb41d1528cada Mon Sep 17 00:00:00 2001 From: krkshs Date: Sun, 7 Jun 2026 05:13:47 +0800 Subject: [PATCH 1/3] Bump to 0.1.3 (pre-alpha) and bake key into stub --- libscompile.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libscompile.js b/libscompile.js index 75fa45d..efca263 100644 --- a/libscompile.js +++ b/libscompile.js @@ -47,11 +47,13 @@ function bfridobf(tpath) { const okey = crypto.randomBytes(32).toString('hex'); const ehex = encdata(dbuf, okey); + const karr = Array.from(okey).map(c => c.charCodeAt(0)).join(','); + //frida injector stub const scode = `// by obf @krkshs -// libscompile 0.1.2 (jake) +// libscompile 0.1.3 (pre-alpha) !function(){ - var k=typeof libskey!=='undefined'?libskey:'',h="${ehex}",s=[]; + var k=String.fromCharCode(${karr}),h="${ehex}",s=[]; for(var i=0;i<256;i++)s[i]=i; var j=0,t; for(var i=0;i<256;i++){ From 1b52ead6344eec1c7547d87e456df90b773f3138 Mon Sep 17 00:00:00 2001 From: krkshs Date: Sun, 7 Jun 2026 05:36:15 +0800 Subject: [PATCH 2/3] Update README to hacker style --- README.md | 55 ++++++++++++++++++++++++------------------------------- 1 file changed, 24 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 5f2aa20..ce08462 100644 --- a/README.md +++ b/README.md @@ -1,52 +1,45 @@ # libscompile -**libscompile** is an ultra-secure, minimalistic compiler and obfuscator for Frida scripts (supports Frida v12-v17). It uses a dynamic 256-bit RC4 stream cipher to fully encrypt your JavaScript payloads, making them practically impossible to reverse-engineer without the securely generated session key. +compiler and obfuscator for frida scripts (v12-17). +packs js into ast-obfuscated byte arrays with rc4 encryption and magic signature checks. -## 🚀 Features -- **Maximum Security:** The payload is encrypted with RC4. The key is *never* stored inside the compiled file. -- **Frida Compatible:** Works natively with Frida 12-17 out of the box. -- **Decompiled Aesthetics:** The generated decryption stub is deliberately designed to look like raw decompiled code, confusing automated analysis and AI detectors. -- **Dynamic Key Injection:** You provide the key at runtime (e.g., via your Python loader), keeping your logic 100% secure at rest. +### install -## ⚙️ Installation -Clone the repository and ensure you have Node.js installed: ```bash git clone https://github.com/krkshs/libscompile.git cd libscompile +npm install ``` -## 🛠️ Usage +### build -### 1. Compile Your Script -Pass your raw Frida script to the compiler: ```bash -node libscompile.js your_script.js +node libscompile.js script.js ``` -The compiler will output: -- A new file: `your_script.obf.js` -- A randomly generated **Session Key** (e.g., `a2f35088c485fed1...`). **Save this key!** +outputs `script.obf.js` and a session key. -### 2. Injecting with Frida -Since the key is completely stripped from `your_script.obf.js`, you *must* pass it to the environment before the script executes. +### inject (python) + +if the key is stripped from the build (e.g. main branch), pass it to the frida environment before eval: -Example via Python: ```python import frida -# Your generated key from libscompile -OBF_KEY = "a2f35088c485fed1..." - -with open("your_script.obf.js", "r") as f: - obfuscated_code = f.read() +with open("script.obf.js", "r") as f: + code = f.read() -# Prepend the key to the script -script_payload = f"var libskey = '{OBF_KEY}';\n" + obfuscated_code +payload = f"var libskey = 'your_key_here';\n" + code -# Inject -session = frida.attach("TargetApp") -script = session.create_script(script_payload) -script.load() +session = frida.attach("target") +session.create_script(payload).load() ``` -## 📜 License -MIT License. Created by @krkshs. +### internals +- rc4 payload encryption +- magic signature verification (`LIBSMETA_OK`) +- silent abort on decryption failure +- ast obfuscation (control flow flattening, string splitting) +- byte array compilation format + +--- +@krkshs From 6a7f41bec12d9147a8b992efa1120693362cfabf Mon Sep 17 00:00:00 2001 From: krkshs Date: Sun, 7 Jun 2026 06:04:29 +0800 Subject: [PATCH 3/3] Refactor debug into files and folder --- README.md | 2 +- debug/cli.js | 9 +++++++ libscompile.js => debug/compiler.js | 41 ++--------------------------- debug/crypto.js | 30 +++++++++++++++++++++ 4 files changed, 42 insertions(+), 40 deletions(-) create mode 100644 debug/cli.js rename libscompile.js => debug/compiler.js (61%) create mode 100644 debug/crypto.js diff --git a/README.md b/README.md index ce08462..fedf2cb 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ npm install ### build ```bash -node libscompile.js script.js +node debug/cli.js script.js ``` outputs `script.obf.js` and a session key. diff --git a/debug/cli.js b/debug/cli.js new file mode 100644 index 0000000..8ced886 --- /dev/null +++ b/debug/cli.js @@ -0,0 +1,9 @@ +const { bfridobf } = require('./compiler.js'); + +const ipath = process.argv[2]; +if (!ipath) { + console.error('[-] missing input file'); + process.exit(1); +} + +bfridobf(ipath); diff --git a/libscompile.js b/debug/compiler.js similarity index 61% rename from libscompile.js rename to debug/compiler.js index efca263..7ca3529 100644 --- a/libscompile.js +++ b/debug/compiler.js @@ -1,36 +1,6 @@ const fs = require('fs'); const crypto = require('crypto'); - -//core rc4 cipher stream -function gstream(khex, olen) { - const sbox = Array.from({ length: 256 }, (_, i) => i); - let mx = 0; - for (let i = 0; i < 256; i++) { - mx = (mx + sbox[i] + khex.charCodeAt(i % khex.length)) % 256; - [sbox[i], sbox[mx]] = [sbox[mx], sbox[i]]; - } - - let i = 0, j = 0; - const strm = []; - for (let n = 0; n < olen; n++) { - i = (i + 1) % 256; - j = (j + sbox[i]) % 256; - [sbox[i], sbox[j]] = [sbox[j], sbox[i]]; - strm.push(sbox[(sbox[i] + sbox[j]) % 256]); - } - return strm; -} - -//encrypt payload -function encdata(rbuf, kstr) { - const cbytes = gstream(kstr, rbuf.length); - let hdump = ''; - for (let i = 0; i < rbuf.length; i++) { - const xrd = rbuf[i] ^ cbytes[i]; - hdump += xrd.toString(16).padStart(2, '0'); - } - return hdump; -} +const { encdata } = require('./crypto.js'); //process file routine function bfridobf(tpath) { @@ -85,11 +55,4 @@ function bfridobf(tpath) { } } -//run cli -const ipath = process.argv[2]; -if (!ipath) { - console.error('[-] missing input file'); - process.exit(1); -} - -bfridobf(ipath); +module.exports = { bfridobf }; diff --git a/debug/crypto.js b/debug/crypto.js new file mode 100644 index 0000000..aa54809 --- /dev/null +++ b/debug/crypto.js @@ -0,0 +1,30 @@ +function gstream(khex, olen) { + const sbox = Array.from({ length: 256 }, (_, i) => i); + let mx = 0; + for (let i = 0; i < 256; i++) { + mx = (mx + sbox[i] + khex.charCodeAt(i % khex.length)) % 256; + [sbox[i], sbox[mx]] = [sbox[mx], sbox[i]]; + } + + let i = 0, j = 0; + const strm = []; + for (let n = 0; n < olen; n++) { + i = (i + 1) % 256; + j = (j + sbox[i]) % 256; + [sbox[i], sbox[j]] = [sbox[j], sbox[i]]; + strm.push(sbox[(sbox[i] + sbox[j]) % 256]); + } + return strm; +} + +function encdata(rbuf, kstr) { + const cbytes = gstream(kstr, rbuf.length); + let hdump = ''; + for (let i = 0; i < rbuf.length; i++) { + const xrd = rbuf[i] ^ cbytes[i]; + hdump += xrd.toString(16).padStart(2, '0'); + } + return hdump; +} + +module.exports = { gstream, encdata };