
Un offuscatore JavaScript basato su tecniche di offuscamento a indistinguibilità crittografica.
Questo progetto non raggiunge l'offuscamento indistinguibile. Non dovresti usare questo prodotto per proteggere segreti. Serve a scoraggiare il reverse engineering, non a prevenirlo
Un offuscatore JavaScript progettato per rendere il codice estremamente difficile da leggere e analizzare sia per umani che per LLM. Scritto in TypeScript. Implementa tecniche dalla ricerca crittografica sull'offuscamento sottoposta a revisione paritaria.
npm install
npm run build
# Utilizzo base
node dist/index.js input.js > output.js
# Con budget di token target (default: 2.000.000)
node dist/index.js --target-tokens 500000 input.js > output.js
# Offuscamento minimale (output piccolo)
node dist/index.js --target-tokens 10000 input.js > output.js
# Massimo gonfiaggio (10M token)
node dist/index.js --target-tokens 10000000 input.js > output.js
# Utilizzo di variabile d'ambiente
INPUT_FILE=input.js node dist/index.js > output.js
# Aiuto
node dist/index.js --help
| Opzione | Predefinito | Descrizione |
|---|---|---|
--target-tokens <n> | 2000000 | Dimensione target dell'output in token. Input piccoli vengono gonfiati fino a questo limite. Input grandi producono meno gonfiaggio per rimanere entro il budget. |
--help, -h | Mostra il messaggio di aiuto |
npm run build # Compila TypeScript in dist/
npm run start # Esegue l'offuscatore (legge input.js)
npm run test # Esegue la suite di test
npm run obfuscate-package # Esegue test di compatibilità su pacchetti npm
const { obfuscate } = require('./dist/obfuscator');
const code = 'function add(a, b) { return a + b; }';
const obfuscated = obfuscate(code);
// Con opzioni
const obfuscated = obfuscate(code, { targetTokens: 500000 });
L'offuscatore applica 20 trasformazioni in 4 fasi. Ogni stadio si basa sul precedente.
| Ordine | Trasformazione | File | Descrizione |
|---|---|---|---|
| 1 | Trappole Anti-Debug | transforms/antiDebug.ts | Inietta istruzioni eval("debugger") e 10-20 cicli setInterval con intervalli di numeri primi (5s-600s) che attivano ripetutamente breakpoint del debugger. Ogni istanza utilizza stringhe codificate uniche. |
| 2 | Inneschi per Programmi Punturati | transforms/tripwires.ts | Incorpora controlli nascosti che confrontano hash di parametri con valori segreti. 5 modelli di hash (impronta bit a bit, aritmetica modulare, charCodeAt, hash numerico, typeof+length). Attiva corruzione silenziosa dello stato, cicli infiniti o lancia eccezioni su input segreti. [Paper 4] |
| 3 | Iniezione di Rumore LPN | transforms/noiseInjection.ts | Aggiunge e annulla rumore casuale attraverso percorsi divisi in calcoli aritmetici. 6 modelli: add/sub, XOR, mul/div, variabile doppia divisa, catena di hash calcolata, rotazione di bit. I valori intermedi sono privi di significato senza tracciare l'intera cancellazione. [Paper 7] |
| Ordine | Trasformazione | File | Descrizione |
|---|---|---|---|
| 4 | Appiattimento del Flusso di Controllo | transforms/controlFlowFlattening.ts | Converte i corpi delle funzioni in macchine a stati while(true) { switch((_s * P) % M) { ... } } con invio aritmetico modulare — i valori dei case sono codificati tramite (idStato * moltiplicatore) % modulo usando parametri primi casuali. [Paper 3] |
| 5 | Predicati Opachi | transforms/opaquePredicates.ts | Inietta condizioni if che valutano sempre vero o falso ma sono matematicamente difficili da dimostrare (ad es., (x*x+x)%2===0). 15 formule di predicato tra aritmetica modulare, bit a bit e categorie di tipo. |
| 6 | Funzioni Proxy | transforms/proxyFunctions.ts | Instrada tutte le chiamate di funzione attraverso due dispatcher: _fc(fn, ...args) per chiamate semplici, _mc(obj, prop, ...args) per chiamate di metodo. Utilizza Function.prototype.apply catturato in una variabile locale per robustezza. |
| 7 | Esaurimento della Finestra di Contesto | transforms/contextExhaustion.ts | Avvolge le espressioni in ternari profondamente annidati con condizioni opache, catene di espressioni void e padding condizionale void. Costringe i LLM a sprecare token della finestra di contesto in rumore. |
| 8 | Fusione di Espressioni a Virgola | transforms/commaExpressions.ts | Comprime istruzioni di espressioni consecutive in singole espressioni a virgola: a(); b(); return c() diventa return a(), b(), c(). |
| Ordine | Passaggio | File | Descrizione |
|---|---|---|---|
| 9 | Passaggio 1: Catalogazione | passes/firstPass.ts | Attraversa l'AST e cataloga ogni identificatore, costruendo una mappa dei globali che assegna a ciascuno un nome Unicode casuale di 6-16 caratteri scelto da 16 intervalli di script (CJK, Hangul, Greco, Cirillico, Devanagari, Thai, Arabo, Katakana, ecc.). |
| 10 | Passaggio 2: Sostituzione | passes/secondPass.ts | Sostituisce tutti i nomi di identificatore con i loro equivalenti Unicode offuscati. Codifica gli argomenti di require() come String.fromCharCode(...). Codifica le sorgenti statiche di import/export come stringhe letterali con escape Unicode. Sostituisce i riferimenti a superClass delle classi, le espressioni di template literal, i pattern di destrutturazione. |
| 11 | Passaggio 3: Parametri Fittizi | passes/thirdPass.ts | Inietta 0-15 parametri casuali non utilizzati in ogni dichiarazione ed espressione di funzione. Salta le funzioni con parametri rest. Rimuove tutti i commenti. |
| Ordine | Trasformazione | File | Descrizione |
|---|---|---|---|
| 12 | Codifica delle Variabili Globali | transforms/globalVariableEncoding.ts | Sostituisce i riferimenti a globali (scoperti dinamicamente da globalThis + pacchetto window) con eval("Nome<suffisso>".replace(new RegExp("<suffisso>$"), "")). Entrambe le stringhe fluiscono attraverso l'array di stringhe. |
| 13 | Codifica delle Chiavi di Proprietà | transforms/propertyKeyEncoding.ts | Converte l'accesso con punto in accesso calcolato con registri per ambito. L'accesso tra ambiti funziona perché tutti i suffissi risolvono allo stesso nome di proprietà in fase di esecuzione tramite .replace(). |
| 14 | Codifica dei Numeri | transforms/numberEncoding.ts | 11 strategie di codifica: shift+add, identità XOR, complemento, divisione, shift annidati, doppio-NOT, modulare, ecc. Ogni istanza è generata in modo univoco. Salta le chiavi di proprietà e i valori dei case di switch. |
| 15 | Verifica dell'Integrità Personale | transforms/selfIntegrity.ts | Inietta 2-4 controlli runtime: verifica del codice nativo di eval, integrità di Function.prototype.toString, rilevamento di anomalie temporali, validazione della struttura del codice. Risposte anti-manomissione: busy wait, eccezione, corruzione silenziosa. [Paper 10] |
| 16 | Estrazione dell'Array di Stringhe | transforms/stringArrayExtraction.ts | Raccoglie tutte le stringhe in un singolo array con decifratura XOR a catena (la chiave per la voce N dipende dal contenuto decodificato della voce N-1) e pattern di errore sparsi dipendenti dalla posizione (ogni carattere ottiene una chiave XOR diversa, con errori sparsi ispirati a LPN in posizioni selezionate). [Papers 2, 9] |
| 17 | Stub della Console | obfuscator.ts | Scopre dinamicamente tutti i metodi di console e imposta ciascuno su una funzione no-op. |
| 18 | Minificazione Terser | obfuscator.ts | Rimuove spazi bianchi e formattazione tramite terser (, ). Ricorre a rimozione basata su regex se terser non riesce a analizzare l'output. |
Il codice morto viene iniettato in più punti con due strategie di generazione:
| Strategia | Sorgente | Descrizione |
|---|---|---|
| Basata su template | transforms/deadCodeInjection.ts | 9 tipi di template: accumulo con loop, costruzione di array, manipolazione di oggetti, concatenazione di stringhe, condizionali annidati, try/catch, countdown con while, switch calcolato, catene bit a bit. I template fanno riferimento a variabili reali dell'ambito. |
| Basata su mutazione | transforms/deadCodeInjection.ts | Clona istruzioni REALI e le muta: scambia operatori all'interno di gruppi di equivalenza, altera costanti, rinomina identificatori. Produce codice morto strutturalmente identico all'AST del codice reale, indistinguibile da esso solo per struttura. [Paper 3] |
Punti di iniezione del codice morto:
Diverse trasformazioni sono ispirate dalla ricerca crittografica sull'offuscamento sottoposta a revisione paritaria:
| Paper | Autori | Tecnica Implementata |
|---|---|---|
| [Paper 1] On the (Im)possibility of Obfuscating Programs | Barak, Goldreich, Impagliazzo, Rudich, Sahai, Vadhan, Yang | Casi di test per funzioni non offuscabili — strumento di verifica che testa se i segreti sopravvivono all'offuscamento |
| [Paper 2] Candidate iO and Functional Encryption for all Circuits | Garg, Gentry, Halevi, Raykova, Sahai, Waters | Decifratura a catena di stringhe — randomizzazione stile Kilian in cui la chiave di ogni voce dipende dalla stringa decodificata precedente |
| [Paper 3] iO from the Multilinear Subgroup Elimination Assumption | Gentry, Lewko, Sahai, Waters | Codice morto basato su mutazione (strutturalmente identico al codice reale); transizioni di stato aritmetiche modulari in CFF |
| [Paper 4] How to Use iO: Deniable Encryption, and More | Sahai, Waters | Inneschi per programmi punturati — controlli nascosti che si attivano su input segreti |
| [Paper 7] iO from Well-Founded Assumptions | Jain, Lin, Sahai | Iniezione di rumore ispirata a LPN in calcoli numerici |
| [Paper 9] iO from Bilinear Maps and LPN Variants | Ragavan, Vafa, Vaikuntanathan | Codifica XOR sparsa con pattern di errore dipendenti dalla posizione |
| [Paper 10] iO of Null Quantum Circuits and Applications | Bartusek, Malavolta | Test di circuito nullo per verifica qualità del codice morto; verifica dell'integrità personale (doppia modalità) |
Due strumenti di verifica misurano la qualità dell'offuscamento, situati in src/verification/:
verification/nullCircuitTest.ts)Offusca una funzione reale e una funzione "nulla" (stessa forma, non fa nulla), quindi confronta 14 metriche strutturali per valutare quanto siano distinguibili. Maggiore somiglianza = migliore offuscamento.
import { runNullCircuitTest } from './verification/nullCircuitTest';
const result = runNullCircuitTest(realCode, paramCount, stmtCount, threshold, targetTokens);
console.log('Similarità:', result.similarity); // 0.0-1.0
verification/unobfuscatableTests.ts)7 casi di test dalle dimostrazioni di impossibilità del Paper 1 che tentano di estrarre segreti da codice offuscato:
import { runAllTests, printSummary } from './verification/unobfuscatableTests';
console.log(printSummary(runAllTests(10000)));
Test: funzione punto (password), numeri magici, stringhe canarino, chiavi incorporate, URL, pattern regex, firme del flusso di controllo.
L'opzione --target-tokens controlla la dimensione dell'output tramite un budget di gonfiaggio che scala l'iniezione di codice morto (la principale leva di volume). Trasformazioni controllate dal budget:
| Rapporto Budget | Trasformazioni Abilitate |
|---|---|
| > 3 | Anti-debug, inneschi, CFF, predicati opachi, fusione a virgola |
| > 5 | Funzioni proxy, codifica chiavi proprietà, iniezione rumore, auto-integrità |
| > 8 | Esaurimento finestra di contesto |
| > 10 | Codifica variabili globali |
Il moltiplicatore del codice morto scala da 1x (rapporto 30) a 150x (rapporto 1500+), controllando il numero e la dimensione dei casi switch morti e dei rami dei predicati opachi.
src/
index.ts Punto di ingresso CLI
obfuscator.ts Orchestratore della pipeline principale (20 trasformazioni)
options.ts Sistema di budget e opzioni
types.ts Definizioni dei tipi AST
random.ts Generazione di nomi Unicode casuali (6-16 caratteri, 16 intervalli di script)
ast.ts Funzioni factory per nodi AST
keywords.ts Scoperta dinamica delle parole chiave (globalThis + pacchetto window)
globals.ts Gestione dello stato globale (mappe a prototipo nullo)
substitute.ts Utility per la sostituzione degli identificatori
declarations.d.ts Dichiarazioni di tipo per moduli
passes/
firstPass.ts Catalogazione degli identificatori
secondPass.ts Sostituzione degli identificatori + codifica delle stringhe
thirdPass.ts Iniezione di parametri fittizi
transforms/
antiDebug.ts Trappole eval("debugger") + cicli setInterval
tripwires.ts Controlli per input segreti su programma punturato [Paper 4]
noiseInjection.ts Rumore aritmetico ispirato a LPN [Paper 7]
controlFlowFlattening.ts while/switch + invio aritmetico modulare [Paper 3]
opaquePredicates.ts 15 predicati matematici sempre vero/falso
proxyFunctions.ts Dispatcher per appiattimento del grafo delle chiamate
contextExhaustion.ts Rumore ternario/void per riempimento contesto LLM
commaExpressions.ts Fusione di istruzioni tramite operatore virgola
globalVariableEncoding.ts eval+replace per globali
propertyKeyEncoding.ts Accesso calcolato a proprietà con registri per ambito
numberEncoding.ts 11 strategie di codifica bit a bit/aritmetica
selfIntegrity.ts Controlli runtime anti-manomissione [Paper 10]
stringArrayExtraction.ts XOR a catena + errori sparsi posizionali [Papers 2, 9]
deadCodeInjection.ts Codice morto basato su template + mutazione [Paper 3]
verification/
nullCircuitTest.ts Valutazione qualità codice morto [Paper 10]
unobfuscatableTests.ts Casi di test per estrazione segreti [Paper 1]
__tests__/ 300+ test unitari in 21 suite
tools/
obfuscate-package.ts Test di compatibilità pacchetti npm basati su webpack
tests/
input*.js File di input di test originali
# Esegue tutti i test
npm test
# Esegue una suite di test specifica
npx jest controlFlowFlattening
npx jest tripwires
npx jest noiseInjection
# Test contro pacchetti npm (clona repository, webpack-bundle, offusca, esegue test)
npm run obfuscate-package # Tutti i 10 pacchetti
npm run obfuscate-package -- minimist semver # Pacchetti specifici
Lo strumento tools/obfuscate-package.ts testa l'offuscatore contro pacchetti npm reali:
| Percorso | Contenuto |
|---|---|
dist/obfuscated/<pacchetto>/bundle.js | Il bundle webpack offuscato per ogni pacchetto |
dist/obfuscated/report.json | Report JSON completo con dimensioni dei bundle, stato di offuscamento, output dei test |
MIT - Copyright 2026 Nicholas Starke
mangle: falsecompress: false