Am Ende des Reverse Engineerings steht nicht einfach nur die Erkenntnis: „Ich weiß, was dieser Code berechnet.“ Die Logik steckt weiterhin in ihrer ursprünglichen Laufzeitumgebung – und genau dann fällt die entscheidende Architekturentscheidung: Wird daraus eine reine Funktion für die CI, oder ein externer Prozess, den jemand im Betrieb ständig im Auge behalten muss? Wer hier die falsche Form wählt, zahlt die zuvor gesparte Zeit später mit Zinsen zurück.
Der Überblick über die vier Phasen fasst diesen Schritt in einer Zeile zusammen: „Phase 4: über die Transportebene degradieren.“ Dieser Artikel führt das aus. Die Kernaussage lautet: Mit jeder Stufe nach unten wachsen Abhängigkeitsfläche, Fehlerbilder und Deployment-Aufwand um eine Größenordnung – deshalb kämpft man standardmäßig für die höhere Stufe.
Drei Zielformen – und eine feste Reihenfolge
Für reverse-engineerte Logik gibt es genau drei Zielformen. Ihre Reihenfolge sollte in euren Konventionen festgeschrieben sein, statt jedes Mal nach dem Motto „Hauptsache, es läuft zuerst“ entschieden zu werden:
Nativer Rewrite. Die Logik wird in der Zielsprache neu umgesetzt, vollständig von der ursprünglichen Laufzeit entkoppelt und nur auf die Standardbibliothek gestützt. Voraussetzung ist, dass die Algorithmusfamilie korrekt erkannt wurde: Sobald der Fingerprinting-Schritt bestanden ist, stammen 90 % aus der öffentlichen Implementierung; die verbleibenden Abweichungen werden gezielt behandelt. Das Ergebnis landet als reine Funktion.
Lokale JS-Engine mit Minimalfragment. Manche Logik lässt sich kurzfristig nicht wirtschaftlich bereinigen. Dann bleibt ein kleiner Ausschnitt des ursprünglichen JavaScript erhalten und die benötigten wenigen Dutzend Zeilen laufen in einem lokalen Node/V8 – nicht die gesamte Seite.
Passive Browser-Bridge. Bestimmte Zustände existieren ausschließlich in einer echten, eingeloggten Seitenlaufzeit: etwa eine zur Laufzeit bereitgestellte Signatur oder eine sitzungsgebundene dynamische Kennung. Statisch lassen sie sich nicht rekonstruieren und vorerst nur im Browser auslesen. Das ist eine Übergangslösung, muss in den Interface-Notizen markiert werden und darf niemals zum Standard-Rollout werden.
Warum jede Stufe deutlich teurer wird
Die Reihenfolge ist nicht willkürlich: Die Kosten der drei Stufen steigen nicht linear. Jede ist ungefähr eine Größenordnung aufwendiger als die vorherige.
Stufe | Abhängigkeitsfläche | Fehlerbild | CI-tauglich? |
|---|---|---|---|
Nativer Rewrite | Standardbibliothek, keine externen Prozesse | Abweichende Ausgabe, auffindbar mit einem | Ja – es ist eine reine Funktion |
Lokale JS-Engine | Eine zusätzliche Node-Laufzeit; der V8-Kontext ist nicht threadsicher, Parallelität braucht einen Lock | Engine-Version, fehlende globale Variable, von der das Fragment abhängt | Gerade noch – die Engine muss installiert werden |
Passive Browser-Bridge | Ein echtes Chrome + Extension + eine manuell gepflegte Sitzung + ein lokaler Loopback-Kanal | Seite nicht geöffnet, Sitzung abgelaufen, Struktur geändert, Tab geschlossen | Nein – ein realer Mensch muss beteiligt sein |
Ein Fehler der ersten Stufe wird von einem Unit-Test abgefangen; ein Fehler der dritten lautet: „Der Nutzer hat diesen Tab heute geschlossen.“ Wer etwas, das als reine Funktion laufen könnte, zur Lösung der dritten Stufe macht, bindet bei jedem Aufruf einen Menschen ein. Als Referenz: Sobald die Algorithmusfamilie identifiziert ist, kann ein verschleiertes Signatur-SDK als eigenständige Implementierung mit weniger als 600 Zeilen landen, die nur das eingebaute crypto benötigt und auf der ersten Stufe läuft. Was vermeintlich nur über die Browser-Bridge geht, ist meist schlicht ein Algorithmus, der noch nicht vollständig erkannt wurde.
Klare Grenze für die passive Bridge: ein Snapshot, niemals aktiv
Eine passive Bridge gerät genau dann außer Kontrolle, wenn sie anfängt, „mitzuhelfen“: automatisch zu aktualisieren, sich automatisch einzuloggen oder auf Ladevorgänge zu warten. Jedes zusätzliche „automatisch“ verschiebt sie vom Weiterleiter in Richtung Crawler. Die Grenze muss daher extrem eng gezogen sein. Diese Regeln wurden auf die harte Tour gelernt:
Genau einen Snapshot erfassen, die Seite niemals verändern. Cookies, Sitzungsstatus und Seitenlaufzeit einer bereits geöffneten Seite werden jeweils einmal abgefragt – und nur einmal. Keine Tabs erstellen, nicht aktualisieren, nicht navigieren, nicht fokussieren, nicht per Polling warten. Fehlt die Seite, fehlt sie eben; die Bridge öffnet sie nicht im Namen des Nutzers.
Fehlende Voraussetzungen sofort mit einem eindeutigen Fehler melden. Gibt es keinen passenden Tab, folgt tab_unavailable; ist die Seite geöffnet, aber nicht eingeloggt, folgt not_logged_in; ist die Sitzung aktiv, aber die Laufzeit noch nicht bereit, folgt runtime_unavailable. Jeder dieser drei Fehlercodes steht für einen realen Zustand und eine konkrete nächste Aktion – auf die Seite warten, einloggen oder das Ziel wechseln –, statt dem Aufrufer nur ein allgemeines „fehlgeschlagen“ zum Raten zu geben.
Sensible Zustände verlassen den Browser nie. Die Extension verlangt keine Berechtigungen für cookies oder webRequest. Sie fragt ausschließlich einen bereits geöffneten passenden Tab ab, führt die Anfrage im Kontext dieser Seite aus und entfernt Felder vor der Rückgabe. Cookies und Signaturzustand der Seite verlassen Chrome zu keinem Zeitpunkt; standardmäßig verbindet sich der Kanal mit einer lokalen Loopback-Adresse. Die Bridge transportiert Ergebnisse, keine Zugangsdaten.
Warum wenige Plattformen 15 Scopes brauchen
Die passive Bridge leitet ausschließlich per Whitelist freigegebene Requests weiter. Pfad, Parameter und Referer werden dabei durch einen Adapter begrenzt. Besonders kontraintuitiv ist die Granularität: Für nur eine Handvoll Plattformen gibt es insgesamt 15 Scopes, denn Scopes werden nach „Seitenkontext“ zugeschnitten, nicht nach „Plattform“. TikTok besteht etwa aus Creative Center, Top Ads, Creator-Plattform, Influencer-Bibliothek und Ads Manager – fünf eigenständigen Scopes mit fünf unabhängigen Sitzungszuständen und Seitenlaufzeiten. Wer im Anzeigen-Backend eingeloggt ist, erhält damit nicht automatisch die Laufzeit der Creator-Plattform. Ein Scope pro Plattform wirkt zunächst einfacher, führt aber beim ersten Fall „In Subsite A eingeloggt, Subsite B kann trotzdem nicht bedient werden“ direkt zurück an den Start. Bei Xiaohongshu sind Hauptseite, App-äquivalente Pfade und Creator-Marktplatz entsprechend drei getrennte Scopes.
Dieselbe Granularität gilt für die Planung: Der Lock greift nur auf Ebene der Plattformfamilie. Anfragen innerhalb derselben Familie, etwa der Douyin-Familie, laufen seriell. Sie verwenden denselben echten Tab; parallele Zugriffe auf einen Seitenkontext würden sich gegenseitig in die Quere kommen. Unterschiedliche Familien wie Douyin und Xiaohongshu können dagegen parallel arbeiten, denn sie nutzen unabhängige Tabs. Innerhalb einer Familie kommt zusätzlich ein Mindestabstand zwischen Requests hinzu. Zu grob gewählt, serialisiert der Lock Arbeit, die parallel möglich wäre; zu fein gewählt, kollidieren Anfragen im selben Tab. Die Plattformfamilie ist genau die natürliche Grenze dafür, was dieselbe Seitenlaufzeit teilt.
Login-Handoff: der einzig erlaubte manuelle Eingriff
Die passive Bridge bedient keine Seiten selbst, aber Sitzungen laufen ab. Die Lösung besteht darin, den menschlichen Eingriff auf eine explizite Einmalaktion zu reduzieren: Ein interaktiver Befehl startet einen Handoff, das Programm öffnet die entsprechende Geschäftsseite über das Betriebssystem, wartet darauf, dass ihr euch manuell einloggt und die Seite bereit ist, und wiederholt anschließend die ursprüngliche Anfrage. Die Extension klickt dabei keine Buttons, füllt keine Formulare aus und exportiert keine Cookies. Der Login erfolgt in einem echten Browser; das Programm setzt die Anfrage erst danach fort.
Die zentrale Vorgabe: Dieser Ablauf darf nie implizit ausgelöst werden. Ein nicht interaktiver Befehl – etwa in CI oder als geplanter Task – darf niemals einen Browser öffnen. Er gibt sauber einen Sitzungsfehler zurück und überlässt die Entscheidung der aufrufenden Ebene. Der Handoff muss außerdem Fehlinterpretationen vermeiden: Nach erfolgreichem Login erhält die Laufzeit nur eine kurze zusätzliche Wartezeit von maximal 20 Sekunden in der Implementierung, bevor ein Ergebnis feststehen muss. Hat die Geschäftsseite bereits auf eine Kontoseite weitergeleitet, der der Ziel-Interface-Kontext fehlt, endet die aktuelle Phase sofort. Ein deterministisches „hier geht es nicht weiter“ darf nicht mit „lädt noch“ verwechselt und stumpf weiter abgewartet werden. Ein degradierungsfähiger Ablauf markiert diese Phase als unavailable und läuft weiter, statt den gesamten Prozess scheitern zu lassen.
Phasenstatus: erledigt, bewusst übersprungen oder Sitzung erforderlich
Die gemeinsame Grundlage all dessen: Keine Phase darf nur „Erfolg“ oder „Fehler“ zurückgeben. In einer Orchestrierungs-Pipeline kann das Ergebnis jeder Phase sechs Formen annehmen: completed (erledigt), empty (ausgeführt, aber ohne Daten), ready (vorbereitet, wartet auf Übermittlung), skipped (regelbasiert bewusst übersprungen), unavailable (aktuell nicht verfügbar, meist weil eine Sitzung benötigt wird) und blocked (eine Voraussetzung ist nicht erfüllt).
„Bewusst übersprungen“, „braucht eine Sitzung“ und „tatsächlich leer“ sind drei grundverschiedene Signale. Liefert ein Schritt nur ein undurchsichtiges Ergebnis zurück, lässt sich nicht erkennen, ob leer bedeutet „soll leer sein“ oder „die Sitzung ist unbemerkt abgelaufen“. Eine solche Pipeline ist nicht betreibbar. Modelliert den Phasenstatus als endliches Enum; dann kann die Orchestrierungsschicht – Skript oder Modell – daraus ableiten, ob sie degradieren, neu authentifizieren oder abbrechen soll. Das ist dasselbe Prinzip wie die drei Fehlercodes der passiven Bridge, nur auf die Ebene des gesamten Ablaufs gehoben.
Mit dem Modell entscheiden, auf welcher Stufe eine Fähigkeit landet
Erst an dieser Stelle kommt das Modell ins Spiel – und zwar bewusst zurückhaltend: Es bereinigt die Logik nicht für euch, sondern hilft zu beurteilen, ob und wie weit sie bereinigt werden sollte. Das ist eine Architekturentscheidung, kein Signatur-Crack. Die Kernfrage lautet: Lässt sich der benötigte Zustand statisch rekonstruieren oder ist er nur zur Laufzeit verfügbar? Anschließend wird der Bereinigungsaufwand gegen die Änderungsfrequenz abgewogen. Verschiedene Schritte stellen dabei unterschiedliche Anforderungen an das Modell:
Schritt | Benötigte Fähigkeit | Wahl | model id |
|---|---|---|---|
Das gesamte Modul lesen, um die Abhängigkeitsfläche zu erfassen | Langer Kontext, liest den Call-Graph in einem Durchgang | Kimi K3 |
|
Die Stufenzuordnung in beide Richtungen begründen und „Hauptsache, es läuft“ widersprechen | Starkes Reasoning; argumentiert dafür, einen zusätzlichen Tag in die Bereinigung zu investieren | Claude Opus 5 |
|
Erste Triage für Dutzende bis Hunderte Fähigkeiten im Batch | Günstig, hohe Parallelität | Claude Sonnet 5 |
|
Ursachenanalyse nach einer Degradierung | Mittleres Reasoning; erklärt anhand eines Fehlerlogs | GPT-5.6 Sol |
|
Die zweite Stufe ist die wichtigste. Der häufigste Fehler bei der Zuordnung: Das Modell übernimmt euren Tonfall von „Hauptsache, es funktioniert“ und antwortet, die Browser-Bridge sei am einfachsten. Dann spiegelt es euch lediglich, statt die langfristigen Kosten einzupreisen. Ein Modell mit starkem Reasoning hält dagegen: „Dieses Segment ist ein Standard-Hash plus eine konstante Abweichung; ein Tag für eine reine Funktion lohnt sich, und es gehört nicht auf die Bridge.“ Verlasst euch nicht auf mein Wort, sondern testet es: Nehmt drei Logikstücke, darunter mindestens eines mit einer Zuordnung, die ihr bereits als korrekt kennt, und gebt claude-opus-5 sowie gpt-5.6-sol denselben Prompt: „Gib eine Stufenzuordnung an, begründe sie und widersprich einer vorschnellen Verlagerung auf die Browser-Bridge.“ Achtet dann auf genau eines: Kämpft das Modell dafür, euch eine Stufe nach oben zu bringen, oder landet es bequem standardmäßig auf der dritten?
Der eigentliche Hinderungsgrund: Wechselkosten
Vier Stufen von drei Anbietern bedeuten drei SDKs, drei Authentifizierungsschemata und drei Fehlerformate. Den Client umzuschreiben, nur um zwischen den Schritten das Modell zu wechseln, lohnt sich nicht. Deshalb verwenden die meisten am Ende ein Modell für alles – und gerade bei der Stufenzuordnung, die das Reasoning-Modell am dringendsten braucht, ein Modell, das nur bestätigt.
AIReiter glättet diese Ebene: ein Key, ein OpenAI-kompatibles Interface, alle vier Stufen dahinter. Zum Wechseln wird lediglich das Feld model im Request-Body geändert.
# Argumentation zur Stufenzuordnung: die Reasoning-Stufe
curl https://aireiter.com/api/v1/chat/completions \
-H "Authorization: Bearer $AIREITER_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-opus-5",
"messages": [{"role": "user", "content": "<placement prompt + the reversed logic fragment + dependency list>"}]
}'
# Erste Triage im Batch: ein Feld ändern
# "model": "claude-sonnet-5"
# Ursachenanalyse nach Degradierung:
# "model": "gpt-5.6-sol"
Nutzt ihr bereits das OpenAI SDK? Setzt base_url auf https://aireiter.com/api/v1. Mit dem Anthropic SDK verwendet ihr POST /api/v1/messages und denselben Key. Preislich liegen Claude-Modelle 30 % unter dem Listenpreis, GPT-Modelle bei der Hälfte des Preises. Die Kosten dieses Workflows konzentrieren sich auf zwei Bereiche: die erste Batch-Triage von Dutzenden bis Hunderten Fähigkeiten mit Sonnet und hohem Anfragevolumen sowie das Lesen eines ganzen Moduls zur Ermittlung seiner Abhängigkeitsfläche mit Kimi und vielen Tokens pro Anfrage. Die Batch-Triage läuft mit einem Claude-Modell – der Rabatt greift also genau beim dichtesten Schritt. Auch die Reasoning-basierte Argumentation zur Stufenzuordnung nutzt ein Claude-Modell mit 30 % Rabatt. Die Long-Context-Stufe von Kimi K3 ist mit demselben Key verfügbar.
Ohne Anmeldung ausprobieren – gebt zunächst ein paar Logikfragmente manuell ein und beobachtet, ob die beiden Modelle euch nur spiegeln oder bei der Frage „Soll das auf die Browser-Bridge?“ widersprechen.
Fazit
Reverse-engineerte Logik in eine Zielumgebung zu überführen, ist kein rein technisches Problem, sondern eine Kostenfrage. Die Drei-Stufen-Leiter – nativer Rewrite > lokale JS-Engine > passive Browser-Bridge – lässt sich nicht umdrehen. Jede Stufe nach unten tauscht eine reine Funktion gegen einen Prozess mit externen Abhängigkeiten, menschlichem Eingriff und einem offenen Live-Tab. Die passive Bridge ist kein verbotener Bereich, sondern eine Übergangskomponente mit strengen Grenzen: ein Snapshot, niemals aktiv; ein expliziter Fehler, sobald eine Seite fehlt; sensible Zustände verlassen den Browser nie; Login nur über expliziten Handoff; Phasenstatus stets eindeutig lesbar. Werden diese Regeln eingehalten, ist sie ein verlässlicher Notbehelf. Fällt nur eine davon weg, entsteht eine Blackbox, die niemand mehr warten will. Das Modell hilft bei der Entscheidung, auf welcher Stufe eine Fähigkeit landen sollte, und hält gegen die Trägheit von „Hauptsache, es läuft“ dagegen. Ob jeder Rewrite fachlich korrekt ist, entscheidet jedoch nicht das Modell, sondern differenzielles Testen.
