Communitygithub.com

leanrea

Ingeniería inversa de software empaquetado con herramientas CLI locales sencillas, sin necesidad de MCP. Cubre bundles de Electron/JS, binarios nativos Mach-O/ELF/PE, binarios Go/Rust/.NET/Flutter/WASM, APKs, SQLite, pcaps, firmware y sitios web.

¿Qué es leanrea?

leanrea es una habilidad de ingeniería inversa rápida y eficiente que utiliza herramientas CLI estándar disponibles localmente. Su objetivo es analizar software empaquetado (desde aplicaciones Electron hasta firmware) en 2-4 llamadas de herramienta, minimizando el coste en tiempo y recursos. La habilidad proporciona comandos concretos para cada tipo de archivo (Mach-O, ELF, PE, Web, APK, etc.), así como reglas claras sobre cómo trabajar con copias, rutear los archivos por su tipo, buscar evidencias de forma no destructiva y evitar la sobrecarga de información. Es especialmente útil para desarrolladores que necesitan entender cómo funciona una función, extraer versiones y dependencias, comparar compilaciones, o reconstruir una característica a partir de un binario o bundle, sin depender de servicios externos ni protocolos como MCP.

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

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

leanrea: ruta rápida

Ya conoces estas herramientas. Este archivo solo enumera el comando más rápido para cada objetivo y las trampas.

Reglas

  • Trabaja sobre una copia (cp -c en APFS es instantáneo). Coloca cada extracción en un nuevo directorio bajo $TMPDIR/re/<nombre>. Reutiliza una extracción si existe.
  • Enruta primero por file -b T y los bytes mágicos. Ejecuta el inventario más barato a continuación. Solo entonces descompila o lee código.
  • rg omite archivos ocultos e ignorados, y los empaquetadores ocultan el código (Electron: .webpack/, .vite/). Siempre busca en árboles extraídos con rg -uu.
  • Nunca hagas cat de un archivo grande o minificado. Córtalo: rg -o '.{0,200}AGUJA.{0,200}' F | head. Volca un desensamblado una vez a un archivo y luego grepéalo.
  • Agrupa sondeos independientes en UNA llamada de shell con ; y marcadores echo '--- nombre' (entrecomillado: zsh expande un ==x desnudo). Limita cada salida con head o -m.
  • Responde basándote en evidencia. En la respuesta, marca cada afirmación como visto (cita archivo:offset, o un símbolo/cadena) o inferido. Un hecho que no encontraste es desconocido, no "ausente". La lectura estática no es ejecución observada.
  • Una herramienta faltante no es un bloqueo. Usa la alternativa en la misma fila, o brew install <x> si el usuario lo permite.
  • Las vueltas cuestan más que los bytes. Apunta a 2–4 llamadas de herramienta: una llamada de reconocimiento por lotes, uno o dos cortes dirigidos, luego responde. Detente cuando cada elemento que se te pidió tenga evidencia. No vuelvas a verificar lo que ya viste.

Primer movimiento: una llamada cada uno, pega y ejecuta

Nativo (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

Luego lee una función: 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

Luego corta la aguja a través del bundle: rg -uu -o --glob '!node_modules' '.{0,250}AGUJA.{0,250}' $X | head -20.

Go: go version -m T solo suele responder la pregunta.

Enrutador

Objetivo (detección)Ruta más rápida
Aplicación Electron (*.app/Contents/Resources/app.asar)npx -y @electron/asar extract app.asar X (también ver app.asar.unpacked/ para addons .node). Punto de entrada: jq .main X/package.json. Superficie: `rg -n -o '.{0,120}(ipcMain.(handle
Web bundle / JS minificadoEncuentra sourceMappingURL. Si el mapa tiene sourcesContent, extrae las fuentes: jq -r '.sources[]'. Para webpack, grep de los ids de módulo, luego corta alrededor del acierto. Para pretty-print: npx -y prettier --parser babel F > F.pretty.js, luego lee con rangos de línea.
Hermes / bytenode / V8 snapshotHermes magic es c6 1f bc 03 (index.android.bundle): usa hermes-dec / hbc-decompiler. .jsc (bytenode) no puede descompilarse: usa cadenas y hooks en tiempo de ejecución.
Mach-O (file: Mach-O)lipo -info (primero adelgazar: lipo -thin arm64 -o T1 T). Luego: otool -L (librerías); xcrun dyld_info -exports -imports; nm -gU (exportaciones) / nm -u (importaciones = el mapa de capacidades); strings -a -n 6; `otool -l
Lógica de código nativootool -tV T > $D/dis.txt (o llvm-objdump -d --no-show-raw-insn -C). Encuentra la función: rg -n '^_?.*Nombre.*:$'. Lee el rastro de llamadas/cadenas: `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 para recursos. checksec: pwn checksec.
Go (__go_buildinfo, .go.buildinfo)go version -m T da el toolchain, ruta, módulo, dependencias y flags de compilación en una sola llamada. Sin Go: `strings -a T
RustDependencias (cargo-auditable): cargo audit bin T, o extrae .dep-v0 / __DATA,.dep-v0 e infla con zlib. Compilador: `strings -a T
.NET (file: Mono/.Net)ilspycmd -p -o X T.dll (instalar: dotnet tool install -g ilspycmd), luego rg. P/Invoke: rg DllImport X. NativeAOT/IL2CPP son nativos: usa las filas de nativo.
APK Androidjadx -d X --show-bad-code a.apk luego rg. Solo recursos/manifiesto: apktool d --no-src -o X a.apk. Vistazo rápido: unzip -l a.apk. lib/*/libflutter.so significa Flutter (Dart AOT: blutter); libhermes.so significa React Native (fila de Hermes).
Hash de snapshot de FlutterEn libapp.so, encuentra el magic f5 f5 dc dc; los 32 caracteres hex en +20 son el hash del snapshot. Mapea a una versión de Dart.
WASMwasm-objdump -x, wasm2wat, wasm-decompile (WABT).
SQLiteCopia la base de datos, más el archivo -wal si está presente. sqlite3 'file:C?mode=ro' '.schema', luego SELECT * FROM t LIMIT 20.
plist / nib / carplutil -p F. Info.plist contiene el bundle id, esquemas URL y cadenas de privacidad. Catálogos de assets: 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 o unblob -e X F. Luego enruta cada binario extraído a través de esta tabla.
Sitio webcurl -sL URL para el HTML y las fuentes de scripts, luego obtén el JS y córtalo. Para comportamiento en tiempo de ejecución, usa un navegador sin cabeza con un registro de red (Playwright page.on('request')) o Chrome --remote-debugging-port.
Aplicación en ejecución / runtimemacOS: lldb -p PID, dtrace/fs_usage/log stream --predicate 'process=="X"'. Electron main: --inspect (solo si los fusibles RunAsNode/inspect lo permiten). Android: adb logcat, frida -U -f pkg -l hook.js.

Patrones de velocidad

  • Cadenas e importaciones primero. En un binario pequeño, nm -u + strings + la lista de exportaciones suelen responder "¿qué hace?" sin desensamblado.
  • Para encontrar quién usa una cadena: obtén su dirección de los comentarios "literal pool for" de otool -tV, o rg -n 'literal pool for: "X'. Luego encuentra la etiqueta de la función que la envuelve arriba de esa línea.
  • Un nombre C++ en un objetivo bl ya te dice el protocolo (por ejemplo getpeereid, write, std::hash). Lee la secuencia de llamadas, no cada instrucción.
  • Para JS, ve desde el límite nativo/JS hacia adentro: encuentra la llamada nativa, luego su clase llamante, luego el registro IPC, luego el renderer/preload.
  • Comparar versiones: haz diff de los inventarios (nm, la lista de módulos, go version -m) antes de hacer diff de cualquier código.
  • Reconstruir: escribe la reimplementación mínima, luego pruébala contra el original (mismas entradas, mismas salidas).

Instalación (solo a pedido)

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

Skills relacionados