Communitygithub.com

leanrea

Reverse Engineering von ausgelieferter Software mit einfachen lokalen CLI-Tools, ohne MCP. Deckt Electron/JS-Bundles, native Mach-O/ELF/PE, Go/Rust/.NET/Flutter/WASM-Binaries, APKs, SQLite, pcaps, Firmware und Websites ab.

Was ist leanrea?

Dieses Skill ermöglicht es einem KI-Agenten, ausgelieferte („shipped“) Software effizient zu reverse-engineeren, ohne auf komplexe oder externe MCP-Server angewiesen zu sein. Es beschreibt einen optimierten, schnellen Arbeitsablauf („fast path“) für eine Vielzahl von Binärformaten und Anwendungstypen, darunter Electron-Apps, native Mach-O/ELF/PE-Binaries, Go-, Rust-, .NET- und Flutter-Programme sowie APKs, SQLite-Datenbanken, Netzwerk-Mitschnitte (pcaps) und Firmware. Der Agent wird angewiesen, zuerst mit `file -b T` und magischen Bytes zu routen, dann eine kostengünstige Bestandsaufnahme (z. B. Symbole, Importe, Strings) durchzuführen, bevor er Code dekompiliert oder liest. Es werden konkrete, optimierte Shell-Befehle für jede Zielplattform bereitgestellt, die typischerweise nur 2–4 Tool-Aufrufe erfordern. Die Regeln betonen die Arbeit an Kopien, das Vermeiden von `cat` für große Dateien, das batching unabhängiger Aufrufe in einem Shell-Befehl und das Belegen von Behauptungen mit Beweisen aus den extrahierten Daten. Das Skill ist plattformunabhängig und setzt voraus, dass die gängigen lokalen Entwicklertools (otool, nm, strings, jq, rg, etc.) installiert sind. Es unterstützt sowohl macOS als auch Linux und Windows (via WSL/Cygwin).

Funktioniert mit~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/aicodeking/leanrea/tree/HEAD/leanrea

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

leanrea: schneller Pfad

Diese Tools kennen Sie bereits. In dieser Datei sind nur der schnellste Befehl für jedes Ziel und die Fallstricke aufgeführt.

Regeln

  • Arbeiten Sie an einer Kopie (cp -c auf APFS ist sofort). Legen Sie jede Extraktion in einem neuen Verzeichnis unter $TMPDIR/re/<name> an. Verwenden Sie eine vorhandene Extraktion wieder, falls vorhanden.
  • Routen Sie zuerst mit file -b T und den magischen Bytes. Führen Sie als nächstes die günstigste Bestandsaufnahme durch. Erst dann dekompilieren oder Code lesen.
  • rg überspringt versteckte und ignorierte Dateien, und Bundler verstecken Code (Electron: .webpack/, .vite/). Durchsuchen Sie extrahierte Bäume immer mit rg -uu.
  • Verwenden Sie niemals cat für eine große oder minimierte Datei. Schneiden Sie sie: rg -o '.{0,200}NEEDLE.{0,200}' F | head. Schreiben Sie eine Disassemblierung einmal in eine Datei, dann durchsuchen Sie diese Datei mit grep.
  • Bündeln Sie unabhängige Sondierungen in EINEN Shell-Aufruf mit ; und echo '--- name'-Markierungen (in Anführungszeichen: zsh expandiert ein bloßes ==x). Begrenzen Sie jede Ausgabe mit head oder -m.
  • Antworten Sie mit Beweisen. Markieren Sie in der Antwort jede Behauptung als gesehen (mit Datei:Offset oder einem Symbol/String) oder abgeleitet. Eine Tatsache, die Sie nicht gefunden haben, ist unbekannt, nicht „nicht vorhanden“. Statisches Lesen ist keine beobachtete Ausführung.
  • Ein fehlendes Tool ist kein Hindernis. Verwenden Sie den Fallback in derselben Zeile oder brew install <x>, wenn der Benutzer es erlaubt.
  • Tool-Aufrufe kosten mehr als Bytes. Zielen Sie auf 2–4 Tool-Aufrufe: einen gebündelten Recon-Aufruf, ein oder zwei gezielte Schnitte, dann antworten. Hören Sie auf, wenn für jedes angefragte Element Beweise vorliegen. Verifizieren Sie nicht erneut, was Sie bereits gesehen haben.

Erster Schritt: ein Aufruf pro Ziel, einfügen und ausführen

Native (Mach-O):

T=./bin; D=$TMPDIR/re/$(basename $T); mkdir -p $D; file $T; lipo -info $T; otool -L $T; echo '--- EXPORTS'; nm -gU $T | head -150; echo '--- IMPORTS'; nm -u $T | rg -v '^__Z|napi_' | tr '\n' ' '; echo; echo '--- STRINGS'; strings -a -n 6 $T | rg -v '^[_$.]' | head -400; otool -tV $T > $D/dis.txt; echo '--- FUNCS'; rg '^[_a-zA-Z].*:$' $D/dis.txt | rg -v '^_?_?Z?N?St3' | head -150

Dann lesen Sie eine Funktion: awk '/^FUNC_LABEL:$/{p=1;next} p&&/^[_a-zA-Z].*:$/{exit} p' $D/dis.txt | rg 'bl|b\.|cmp|literal|mov\s+w2'.

Electron:

A=./app.asar; X=$TMPDIR/re/asar; rm -rf $X; npx -y @electron/asar extract $A $X && jq '{name,version,main}' $X/package.json; find $X -path '*/node_modules' -prune -o -type f \( -name '*.js' -o -name '*.node' \) -print | head -60; ls ${A}.unpacked/node_modules 2>/dev/null; rg -uu -l --glob '!node_modules' 'exposeInMainWorld' $X

Dann schneiden Sie die Nadel über das Bundle: rg -uu -o --glob '!node_modules' '.{0,250}NEEDLE.{0,250}' $X | head -20.

Go: go version -m T allein beantwortet normalerweise die Frage.

Router

Ziel (erkennen)Schnellster Pfad
Electron-App (*.app/Contents/Resources/app.asar)npx -y @electron/asar extract app.asar X (auch app.asar.unpacked/ für .node-Addons sehen). Einstiegspunkt: jq .main X/package.json. Oberfläche: `rg -n -o '.{0,120}(ipcMain.(handle
Web-Bundle / minifiziertes JSsourceMappingURL finden. Wenn die Map sourcesContent hat, die Quellen ausgeben: jq -r '.sources[]'. Für webpack: die Modul-IDs durchsuchen, dann um den Treffer herum schneiden. Für Pretty-Print: npx -y prettier --parser babel F > F.pretty.js, dann mit Zeilenbereichen lesen.
Hermes / bytenode / V8-SnapshotHermes-Magie ist c6 1f bc 03 (index.android.bundle): hermes-dec / hbc-decompiler verwenden. .jsc (bytenode) kann nicht dekompiliert werden: Strings und Laufzeit-Hooks verwenden.
Mach-O (file: Mach-O)lipo -info (zuerst thin: lipo -thin arm64 -o T1 T). Dann: otool -L (Bibliotheken); xcrun dyld_info -exports -imports; nm -gU (Exporte) / nm -u (Importe = die Fähigkeitskarte); strings -a -n 6; `otool -l
Nativer Code / Logikotool -tV T > $D/dis.txt (oder llvm-objdump -d --no-show-raw-insn -C). Die Funktion finden: rg -n '^_?.*Name.*:$'. Den Call-/String-Pfad lesen: `awk '/^FUNC:/{p=1} p&&/^[_a-zA-Z].*:$/&&!/FUNC/{exit} p' dis.txt
ELF / PEreadelf -hlSW, readelf -dW (NEEDED), nm -D --defined-only, objdump -d -M intel. PE: objdump -x, pefile/wrestool für Ressourcen. checksec: pwn checksec.
Go (__go_buildinfo, .go.buildinfo)go version -m T liefert Toolchain, Pfad, Mod, Abhängigkeiten und Build-Flags in einem Aufruf. Ohne Go: `strings -a T
RustAbhängigkeiten (cargo-auditable): cargo audit bin T, oder .dep-v0 / __DATA,.dep-v0 extrahieren und zlib-inflaten. Compiler: `strings -a T
.NET (file: Mono/.Net)ilspycmd -p -o X T.dll (Installation: dotnet tool install -g ilspycmd), dann rg. P/Invoke: rg DllImport X. NativeAOT/IL2CPP sind nativ: die nativen Zeilen verwenden.
Android APKjadx -d X --show-bad-code a.apk dann rg. Nur Ressourcen/Manifest: apktool d --no-src -o X a.apk. Schnellansicht: unzip -l a.apk. lib/*/libflutter.so bedeutet Flutter (Dart AOT: blutter); libhermes.so bedeutet React Native (Hermes-Zeile).
Flutter-Snapshot-HashIn libapp.so die Magie f5 f5 dc dc finden; die 32 Hex-Zeichen bei +20 sind der Snapshot-Hash. Einer Dart-Version zuordnen.
WASMwasm-objdump -x, wasm2wat, wasm-decompile (WABT).
SQLiteDie DB kopieren, plus die -wal-Datei falls vorhanden. sqlite3 'file:C?mode=ro' '.schema', dann SELECT * FROM t LIMIT 20.
plist / nib / carplutil -p F. Info.plist enthält die Bundle-ID, URL-Schemata und Datenschutz-Strings. Asset-Kataloge: assetutil --info Assets.car.
pcap / HARtshark -r C -q -z conv,tcp; `tshark -r C -T fields -e dns.qry.name -e tls.handshake.extensions_server_name -e http.request.full_uri
Firmwarebinwalk -e F oder unblob -e X F. Dann jeden extrahierten Binärcode durch diese Tabelle routen.
Websitecurl -sL URL für das HTML und die Skript-quellen, dann das JS holen und schneiden. Für Laufzeitverhalten einen Headless-Browser mit Netzwerk-Log verwenden (Playwright page.on('request')) oder Chrome --remote-debugging-port.
Laufende App / RuntimemacOS: lldb -p PID, dtrace/fs_usage/log stream --predicate 'process=="X"'. Electron main: --inspect (nur wenn die RunAsNode/inspect-Fuses es erlauben). Android: adb logcat, frida -U -f pkg -l hook.js.

Geschwindigkeitsmuster

  • Strings und Importe zuerst. Bei einem kleinen Binary beantworten nm -u + strings + die Exportliste normalerweise „was macht es“ ohne Disassemblierung.
  • Um herauszufinden, wer einen String verwendet: seine Adresse aus den otool -tV „literal pool for“-Kommentaren holen, oder rg -n 'literal pool for: "X'. Dann die umschließende Funktionsbezeichnung oberhalb dieser Zeile finden.
  • Ein C++-Name in einem bl-Ziel verrät bereits das Protokoll (z. B. getpeereid, write, std::hash). Lesen Sie die Aufrufsequenz, nicht jede Anweisung.
  • Bei JS von der nativen/JS-Grenze nach innen vorgehen: den nativen Aufruf finden, dann seine Aufrufer-Klasse, dann die IPC-Registrierung, dann den Renderer/Preload.
  • Versionen vergleichen: die Bestandsaufnahmen differenzieren (nm, die Modul-Liste, go version -m), bevor Sie Code differenzieren.
  • Wiederaufbau: die minimale Neuimplementierung schreiben, dann gegen das Original testen (gleiche Eingaben, gleiche Ausgaben).

Installation (nur auf Anfrage)

brew install jadx apktool radare2 binwalk wabt wireshark ghidra · npm i -g @electron/asar · dotnet tool install -g ilspycmd · cargo install cargo-audit.

Verwandte Skills