τTau SolutionsHerramientas

Decompiladores a Java

panorama · Revisado el 12 de agosto de 2026

1. Qué es y por qué existe

Un APK no lleva dentro código fuente. Lleva classes*.dex: bytecode Dalvik, un juego de instrucciones basado en registros que describe qué hace el programa pero no cómo se escribió. Decompilar a Java es el intento de recorrer ese camino al revés — de las instrucciones a un texto que un humano pueda leer como si fuera el original.

La palabra clave es intento. La compilación de Java o Kotlin a DEX es una función que pierde información a propósito: descarta nombres, aplana construcciones del lenguaje, reordena instrucciones y borra tipos. Un decompilador no invierte esa función porque no es invertible; produce un programa distinto que se comporta igual. Cuando el decompilador acierta, la diferencia es cosmética y el lector no la nota. Cuando falla, el resultado va desde un método que no compila hasta —el caso peligroso— un método que compila, parece razonable y no dice lo que la aplicación hace.

Este documento cubre las herramientas que hacen ese trabajo y, sobre todo, dónde fallan. Para el nivel de abajo —el bytecode que se está decompilando— está Bytecode Dalvik. Para el nivel intermedio, que es fiel en lugar de reconstruido, está Desensambladores smali.

2. Qué se pierde, y por qué no vuelve

Antes de comparar herramientas conviene fijar el techo. Ninguna de las de este documento puede recuperar lo que sigue, porque no está en el fichero.

2.1 Los genéricos

La JVM implementa los genéricos por borrado de tipos (type erasure): en tiempo de ejecución List<String> y List<Integer> son la misma clase. Parte de la información sobrevive en el atributo Signature, que D8 propaga al DEX como la anotación dalvik.annotation.Signature, y los decompiladores buenos la leen. Pero es un atributo opcional: si R8 lo descarta —lo hace cuando nadie lo consulta por reflexión y no se ha pedido -keepattributes Signature—, la firma genérica desaparece sin dejar rastro y el decompilador solo puede escribir el tipo crudo.

Consecuencia práctica: un Map<String, List<Usuario>> puede salir como Map. El programa sigue siendo correcto; la intención del autor, no.

2.2 El azúcar sintáctico

Todo lo que el compilador de Java o de Kotlin traduce a construcciones más simples se pierde como forma, aunque se conserve como comportamiento:

En el fuente En el DEX Qué recupera el decompilador
for (X x : lista) Bucle con Iterator explícito El for extendido, casi siempre
switch sobre String Dos switch: uno sobre hashCode(), otro sobre el índice A veces; si no, dos switch anidados sin sentido aparente
Lambda / referencia a método Clase sintética, o invoke-custom con invoke-polymorphic Depende del decompilador; es de lo más frágil
try-with-resources try/finally anidados con addSuppressed Rara vez; suele salir el finally expandido
Autoboxing Integer.valueOf(...) Se ve la llamada, no el azúcar
Concatenación con + StringBuilder, o invokedynamic con StringConcatFactory Normalmente sí
Clases internas Clases separadas con this$0 y accesores sintéticos Se reconstruyen, con cicatrices
enum Clase con campos estáticos y array $VALUES Normalmente sí

Nada de esto es un fallo del decompilador. Es que la información no viaja.

2.3 Los nombres de las variables locales

Los nombres de parámetros y de variables locales viven en debug_info_item, dentro del code_item de cada método. Es una estructura opcional. Una compilación de release con R8 la elimina casi siempre, y cuando no la elimina R8, la elimina el flag --no-debug-info de quien haya reempaquetado la aplicación por el camino.

Sin debug_info, el decompilador tiene que inventar nombres. jadx los deriva del tipo y del número de registro (str, i, list2, obj), lo cual es legible pero no es el nombre original y no debe citarse como tal. Los nombres de campos y de métodos son otra cosa: esos sí están en las tablas del DEX, salvo que R8 los haya ofuscado — y entonces el problema ya no es la decompilación sino la ofuscación, que trata R8 y ProGuard.

Puede comprobarse sobre el ejemplo mínimo de la sección 5 de Desensambladores smali: compilado con javac -g, el debug_info conserva los nombres; compilado sin -g, los registros aparecen sin nombre.

2.4 El orden real del código

R8 no se limita a renombrar. Hace inlining de métodos pequeños, outlining de secuencias repetidas a un método sintético compartido, elimina ramas muertas, fusiona clases y mueve código entre métodos. Lo que sale del decompilador es el programa después de esas transformaciones.

Esto tiene un efecto que sorprende al que llega: un método que en el fuente tenía diez líneas puede aparecer con doscientas porque le han inyectado el cuerpo de cinco llamadas; y un método que en el fuente existía puede no aparecer en absoluto. Buscar «el método que hace X» en la salida de un decompilador y no encontrarlo no prueba que la aplicación no haga X.

2.5 El salto de modelo

El bytecode de la JVM está basado en pila; el de Dalvik, en registros. Los decompiladores de Java —CFR, Vineflower, Procyon, Fernflower— están escritos para el primero. Para usarlos sobre un APK hace falta una traducción previa de registros a pila (dex2jar), y esa traducción es otra fuente de pérdida y de error, encadenada a la primera. jadx evita el rodeo porque lee DEX de forma nativa; es su ventaja estructural.

3. jadx

3.1 Ficha

Dato Valor
Repositorio https://github.com/skylot/jadx
Licencia Apache-2.0
Lenguaje Java
Versión estable 1.5.6, publicada el 10 de julio de 2026
Último push al repositorio 5 de agosto de 2026
Creado 18 de marzo de 2013
Tracción 50.030 ★ · 5.719 forks
Issues abiertas 441
Archivado No

Consultado el 12 de agosto de 2026 vía la API de GitHub. Activo y con cadencia sostenida: las últimas releases son 1.5.4 (13 de febrero de 2026), 1.5.5 (25 de febrero de 2026) y 1.5.6 (10 de julio de 2026). Trece años de historia, licencia permisiva y el mayor número de estrellas de todo el instrumental de este bloque. Es la referencia del sector y no está cerca de dejar de serlo.

Las 441 issues abiertas no son señal de abandono sino de superficie: un decompilador falla por definición en algún porcentaje de los métodos, y cada fallo es un caso concreto que alguien reporta.

3.2 La arquitectura, en cuatro etapas

jadx lee DEX directamente y no pasa por .class. El recorrido conceptual es:

┌──────────────┐   plugin de entrada
│  classes.dex │   dex-input, smali-input, java-convert, apk-input
└──────┬───────┘
       ▼
┌──────────────────────────────────────────────┐
│ 1. Carga: tablas del DEX a un modelo de       │
│    clases, campos, métodos e instrucciones    │
└──────┬───────────────────────────────────────┘
       ▼
┌──────────────────────────────────────────────┐
│ 2. IR: grafo de bloques básicos, forma SSA e  │
│    inferencia de tipos sobre los registros    │
└──────┬───────────────────────────────────────┘
       ▼
┌──────────────────────────────────────────────┐
│ 3. Reconstrucción de control de flujo: del    │
│    grafo de saltos a regiones anidadas —      │
│    if, bucles, switch, try/catch              │
└──────┬───────────────────────────────────────┘
       ▼
┌──────────────────────────────────────────────┐
│ 4. Generación de código Java                  │
└──────────────────────────────────────────────┘

La etapa 3 es donde se juega todo. El DEX no tiene bucles ni condicionales: tiene saltos. Recuperar una estructura anidada a partir de un grafo arbitrario no siempre es posible con las construcciones del lenguaje Java, y ese es el origen directo de los modos de fallo de la sección 3.5.

⚠️ sin verificar: los nombres internos de las pasadas de jadx y el detalle exacto de su representación intermedia no se han contrastado contra el código fuente del proyecto en esta revisión. Las cuatro etapas describen el recorrido que la documentación del proyecto y la estructura de sus módulos hacen evidente, no una lista de clases de su implementación.

3.3 jadx-gui

El proyecto distribuye dos binarios: jadx (línea de órdenes) y jadx-gui (interfaz gráfica). La interfaz no es un envoltorio de la CLI: decompila bajo demanda, clase a clase, lo que la hace utilizable sobre aplicaciones donde la decompilación completa tardaría minutos. Aporta además búsqueda global por texto, clase, método o campo; navegación por referencias («quién llama a esto»); renombrado interactivo con persistencia; y la vista del smali del método al lado del Java, que es la forma práctica de comprobar si el Java es fiel.

Esa vista lado a lado es la respuesta operativa a todo lo de la sección 2: cuando el Java no cuadra, se mira el smali, que no miente.

3.4 Plugins

Desde la rama 1.5 jadx tiene un sistema de plugins con gestión desde la CLI. Los de entrada determinan qué formatos acepta:

Plugin Qué añade
dex-input .dex y .apk, con verificación opcional de checksum
java-convert .class, .jar y .aar, convirtiéndolos a DEX con dx o d8
smali-input Ficheros .smali, con nivel de API configurable
kotlin-metadata Lee la anotación kotlin.Metadata para mejorar la salida de Kotlin
kotlin-smap Usa SourceDebugExtension para renombrar alias de clases
rename-mappings Aplica ficheros de mapping externos

La gestión se hace con el subcomando plugins: -l/--list lista los instalados, -a/--available los del marketplace, -i/--install <locationId> instala y --uninstall <pluginId> desinstala.

El kotlin-metadata importa más de lo que parece. Una parte grande del Android moderno es Kotlin, y sin esa anotación el decompilador escribe el Java equivalente —con null checks inyectados, clases Companion, funciones de extensión convertidas en estáticas— que es correcto y bastante ilegible.

3.5 Los modos de fallo, y qué significa cada uno

Es la parte más útil de conocer, porque el lector se los va a encontrar.

Sobre los marcadores literales. Circulan por foros y por documentación de terceros dos cadenas que no existen en jadx: // decompilation failed y // JADX WARNING: inconsistent code. Las reales son las de abajo, verificadas contra el árbol del proyecto. El catálogo de Diagnóstico de fallos explica en su sección 6 por qué la segunda no se puede encontrar grepeando el repositorio: se compone en ejecución.

/* JADX ERROR: <mensaje> */ — con dos espacios tras /*, que es como lo escribe codegen/utils/CodeGenUtils.java. La etapa 3 no consiguió estructurar el método. Si hay una causa asociada, la traza de pila Java completa va incrustada dentro del comentario. Según la configuración, debajo aparece el smali embebido. El método no está decompilado en absoluto: lo que se lee es el desensamblado. Es el fallo honesto, porque se ve.

/* JADX WARN: <mensaje> */ (y sus hermanos JADX INFO: y JADX DEBUG:). jadx sí produjo Java, pero detectó que su propia reconstrucción no es coherente con el grafo de partida. Mensajes habituales tras el prefijo: «Multi-variable type inference failed», «Code restructure failed», «Removed duplicated region». Por defecto --comments-level es info, así que WARN e INFO se emiten y DEBUG no.

Code decompiled incorrectly, please refer to instructions dump. — acompañado de To view partially-correct add '--show-bad-code' argument. Este es el peligroso: hay código Java plausible en pantalla que puede no corresponder al comportamiento real. Por defecto jadx oculta estos métodos; --show-bad-code los muestra. El aviso está para leerse, no para ignorarse.

Class decompilation failed es otra cosa: es el mensaje de una JadxRuntimeException del modo --single-class, no un comentario del código generado. Confundirlas lleva a buscar en la salida algo que solo aparece en la consola.

Métodos que salen como smali embebido. Consecuencia del primero. jadx cae al modo fallback para ese método concreto. Se puede forzar globalmente con -m fallback, que renuncia a decompilar y vuelca la representación de bajo nivel de toda la aplicación — útil cuando la estructura importa menos que no perder nada.

Nombres p0, i, str2, C0123a. No es un fallo: es la sección 2.3 más la ofuscación. Los identificadores que empiezan por C seguidos de dígitos son la convención de jadx para clases cuyo nombre original era inválido o colisionaba.

OutOfMemoryError y cuelgues. Habitual en aplicaciones grandes. La documentación del proyecto recomienda bajar el número de hilos con -j, excluir paquetes que no interesan, usar la caché en disco de jadx-gui, y subir el heap de la JVM (-Xmx8g en vez de -Xmx4g).

Este último punto tiene una consecuencia de arquitectura para quien quiera embeber jadx en una herramienta propia: conviene lanzarlo siempre en subproceso aislado con límite de memoria y timeout, nunca por JNI, porque un fallo de memoria del decompilador se llevaría por delante al proceso que lo hospeda.

3.6 --deobf y mapping.txt: dos cosas distintas

Se confunden constantemente y no tienen nada que ver.

--deobf es heurístico. Detecta identificadores que parecen ofuscados —por longitud, con los umbrales --deobf-min y --deobf-max— y les asigna nombres generados y estables dentro de una misma ejecución. No recupera nada: cambia a.b.c por algo pronunciable. Sirve para poder hablar del código y para que las referencias cruzadas se sigan; no para saber cómo se llamaba.

--mappings-path es determinista. Carga un fichero de correspondencias y aplica los nombres reales. El plugin rename-mappings acepta, entre otros formatos, el mapping.txt de ProGuard y R8, además de Tiny, Enigma, SRG, XSRG, JAM, CSRG, TSRG, migración de IntelliJ, Recaf y el JOBF propio de jadx. --mappings-mode controla si los cambios se autoguardan.

La regla de lectura: si hay mapping.txt, los nombres son los originales; si solo hay --deobf, son invención. Confundirlos es cómo se escriben informes falsos.

4. La ruta alternativa: dex2jar más un decompilador de Java

4.1 El rodeo

classes.dex ──dex2jar──▶ classes.jar ──CFR / Vineflower / Procyon / Fernflower──▶ .java

Se traduce el bytecode de registros a bytecode de pila, y luego se usa cualquiera de los decompiladores de Java de los últimos quince años. Dos pasos, dos oportunidades de fallar.

4.2 dex2jar

Dato Valor
Repositorio https://github.com/pxb1988/dex2jar
Licencia Apache-2.0
Versión estable 2.4, publicada el 3 de octubre de 2023
Último push 21 de julio de 2024
Tracción 13.132 ★ · 2.186 forks · 379 issues abiertas
Archivado No

Consultado el 12 de agosto de 2026. Estado real: mantenimiento mínimo. Dos años sin release y más de dos años sin commits, con 379 issues abiertas. No está archivado y no ha sido declarado muerto, pero tampoco se mueve. Existen forks activos que empaquetan correcciones; su vigencia no se ha verificado en esta revisión. ⚠️ sin verificar: no se ha comprobado qué fork de dex2jar está vivo hoy ni con qué cobertura.

El dato que importa para elegir ruta está medido: en el estudio de la sección 6, dex2jar falló al convertir 394 de las 13.601 aplicaciones de Google Play y 33 de las 24.553 muestras de malware, frente a 0 de las 3.018 de F-Droid. Es decir, la ruta alternativa empieza perdiendo aproximadamente un 2,9 % de las aplicaciones comerciales antes de que el decompilador de Java llegue a intervenir.

4.3 Los decompiladores de Java

Herramienta Repositorio Licencia Última versión Último push Estado
CFR leibnitz27/cfr MIT 0.152 (11-12-2021) 04-06-2026 Repositorio vivo, sin release desde 2021
Vineflower Vineflower/vineflower Apache-2.0 1.12.0 (29-04-2026) 11-07-2026 Activo
Procyon mstrobel/procyon Otra (no reconocida por GitHub) 0.6.0 (21-02-2022) 12-06-2022 Parado desde 2022
Fernflower Dentro de JetBrains/intellij-community Apache-2.0 ⚠️ Vive como componente de IntelliJ

Consultado el 12 de agosto de 2026 vía la API de GitHub.

CFR es el más sólido de los clásicos y el que mejor sigue las versiones modernas del lenguaje Java. Su anomalía de mantenimiento merece leerse con cuidado: el repositorio recibió commits el 4 de junio de 2026, pero la última release etiquetada es la 0.152, de diciembre de 2021, y la web oficial del autor sigue anunciando esa misma versión. Hay desarrollo; no hay publicación. Quien lo use en producción está usando un binario de hace casi cinco años o compilando de master.

Vineflower es el sucesor real de Fernflower: se declara en su propia descripción como «fork of the Fernflower decompiler», con énfasis en la calidad de salida. Es el único de los cuatro con release reciente (1.12.0, abril de 2026) y desarrollo continuo. Si hay que elegir un decompilador de Java hoy, es este.

Procyon está parado: última release en febrero de 2022, último commit en junio de 2022. Conserva valor histórico y sigue siendo interesante por su tratamiento de ciertas construcciones, pero no recibe correcciones.

Fernflower es el decompilador que JetBrains integra en IntelliJ IDEA y en Android Studio — cuando se abre una clase compilada en el IDE, es él quien la muestra. No se distribuye como proyecto independiente con releases propias; vive dentro del árbol de intellij-community. ⚠️ sin verificar: no se ha podido confirmar en esta revisión la licencia exacta ni el estado del subdirectorio de Fernflower dentro del repositorio de JetBrains; la API de GitHub devolvió 403 a las consultas de contenido.

4.4 Cuándo esta ruta gana y cuándo pierde

Gana en un caso concreto y real: cuando jadx falla en un método determinado. El estudio de la sección 6 lo cuantifica — en aproximadamente el 96 % de los casos en que jadx falla al decompilar un método, al menos otro decompilador lo consigue. Si el objetivo es leer ese método y jadx ha escrito JADX ERROR, probar CFR o Vineflower sobre el .jar de dex2jar es exactamente lo que hay que hacer.

También gana cuando el objetivo no es un APK sino un .jar suelto, donde el rodeo desaparece.

Pierde en todo lo demás:

  • dex2jar puede fallar antes de empezar, y falla en un 2,9 % de las aplicaciones de Play.
  • Las tasas de fallo por método son entre 50 y 1.200 veces peores que las de jadx (sección 6).
  • No entiende de recursos: no decodifica el AndroidManifest.xml ni res/.
  • No sabe nada de Kotlin metadata ni de las convenciones de Android.
  • Son dos herramientas encadenadas en vez de una.

La conclusión operativa es que no es una alternativa a jadx: es un segundo intento para los métodos que jadx no ha podido.

5. Las comerciales y las suites

5.1 JEB (PNF Software)

Plataforma comercial y de código cerrado de PNF Software, descrita por el fabricante como una plataforma de ingeniería inversa para desensamblado, decompilación, depuración y análisis. Lo que la distingue del resto de este documento:

  • Un decompilador de Dalvik propio, independiente de jadx, con reputación de aguantar mejor el código muy ofuscado.
  • Decompiladores nativos en el mismo entorno: x86/x86-64, ARM/ARM64, MIPS/MIPS64, RISC-V, además de WebAssembly, EVM de Ethereum, PLC Simatic S7 y kernels SASS de Nvidia. Cubre en un solo producto lo que aquí se reparte entre este documento y Análisis binario y estático.
  • API de scripting en Java y Python para automatizar, con plugins de ejemplo publicados en GitHub aunque el núcleo sea propietario.
  • Depurador que se acopla tanto al Dalvik como al nativo.

Ediciones: Community Edition y demo gratuitas; JEB Pro y JEB Android comerciales. La página del producto no publica precios y remite a la sección de compra. Versión observada en la página del fabricante: JEB 5.36, de enero de 2026. Consultado el 12 de agosto de 2026.

El ancla de precio que sí está documentada es la de la licencia OEM para servidor —8.000 $ por servidor y año—, entre los precios que el fabricante publica en su página de compra y que recoge Mapa del ecosistema.

El punto ciego: es de pago, es cerrado y no se puede auditar. Para trabajo reproducible o para una cadena de herramientas verificable, eso es un problema real.

5.2 Bytecode Viewer

Dato Valor
Repositorio https://github.com/Konloch/bytecode-viewer
Licencia GPL-3.0
Última versión 2.13.2 (1 de enero de 2026), etiquetada «2026 Release (In-Dev)»
Último push 17 de julio de 2026
Tracción 15.590 ★ · 1.271 forks · 103 issues abiertas

Consultado el 12 de agosto de 2026. Su propia descripción: «A Java 8+ Jar & Android APK Reverse Engineering Suite (Decompiler, Editor, Debugger & More)».

Lo que aporta es agregación: ejecuta varios decompiladores a la vez sobre la misma clase y los muestra en paneles paralelos. Eso convierte el hallazgo del 96 % de la sección 4.4 en una operación de un clic en lugar de un montaje manual de dos herramientas. Añade además editor, buscador y visor de bytecode.

El punto ciego: es una interfaz gráfica. No hay modo desatendido utilizable en CI, que es exactamente la enfermedad del sector que cuantifica la sección 4.2 de Comparativa y selección. Y la licencia GPL-3.0 condiciona su integración en productos con núcleo permisivo.

6. La comparación honesta: qué dicen las mediciones

No he podido medir esto localmente: jadx no está instalado en la máquina de referencia y las reglas de este trabajo prohíben instalarlo. Lo que sigue son mediciones publicadas, con la fuente identificada.

La referencia es A Large-Scale Empirical Study of Android App Decompilation, de Noah Mauthe (Universidad del Sarre), Ulf Kargén y Nahid Shahmehri (Universidad de Linköping), presentado en SANER 2021. Es el primer estudio sistemático a gran escala de tasas de fallo de decompilación en Android. Tres conjuntos:

Conjunto Aplicaciones Media de métodos por aplicación
F-Droid (código abierto) 3.018 13.532
Google Play (crawl reciente) 13.601 63.748
Malware 24.553 5.142

6.1 Tasa media de fallo por método

Tabla VI del estudio — porcentaje medio de métodos fallidos por aplicación, incluyendo los timeouts como fallo total y excluyendo las aplicaciones en que dex2jar falló:

Conjunto CFR Fernflower jadx Procyon
F-Droid 0,741 % 5,966 % 0,005 % 1,522 %
Google Play 1,032 % 58,418 % 0,019 % 11,006 %
Malware 1,838 % 9,726 % 0,044 % 1,672 %
Media ponderada 1,204 % 24,703 % 0,023 % 4,733 %

Excluyendo también los timeouts (tabla V), la media ponderada queda en CFR 1,094 %, Fernflower 1,024 %, jadx 0,021 % y Procyon 0,564 %. La diferencia entre las dos tablas para Fernflower —del 24,7 % al 1,0 %— dice que su problema principal no es decompilar mal sino agotar el tiempo: el estudio registra un número muy grande de timeouts para él, frente a solo 5 para jadx.

Lectura: jadx es entre 25 y 1.200 veces mejor que la ruta alternativa, según el conjunto. No es una mejora marginal.

6.2 El dato que de verdad importa

Tabla VII — porcentaje de aplicaciones en las que todos los métodos se decompilaron sin un solo fallo:

Conjunto Solo jadx Ensemble de los cuatro Los cuatro a la vez
F-Droid 74,52 % 74,69 % 8,65 %
Google Play 21,02 % 21,03 % 0,15 %
Malware 78,81 % 79,68 % 0,60 %

Aquí está la conclusión que hay que interiorizar: solo una de cada cinco aplicaciones de Google Play decompila entera sin un solo método fallido. Y combinar los cuatro decompiladores no arregla nada a nivel de aplicación — sube del 21,02 % al 21,03 %.

La explicación que da el propio estudio es de aritmética: las aplicaciones de Play tienen 63.748 métodos de media, así que con una tasa de fallo por método de 0,019 % la probabilidad de que ninguno falle es baja aunque el decompilador sea excelente. No es que jadx sea peor en Play; es que hay muchos más métodos donde equivocarse.

El corolario incómodo: si nadie te dice qué métodos fallaron, no sabes qué parte de lo que estás leyendo no es lo que la aplicación hace. Hoy esos fallos son silenciosos, y una cobertura de decompilación explícita —cuántos métodos se decompilaron y cuántos no— es justamente lo que ninguna de estas herramientas reporta de serie.

6.3 Y una conclusión que consuela

El estudio también responde a si la ofuscación está rompiendo la decompilación a propósito, y la respuesta es que no: los autores no encontraron ni un caso de ofuscación de control de flujo con ramas falsas hacia posiciones inválidas, la técnica «irrompible» habitual en código nativo o JVM de escritorio. Los fallos se deben mayoritariamente a limitaciones técnicas de los decompiladores —control de flujo muy complejo, anidamiento profundo, agotamiento de recursos en métodos grandes— y no a defensas deliberadas. La conclusión de los autores es que la decompilación casi perfecta de Android es alcanzable con mejoras de implementación.

6.4 Límites de estos datos

Hay que decirlo con claridad:

  • Es un estudio de 2021. Cita jadx con una referencia de 2020, sin fijar número de versión; la versión actual es la 1.5.6, de julio de 2026. Las cinco ramas de mejora desde entonces no están reflejadas. Las cifras absolutas son casi con seguridad mejores hoy; el orden de magnitud entre herramientas es lo que conserva valor.
  • Mide fallo declarado, no corrección. Un método que decompila «bien» puede producir Java que no refleja el comportamiento — los propios autores lo advierten.
  • No incluye Vineflower, que no existía como tal, ni JEB, que es de pago.
  • Las tablas III y IV del estudio documentan que parte de los fallos contabilizados son artefactos de la medición: coincidencias superfluas por clases internas y métodos irreconciliables por genéricos. Para jadx, el 34,0 % de los fallos en Google Play entran en esta segunda categoría.

⚠️ sin verificar: no existen mediciones públicas equivalentes y recientes —de 2025 o 2026— sobre las versiones actuales de estas herramientas. No se ha encontrado ninguna en esta revisión, y las cifras de arriba son lo mejor disponible.

7. Recetas de jadx CLI

⚠️ No ejecutado localmente: jadx no está instalado en la máquina de referencia. La sintaxis procede del README oficial del proyecto y de su wiki de resolución de problemas, consultados el 12 de agosto de 2026. No se ha comprobado ninguna salida.

Decompilación completa a un directorio:

jadx -d salida/ app.apk

Solo el código, sin decodificar recursos — mucho más rápido, y suficiente si solo se va a leer lógica:

jadx -d salida/ --no-res app.apk

Solo los recursos, sin decompilar:

jadx -d salida/ --no-src app.apk

Con deofuscación heurística y umbrales de longitud:

jadx -d salida/ --deobf --deobf-min 3 --deobf-max 64 app.apk

Con mapping.txt real, que es lo que de verdad recupera nombres:

jadx -d salida/ --mappings-path mapping.txt app.apk

Mostrando los métodos marcados como incoherentes, para poder auditarlos:

jadx -d salida/ --show-bad-code app.apk

Renunciando a estructurar y volcando la representación de bajo nivel:

jadx -d salida/ -m fallback app.apk

Una sola clase, útil cuando la aplicación es enorme:

jadx --single-class com.ejemplo.MiClase -d salida/ app.apk

Control de recursos, que es el problema práctico en aplicaciones grandes:

JAVA_OPTS="-Xmx8g" jadx -j 4 -d salida/ app.apk

Gestión de plugins:

jadx plugins --list
jadx plugins --available
jadx plugins --install <locationId>

Códigos de salida. ⚠️ sin verificar: no se ha podido confirmar la tabla de códigos de salida de la CLI de jadx. La consulta al fichero JadxCLI.java en la API de GitHub devolvió 403 y no se ha ejecutado la herramienta. Lo único que se puede afirmar sin riesgo es que jadx no devuelve error por métodos que fallan: la decompilación parcial es su comportamiento normal, no una condición de error. Quien automatice jadx en un pipeline no debe apoyarse en el código de salida para saber si el resultado es completo; tiene que contar los marcadores de fallo en la salida generada.

8. Cómo elegir, en una tabla

Situación Qué usar
Leer código de un APK, caso general jadx
Leer código, exploración interactiva jadx-gui, con la vista de smali al lado
jadx escribió JADX ERROR en el método que me importa dex2jar + Vineflower, o CFR; o Bytecode Viewer para probarlos a la vez
Un .jar o .class suelto, sin APK Vineflower o CFR directamente
Código muy ofuscado y hay presupuesto JEB
Necesito el comportamiento exacto, sin reconstrucción No decompiles: smali
Automatizar en CI jadx en subproceso, contando marcadores de fallo

Y la regla que resume el documento: cuando el Java y el smali discrepan, el smali tiene razón.

Fuentes

  1. jadx — repositorio oficial — https://github.com/skylot/jadx Consultado el 12 de agosto de 2026 vía https://api.github.com/repos/skylot/jadx. De aquí salen la licencia Apache-2.0, la fecha de creación, el recuento de estrellas, forks e issues, y la fecha del último push de la ficha de la sección 3.1.
  2. jadx — releases — https://api.github.com/repos/skylot/jadx/releases Consultado el 12 de agosto de 2026. De aquí salen la versión 1.5.6 y su fecha de publicación, y el historial de releases citado en la sección 3.1.
  3. jadx — README oficial — https://github.com/skylot/jadx#readme Consultado el 12 de agosto de 2026. De aquí salen la lista de opciones de la CLI de la sección 7, la lista de plugins de entrada de la sección 3.4, los subcomandos de plugins, y la advertencia literal de que «in most cases jadx can't decompile all 100% of the code».
  4. jadx — Troubleshooting Q&A (wiki) — https://github.com/skylot/jadx/wiki/Troubleshooting-Q&A Consultado el 12 de agosto de 2026. De aquí salen el significado de --show-bad-code y las recomendaciones de memoria e hilos de la sección 3.5. Los marcadores literales de la sección 3.5 no salen de aquí: están verificados contra el árbol del proyecto y contrastados en la sección 6 de 50-procesos/04-diagnostico-de-fallos.md.
  5. A Large-Scale Empirical Study of Android App Decompilation — Noah Mauthe, Ulf Kargén, Nahid Shahmehri. SANER 2021. https://www.ida.liu.se/~ulfka17/papers/SANER2021.pdf Consultado el 12 de agosto de 2026; PDF descargado y extraído con pdftotext para leer las tablas directamente. De aquí sale toda la sección 6: tamaños de los conjuntos, tablas V, VI y VII, medias de métodos por aplicación, el 96 % de complementariedad, los fallos de dex2jar, y las conclusiones sobre ofuscación.
  6. dex2jar — repositorio oficial — https://github.com/pxb1988/dex2jar Consultado el 12 de agosto de 2026 vía la API de GitHub. De aquí salen la licencia, la versión 2.4, la fecha del último push y los recuentos de la sección 4.2.
  7. CFR — repositorio oficial — https://github.com/leibnitz27/cfr Consultado el 12 de agosto de 2026 vía la API de GitHub y su lista de tags. De aquí salen la licencia MIT, la release 0.152 y el contraste entre el push de junio de 2026 y la ausencia de releases desde 2021.
  8. CFR — página oficial del autor — https://www.benf.org/other/cfr/ Consultado el 12 de agosto de 2026. Confirma que la versión anunciada sigue siendo la 0.152 de diciembre de 2021, y de aquí sale su sintaxis de invocación.
  9. Vineflower — repositorio oficial — https://github.com/Vineflower/vineflower Consultado el 12 de agosto de 2026 vía la API de GitHub. De aquí salen la licencia Apache-2.0, la versión 1.12.0 del 29 de abril de 2026, y su declaración de ser un fork de Fernflower.
  10. Procyon — repositorio oficial — https://github.com/mstrobel/procyon Consultado el 12 de agosto de 2026 vía la API de GitHub y su lista de releases. De aquí salen la versión 0.6.0 de febrero de 2022 y la fecha del último push, que sostienen la afirmación de que está parado.
  11. Bytecode Viewer — repositorio oficial — https://github.com/Konloch/bytecode-viewer Consultado el 12 de agosto de 2026 vía la API de GitHub. De aquí salen la licencia GPL-3.0, la versión 2.13.2 y los recuentos de la sección 5.2.
  12. JEB Decompiler — página oficial de PNF Software — https://www.pnfsoftware.com/jeb/ Consultado el 12 de agosto de 2026. De aquí salen las ediciones, la lista de arquitecturas decompiladas y la versión 5.36 de la sección 5.1.
  13. Documentos de este corpusMapa del ecosistema (§2.3). De aquí sale el precio de la licencia OEM de JEB citado en la sección 5.1, verificado allí contra la página de compra de PNF Software.