
Ein JavaScript-Obfuskator basierend auf kryptografischen Indistinguishability-Obfuskationstechniken
Dieses Projekt erreicht keine Ununterscheidbarkeits-Verschleierung. Sie sollten dieses Produkt nicht zum Schutz von Geheimnissen verwenden. Es dient dazu, Reverse Engineering abzuschrecken, nicht zu verhindern
Ein JavaScript-Verschleierer, der entwickelt wurde, um Code sowohl für Menschen als auch für LLMs extrem schwer lesbar und analysierbar zu machen. Geschrieben in TypeScript. Implementiert Techniken aus peer-reviewter kryptografischer Verschleierungsforschung.
npm install
npm run build
# Grundlegende Verwendung
node dist/index.js input.js > output.js
# Mit Ziel-Token-Budget (Standard: 2.000.000)
node dist/index.js --target-tokens 500000 input.js > output.js
# Minimale Verschleierung (kleine Ausgabe)
node dist/index.js --target-tokens 10000 input.js > output.js
# Maximale Aufblähung (10M Tokens)
node dist/index.js --target-tokens 10000000 input.js > output.js
# Verwendung der Umgebungsvariable
INPUT_FILE=input.js node dist/index.js > output.js
# Hilfe
node dist/index.js --help
| Option | Standard | Beschreibung |
|---|---|---|
--target-tokens <n> | 2000000 | Zielgröße der Ausgabe in Tokens. Kleine Eingaben werden bis zu dieser Grenze aufgebläht. Große Eingaben erzeugen weniger Aufblähung, um innerhalb des Budgets zu bleiben. |
--help, -h | Hilfemeldung anzeigen |
npm run build # Kompiliere TypeScript nach dist/
npm run start # Führe den Verschleierer aus (liest input.js)
npm run test # Führe die Testsuite aus
npm run obfuscate-package # Führe Kompatibilitätstests gegen npm-Pakete aus
const { obfuscate } = require('./dist/obfuscator');
const code = 'function add(a, b) { return a + b; }';
const obfuscated = obfuscate(code);
// Mit Optionen
const obfuscated = obfuscate(code, { targetTokens: 500000 });
Der Verschleierer wendet 20 Transformationen in 4 Phasen an. Jede Stufe baut auf der vorherigen auf.
| Reihenfolge | Durchlauf | Datei | Beschreibung |
|-------|------|-------------|
| 9 | Durchlauf 1: Katalogisierung | passes/firstPass.ts | Durchläuft den AST und katalogisiert jeden Identifikator, erstellt eine Globals-Karte, die jedem einen zufälligen 6-16 Zeichen langen Unicode-Namen zuweist, der aus 16 Skriptbereichen (CJK, Hangul, Griechisch, Kyrillisch, Devanagari, Thai, Arabisch, Katakana usw.) stammt. |
| 10 | Durchlauf 2: Ersetzung | passes/secondPass.ts | Ersetzt alle Identifikatornamen durch ihre verschleierten Unicode-Äquivalente. Codiert require()-Argumente als String.fromCharCode(...). Codiert statische import/export-Quellen als Unicode-escaped String-Literale. Ersetzt superClass-Referenzen von Klassen, Vorlagenliteral-Ausdrücke, Destrukturierungsmuster. |
| 11 | Durchlauf 3: Dummy-Parameter | passes/thirdPass.ts | Injiziert 0-15 zufällige ungenutzte Parameter in jede Funktionsdeklaration und jeden Ausdruck. Überspringt Funktionen mit Rest-Parametern. Entfernt alle Kommentare. |
Toter Code wird an mehreren Stellen mit zwei Generierungsstrategien injiziert:
| Strategie | Quelle | Beschreibung |
|---|
Toter-Code-Injektionspunkte:
Mehrere Transformationen sind von peer-reviewter kryptografischer Verschleierungsforschung inspiriert:
Zwei Verifikationswerkzeuge messen die Verschleierungsqualität, befinden sich in src/verification/:
verification/nullCircuitTest.ts)Verschleiert eine echte Funktion und eine "Null"-Funktion (gleiche Form, tut nichts) und vergleicht dann 14 strukturelle Metriken, um zu bewerten, wie unterscheidbar sie sind. Höhere Ähnlichkeit = bessere Verschleierung.
import { runNullCircuitTest } from './verification/nullCircuitTest';
const result = runNullCircuitTest(realCode, paramCount, stmtCount, threshold, targetTokens);
console.log('Similarity:', result.similarity); // 0.0-1.0
verification/unobfuscatableTests.ts)7 Testfälle aus Paper 1's Unmöglichkeitsbeweisen, die versuchen, Geheimnisse aus verschleiertem Code zu extrahieren:
import { runAllTests, printSummary } from './verification/unobfuscatableTests';
console.log(printSummary(runAllTests(10000)));
Tests: Punktfunktion (Passwort), magische Zahlen, Kanarienvogel-Strings, eingebettete Schlüssel, URLs, Regex-Muster, Kontrollflusssignaturen.
Die Option --target-tokens steuert die Ausgabegröße über ein Aufblähungsbudget, das die Injektion von totem Code (dem primären Volumenhebel) skaliert. Budgetgesteuerte Transformationen:
| Budgetverhältnis | Aktivierte Transformationen |
|---|---|
| > 3 | Anti-Debug, Tripwires, CFF, undurchsichtige Prädikate, Komma-Zusammenlegung |
| > 5 | Proxy-Funktionen, Eigenschaftsschlüssel-Codierung, Rauschinjektion, Selbstintegrität |
| > 8 | Kontextfenster-Erschöpfung |
| > 10 | Globale Variablen-Codierung |
Dead-Code-Multiplikator skaliert von 1x (Verhältnis 30) bis 150x (Verhältnis 1500+), steuert die Anzahl und Größe der toten Switch-Fälle und undurchsichtigen Prädikat-Zweige.
src/
index.ts CLI-Einstiegspunkt
obfuscator.ts Haupt-Pipeline-Orchestrator (20 Transformationen)
options.ts Budgetsystem und Optionen
types.ts AST-Typdefinitionen
random.ts Zufällige Unicode-Namensgenerierung (6-16 Zeichen, 16 Skriptbereiche)
ast.ts AST-Knoten-Factory-Funktionen
keywords.ts Dynamische Schlüsselwort-Erkennung (globalThis + window-Paket)
globals.ts Globales Zustandsmanagement (Null-Prototyp-Karten)
substitute.ts Identifikator-Ersetzungs-Hilfsfunktionen
declarations.d.ts Modul-Typdeklarationen
passes/
firstPass.ts Identifikator-Katalogisierung
secondPass.ts Identifikator-Ersetzung + String-Codierung
thirdPass.ts Dummy-Parameter-Injektion
transforms/
antiDebug.ts eval("debugger")-Fallen + setInterval-Schleifen
tripwires.ts Punkturierte Programm-Geheimniseingabe-Prüfungen [Paper 4]
noiseInjection.ts LPN-inspiriertes arithmetisches Rauschen [Paper 7]
controlFlowFlattening.ts while/switch + modulare arithmetische Disposition [Paper 3]
opaquePredicates.ts 15 immer-wahr/falsch-Mathe-Prädikate
proxyFunctions.ts Aufrufgraph-Abflachungs-Verteiler
contextExhaustion.ts Ternärer/void-Rauschen für LLM-Kontextfüllung
commaExpressions.ts Anweisungszusammenlegung via Komma-Operator
globalVariableEncoding.ts eval+replace für Globals
propertyKeyEncoding.ts Berechneter Eigenschaftszugriff mit bereichsspezifischen Registern
numberEncoding.ts 11 bitweise/arithmetische Codierungsstrategien
selfIntegrity.ts Anti-Manipulations-Laufzeitprüfungen [Paper 10]
stringArrayExtraction.ts Verkettete XOR + spärliche Positionsfehler [Papers 2, 9]
deadCodeInjection.ts Vorlagen- + mutationsbasierter toter Code [Paper 3]
verification/
nullCircuitTest.ts Toter-Code-Qualitätsbewertung [Paper 10]
unobfuscatableTests.ts Geheimnisextraktions-Testfälle [Paper 1]
__tests__/ 300+ Unit-Tests in 21 Suiten
tools/
obfuscate-package.ts Webpack-basierte npm-Paket-Kompatibilitätstests
tests/
input*.js Ursprüngliche Testeingabedateien
# Alle Tests ausführen
npm test
# Eine bestimmte Testsuite ausführen
npx jest controlFlowFlattening
npx jest tripwires
npx jest noiseInjection
# Gegen npm-Pakete testen (klont Repos, webpack-bundelt, verschleiert, führt Tests aus)
npm run obfuscate-package # Alle 10 Pakete
npm run obfuscate-package -- minimist semver # Spezifische Pakete
Das Werkzeug tools/obfuscate-package.ts testet den Verschleierer gegen reale npm-Pakete:
| Pfad | Inhalt |
|---|---|
dist/obfuscated/<package>/bundle.js | Das verschleierte webpack-Bundle für jedes Paket |
dist/obfuscated/report.json | Vollständiger JSON-Bericht mit Bundlegrößen, Verschleierungsstatus, Testausgabe |
MIT - Copyright 2026 Nicholas Starke
| Reihenfolge | Transformation | Datei | Beschreibung |
|---|
| 1 | Anti-Debug-Fallen | transforms/antiDebug.ts | Injiziert eval("debugger")-Anweisungen und 10-20 setInterval-Schleifen mit Primzahl-Intervallen (5s-600s), die wiederholt Debugger-Breakpoints auslösen. Jede Instanz verwendet eindeutige codierte Zeichenfolgen. |
| 2 | Punkturierte Programm-Tripwires | transforms/tripwires.ts | Bettet versteckte Prüfungen ein, die Parameter-Hashes mit geheimen Werten vergleichen. 5 Hash-Muster (bitweiser Fingerabdruck, modulare Arithmetik, charCodeAt, numerischer Hash, typeof+length). Löst stille Zustandskorruption, busy loops oder wirft bei geheimen Eingaben. [Paper 4] |
| 3 | LPN-Rauschinjektion | transforms/noiseInjection.ts | Fügt zufälliges Rauschen in arithmetische Berechnungen hinzu und hebt es durch getrennte Pfade wieder auf. 6 Muster: add/sub, XOR, mul/div, geteilte Doppelvariable, berechnete Hash-Kette, Bit-Rotate. Zwischenwerte sind ohne Verfolgung der vollständigen Aufhebung bedeutungslos. [Paper 7] |
| Reihenfolge | Transformation | Datei | Beschreibung |
|---|
| 4 | Kontrollfluss-Abflachung | transforms/controlFlowFlattening.ts | Wandelt Funktionskörper in while(true) { switch((_s * P) % M) { ... } }-Zustandsautomaten um mit modularer arithmetischer Disposition — Fallwerte werden durch (stateId * multiplier) % modulus unter Verwendung zufälliger Primparameter codiert. [Paper 3] |
| 5 | Undurchsichtige Prädikate | transforms/opaquePredicates.ts | Injiziert if-Bedingungen, die immer true oder false ergeben, aber mathematisch schwer zu beweisen sind (z. B. (x*x+x)%2===0). 15 Prädikatformeln in den Kategorien modulare Arithmetik, bitweise Operatoren und Typüberprüfung. |
| 6 | Proxy-Funktionen | transforms/proxyFunctions.ts | Leitet alle Funktionsaufrufe über zwei Verteiler: _fc(fn, ...args) für einfache Aufrufe, _mc(obj, prop, ...args) für Methodenaufrufe. Verwendet Function.prototype.apply, das in einer lokalen Variablen erfasst wird, für Robustheit. |
| 7 | Kontextfenster-Erschöpfung | transforms/contextExhaustion.ts | Wickelt Ausdrücke in tief verschachtelte ternäre Operatoren mit undurchsichtigen Bedingungen, void-Ausdrucksketten und bedingte void-Padding. Zwingt LLMs, Kontextfenster-Tokens für Rauschen zu verschwenden. |
| 8 | Komma-Ausdruckszusammenlegung | transforms/commaExpressions.ts | Fasst aufeinanderfolgende Ausdrucksanweisungen zu einzelnen Komma-Ausdrücken zusammen: a(); b(); return c() wird zu return a(), b(), c(). |
| Reihenfolge | Transformation | Datei | Beschreibung |
|---|
| 12 | Globale Variablen-Codierung | transforms/globalVariableEncoding.ts | Ersetzt Verweise auf Globals (dynamisch von globalThis + window-Paket entdeckt) durch eval("Name<suffix>".replace(new RegExp("<suffix>$"), "")). Beide Zeichenketten fließen durch das String-Array. |
| 13 | Eigenschaftsschlüssel-Codierung | transforms/propertyKeyEncoding.ts | Konvertiert Punktzugriff in berechneten Zugriff mit bereichsspezifischen Registern. Bereichsübergreifender Zugriff funktioniert, weil alle Suffixe zur Laufzeit via .replace() denselben Eigenschaftsnamen auflösen. |
| 14 | Zahlen-Codierung | transforms/numberEncoding.ts | 11 Codierungsstrategien: shift+add, XOR-Identität, Komplement, Division, verschachtelte Shifts, doppeltes NOT, modular usw. Jede Instanz wird eindeutig generiert. Überspringt Eigenschaftsschlüssel und Switch-Case-Werte. |
| 15 | Selbstintegritätsprüfung | transforms/selfIntegrity.ts | Injiziert 2-4 Laufzeitprüfungen: eval-nativer Code-Verifikation, Function.prototype.toString-Integrität, Timing-Anomalieerkennung, Codestruktur-Validierung. Anti-Manipulations-Reaktionen: busy wait, throw, stille Korruption. [Paper 10] |
| 16 | String-Array-Extraktion | transforms/stringArrayExtraction.ts | Sammelt alle Zeichenketten in einem einzigen Array mit verketteter XOR-Entschlüsselung (Schlüssel für Eintrag N hängt vom entschlüsselten Inhalt von Eintrag N-1 ab) und spärlichen positionsabhängigen Fehlermustern (jedes Zeichen erhält einen anderen XOR-Schlüssel, mit LPN-inspirierten spärlichen Fehlern an ausgewählten Positionen). [Papers 2, 9] |
| 17 | Console-Stubs | obfuscator.ts | Entdeckt dynamisch alle console-Methoden und setzt jede auf eine No-op-Funktion. |
| 18 | Terser-Minifizierung | obfuscator.ts | Entfernt Leerzeichen/Formatierung via terser (mangle: false, compress: false). Fällt auf regex-basierte Entfernung zurück, wenn terser die Ausgabe nicht parsen kann. |
| Vorlagenbasiert | transforms/deadCodeInjection.ts | 9 Vorlagentypen: Schleifenakkumulation, Array-Aufbau, Objektmanipulation, String-Verkettung, verschachtelte Bedingungen, try/catch, while-Countdown, Switch-Berechnung, Bitketten. Vorlagen referenzieren reale Bereichsvariablen. |
| Mutationsbasiert | transforms/deadCodeInjection.ts | Klont ECHTE Anweisungen und mutiert sie: tauscht Operatoren innerhalb von Äquivalenzgruppen, stört Konstanten, benennt Identifikatoren um. Produziert AST-strukturell identischen toten Code, der sich strukturell nicht von echtem Code unterscheiden lässt. [Paper 3] |
| Paper | Autoren | Implementierte Technik |
|---|
| [Paper 1] On the (Im)possibility of Obfuscating Programs | Barak, Goldreich, Impagliazzo, Rudich, Sahai, Vadhan, Yang | Unverschleierbare Funktionstestfälle — Verifikationstool, das testet, ob Geheimnisse die Verschleierung überleben |
| [Paper 2] Candidate iO and Functional Encryption for all Circuits | Garg, Gentry, Halevi, Raykova, Sahai, Waters | Verkettete String-Entschlüsselung — Kilian-artige Randomisierung, bei der der Schlüssel jedes Eintrags vom vorherigen dekodierten String abhängt |
| [Paper 3] iO from the Multilinear Subgroup Elimination Assumption | Gentry, Lewko, Sahai, Waters | Mutationsbasierter toter Code (strukturell identisch mit echtem Code); modulare arithmetische Zustandsübergänge in CFF |
| [Paper 4] How to Use iO: Deniable Encryption, and More | Sahai, Waters | Punkturierte Programm-Tripwires — versteckte Prüfungen, die bei geheimen Eingaben ausgelöst werden |
| [Paper 7] iO from Well-Founded Assumptions | Jain, Lin, Sahai | LPN-inspirierte Rauschinjektion in numerischen Berechnungen |
| [Paper 9] iO from Bilinear Maps and LPN Variants | Ragavan, Vafa, Vaikuntanathan | Spärliche XOR-Codierung mit positionsabhängigen Fehlermustern |
| [Paper 10] iO of Null Quantum Circuits and Applications | Bartusek, Malavolta | Null-Schaltkreis-Test zur Qualitätsprüfung von totem Code; Selbstintegritätsprüfung (Dual-Modus) |