Volver a actualizaciones
Nuevo releaseAug 31, 2026

aotopsy v1.1.0

Analizador estático para instantáneas AOT de Flutter/Dart — recupera nombres de funciones, jerarquías de clases, grafos de llamadas y señales de comportamiento de libapp.so sin incrustar ni ejecutar la VM de Dart. Compatible con ARM64 y x86_64, Dart 2.10–3.12.

Compartir

AOTopsy

CI Release License

Un analizador de snapshots AOT de Dart. Convierte libapp.so — el código Dart compilado dentro de un APK de Flutter en versión release — en nombres de funciones, diseños de clases, grafos de llamadas, señales de comportamiento y pseudocódigo legible. Sin VM de Dart, sin compilación del SDK, sin respaldo en tiempo de ejecución.

Aviso de fork: AOTopsy es un fork de unflutter, originalmente creado por Anthony Zboralski. El repositorio original zboralski/unflutter ya no está disponible (eliminado por el autor); existe una continuación comunitaria en KristijanZic/unflutter. Todo el crédito por el parser de snapshots original, el deserializador de clústeres, el pipeline de desensamblado ARM64 y la integración con Ghidra/IDA pertenece al autor original. AOTopsy lo extiende con soporte para x86_64, un descompilador nativo, inferencia de tipos a nivel de programa completo, generación de scripts de Frida y documentación exhaustiva.

Qué Recupera

SalidaQué es
Nombres de funcionesEl nombre Dart original de cada función compilada
Estructuras de clasesNombres de campos, desplazamientos de bytes, cadenas de herencia
Grafo de llamadasAristas de llamadas directas (BL) e indirectas (BLR/dispatch) con procedencia
Referencias a cadenasQué funciones cargan qué literales de cadena desde el pool de objetos
Señales de comportamientoClasificación de palabras clave: criptografía, red, juegos de azar, SIM, ubicación, WebView, blockchain
PseudocódigoSalida descompilada neutral respecto a la arquitectura desde código máquina ARM64 o x86_64
Exportación de código fuente DartArchivos .dart modulares de todo el proyecto reconstruidos con clases, campos y métodos

Soporta ARM64 y x86_64. Cubre Dart 2.10 hasta 3.13 (3.13.2 es la frontera estable actual).

Precisión y Honestidad

AOTopsy se mide contra la verdad de referencia, no se asume. Dos propiedades se verifican mediante el conjunto de pruebas en cada cambio:

MétricaValorQué significa
Concordancia en la recuperación de nombres89.8% en general (81.3% en la peor banda, umbral mínimo de 0.81) en 44 compilaciones de verdad de referenciaNombres de funciones recuperados comparados con el .symtab ELF de cada compilación, la verdad de referencia externa — TestSymtabDifferential. Marcador completo por compilación: BENCHMARK.md (make bench).
Validez sintáctica del descompilador100% Dart válidoCada función de pseudocódigo emitida se analiza como Dart — TestDecompileQualityCorpus.
Tasa de fabricación0%La regla §2: nunca emitir un nombre, tipo o destino de llamada adivinado como un hecho. Los desconocidos se muestran honestamente (indirectCall, <unknown>, dynamic).

Las gemelas de verdad de referencia son compilaciones de producción reales que no podemos redistribuir, por lo que esas compuertas diferenciales se ejecutan localmente; el CI público valida la compilación y las pruebas unitarias en la matriz de plataformas (las pruebas dependientes de muestras se omiten limpiamente cuando el binario está ausente). Consulta SECURITY.md para la verificación de binarios de release y el alcance honesto a continuación.

Inicio Rápido

make build
./aotopsy libapp.so                    # pipeline completo
./aotopsy doctor libapp.so             # diagnóstico rápido
./aotopsy export-dart --lib libapp.so --out ./lib  # reconstruir todo el proyecto de código fuente Dart
./aotopsy _debug decompile-native --lib libapp.so --find MyClass  # encontrar y descompilar una función

Consulta WORKFLOW.md para la metodología paso a paso cuando tienes un APK crudo y no sabes por dónde empezar.

Cómo Funciona

AOTopsy trata el snapshot AOT de Dart como una gramática binaria determinista. Cada byte tiene exactamente una interpretación correcta dadas las restricciones adecuadas (estructura ELF, magic del snapshot, hash de versión, tabla CID, codificación de clústeres). El parser aplica restricciones hasta que solo sobrevive una interpretación — sin heurísticas, sin adivinanzas.

El pipeline se ejecuta en etapas, cada una una función pura de bytes a datos estructurados:

flowchart TD
    A[libapp.so] --> B[ELF parse]
    B --> C[snapshot region extraction]
    C --> D[version detection]
    D --> E[cluster alloc<br/>object census]
    E --> F[cluster fill<br/>field values, names, strings]
    F --> G[instructions table<br/>code ranges, stub boundaries]
    G --> H{architecture?}
    H -->|ARM64| I[ARM64 disassembly]
    H -->|x86_64| J[x86_64 disassembly]
    I --> K[CFG + call edges<br/>register provenance]
    J --> K
    K --> L[type inference<br/>BLR receiver type resolution]
    L --> M[signal classification<br/>behavioral keyword matching]
    M --> N[JSONL + HTML + DOT<br/>pseudocode output]

Dos backends independientes comparten la misma mitad frontal (ELF hasta el llenado de clústeres), y luego se dividen por arquitectura: internal/disasm para ARM64, internal/disasm/x86.go para x86_64. El descompilador (internal/decompiler) maneja ambas arquitecturas a través de un IR unificado.

flowchart LR
    subgraph "Mitad frontal compartida"
        A[elfx] --> B[snapshot]
        B --> C[cluster]
    end
    subgraph "Backend ARM64"
        C --> D1[disasm ARM64]
        D1 --> E1[callgraph]
        E1 --> F1[signal]
    end
    subgraph "Backend x86_64"
        C --> D2[disasm x86_64]
        D2 --> E2[callgraph]
        E2 --> F2[signal]
    end
    subgraph "Descompilador (ambas arquitecturas)"
        C --> G[decompiler IR]
        G --> H[pseudocode]
    end

Comparación con Blutter

flowchart LR
    subgraph Blutter
        direction TB
        B1[libapp.so] --> B2[Compilar SDK de Dart<br/>coincidente]
        B2 --> B3[Incrustar VM de Dart]
        B3 --> B4[Deserializar mediante<br/>APIs internas de la VM]
        B4 --> B5[Fidelidad perfecta]
    end
    subgraph AOTopsy
        direction TB
        A1[libapp.so] --> A2[Analizar formato binario<br/>directamente]
        A2 --> A3[Sin VM, sin SDK]
        A3 --> A4[Modelado de formato<br/>específico de versión]
        A4 --> A5[Portabilidad + velocidad]
    end

Blutter incrusta la VM de Dart para deserializar el snapshot a través de sus propias rutas de código. Fidelidad perfecta, pero requiere compilar un SDK de Dart coincidente para cada versión objetivo — y es solo ARM64, sin soporte estático para x86_64. AOTopsy es el único analizador estático e independiente de versión con un descompilador de pseudocódigo nativo y precisión de verdad de referencia publicada.

AOTopsy analiza el formato binario directamente. Sin VM, sin SDK. La compensación: cada cambio de formato entre versiones de Dart debe modelarse explícitamente. No hay tiempo de ejecución que lo maneje automáticamente.

Comandos

Pipeline completo

aotopsy libapp.so              # desensamblado + aristas de llamadas + señales + metadatos (ARM64: + Ghidra/IDA)
aotopsy signal libapp.so       # igual, omitir metadatos
aotopsy libapp.so --graph      # también construir archivos DOT del grafo de llamadas

Banderas: --out <dir> (predeterminado: <basename>.aotopsy/), --quiet, --strict, --max-steps <n>, --k <n> (profundidad de contexto de señales, predeterminado 2).

Categorías