
Un descompilador nativo de APK y DEX escrito en Rust
El parser DEX inicial en Rust en src/native_dex.rs adapta la lógica de análisis de
JADX v1.5.6, fijado al commit
28ff15e4ae69950aebea110a13e5ab895d234dfc.
JADX es copyright de Skylot y sus contribuidores; los avisos aplicables del Android Open Source
Project y otros avisos upstream se conservan en NOTICE.
La implementación de referencia es el
plugin de entrada DEX,
incluyendo DexReader, sections/DexHeader, sections/SectionReader,
sections/DexClassData y utils/Leb128.
Las modificaciones de RDX traducen la lógica del parser a Rust con acceso a bytes verificado, propagación explícita de errores y representaciones de clases/miembros propias de RDX. El emisor de código fuente nativo es código nuevo de RDX. Esta es una implementación inicial y parcial del parser y del motor nativo, no un port completo del pipeline de descompilación de JADX ni una afirmación de cobertura de salida equivalente.
Los archivos a continuación son copias sin modificar descargadas de la release fijada:
8dada3edaf50dbc082c9a125058f25def75e625a).5c0b69a0f5298e0b329e33e860f7626f0c2c3891).Se conserva el NOTICE upstream completo, incluyendo los avisos históricos de bibliotecas empaquetadas e iconos. La conservación no significa que el parser en Rust incorpore todas esas bibliotecas o recursos. La implementación en Java y sus dependencias de tiempo de ejecución ya no se distribuyen.
Las distribuciones que contengan el parser adaptado deben incluir la licencia y los avisos aplicables. Los cambios derivados de archivos upstream adicionales deben conservar sus avisos y extender este mapeo de origen a medida que el port crezca.
src/native_resources.rs mapea el despacho de chunks, namespaces, elementos y atributos tipados
del parsing de JADX v1.5.6 fijado
jadx-core/src/main/java/jadx/core/xmlgen/BinaryXMLParser.java
a Rust nativo. Su lector de string-pool y su emisor XML acotado son código de RDX.
El decodificador valida los límites de entrada/chunk/string, soporta pools UTF-8/UTF-16
y maneja valores de atributos tipados comunes de Android sin un runtime de Java.
Los IDs de recursos permanecen numéricos: la búsqueda de símbolos ARSC y los nombres de enum/flags del manifiesto
aún no están portados. Este no es el subsistema completo de recursos upstream.
src/native_java/ es la capa conservadora de RDX en Rust para el lowering de valores de registro y la emisión de Java
sobre el lector DEX adaptado. Maneja instrucciones tipadas soportadas, ramas hacia adelante, bucles simples y
switches hacia adelante con materialización explícita de efectos y mapeos de código fuente generados.
El manejo de opcodes de arrays/tipos sigue la especificación de instrucciones DEX de AOSP.
No es un port del pipeline de CFG/SSA/inferencia de tipos de JADX y no reclama
su cobertura de reconstrucción. Los métodos no soportados conservan la salida DEX nativa.
src/native_cfg.rs adapta el enfoque de split/connect de JADX fijado
BlockSplitter.java.
La implementación en Rust opera directamente sobre unidades de código DEX verificadas, conserva
las instrucciones goto y los offsets originales, excluye datos de payload y aísla de forma conservadora
las instrucciones protegidas para aristas excepcionales. Aún no implementa
las transformaciones de bloques sintéticos, SSA ni la construcción de regiones de JADX. El análisis de
dominadores es una etapa separada descrita a continuación.
Esta etapa se expone a través de una auditoría de corpus separada; el renderizador de código fuente de la GUI
sigue usando el lowering de valores de registro existente. Ver
docs/jadx-port-plan.md para las pasadas restantes.
src/native_dominators.rs adapta el fijado
DominatorTree.java:
el algoritmo iterativo de dominador inmediato de Cooper/Harvey/Kennedy, la intersección de predecesores
y los recorridos de frontera de dominancia. Las modificaciones en Rust preservan los IDs de bloque originales,
usan recorrido iterativo en reverse-postorder, acotan el trabajo/almacenamiento de fronteras
y usan intervalos de árbol para consultas de dominancia en lugar de bitsets de dominadores por bloque.
Un predecesor de entrada virtual maneja las aristas de retroceso hacia la entrada del método.
La alcanzabilidad se calcula desde la entrada real del método sobre aristas normales y excepcionales
conservadoras; los bloques handler desconectados se reportan como inalcanzables.
Esto es análisis de dominadores, no la pasada completa de transformación BlockProcessor.
src/native_ir.rs adapta el mapeo de operandos por familia de instrucciones del fijado
InsnDecoder.java.
Su lector verificado de operandos DEX crudos sigue los formatos de instrucción de AOSP y es código
de RDX. Conserva offsets/opcodes, lecturas y escrituras de registros ordenadas, anchos de palabra,
literales, referencias indexadas y comportamiento de lanzamiento conservador. A diferencia de upstream,
aún no resuelve entradas del pool, fusiona resultados de llamadas ni realiza inferencia de tipos.
Los argumentos de invocación permanecen como palabras de registro crudas ordenadas hasta la resolución de firmas.
src/native_calls.rs ahora resuelve entradas del pool de métodos y agrupa las palabras de receptor/argumento
por sus prototipos efectivos, siguiendo las mismas convenciones de invoke/result del InsnDecoder fijado.
Maneja argumentos wide, owners de arrays, prototipos secundarios polimórficos y filled arrays, y enlaza instrucciones
move-result tipadas adyacentes. Los invokes personalizados rechazan explícitamente metadatos de call-site faltantes.
Esto es binding de firmas, no resolución de despacho virtual ni SSA.
Las categorías de registro describen restricciones de ancho de almacenamiento/referencia, no tipos Java inferidos. El CFG y la decodificación de operandos comparten un único decodificador de ancho de instrucción; el antiguo renderizador de código fuente permanece separado mientras se construye este pipeline de análisis.
src/native_dex_metadata.rs decodifica valores codificados, listas de handlers try/catch y
conjuntos compartidos de anotaciones de clase/campo/método/parámetro del
formato DEX de AOSP.
Los offsets verificados, los presupuestos de asignación/trabajo, el almacenamiento compartido de handlers y las representaciones
en Rust son código de RDX. src/native_java/annotations.rs renderiza valores de anotaciones Java comunes,
conservando enlaces de tipo/enum y strings/chars escapados. La ubicación de las anotaciones sigue el fijado AnnotationGen.java.
Se muestran las anotaciones de build/runtime, incluso en métodos con cuerpos de fallback DEX.
Las anotaciones del sistema permanecen como metadatos; Throws también se renderiza como cláusula throws.
Los valores Java no soportados se marcan explícitamente. Los valores por defecto de anotaciones y los metadatos de depuración
no se reconstruyen completamente.
src/native_java/numeric.rs, strings.rs, liveness.rs y el renderizador de excepciones
son implementaciones de RDX sobre la semántica de instrucciones DEX. Sus
límites de fallback conservadores y fixtures de comportamiento independientes en Rust están
documentados en docs/native-engine.md y docs/validation.md. No
ejecutan ni incrustan código Java upstream.
src/native_ssa.rs adapta la inserción de phi en fronteras de dominancia con poda de live-in y
el renombrado del fijado JADX
SSATransform.java.
Las adaptaciones en Rust usan recorrido iterativo, identidades de palabra acotadas y bloques sintéticos
de éxito normal para preservar el estado excepcional previo a la escritura. Este último reemplaza
la reparación de aristas try posterior al renombrado de upstream. La simplificación de phi permanece sin portar;
la inferencia de tipos parcial se describe a continuación. native_call_values.rs adjunta
las restricciones de firma existentes a las palabras SSA. No se ejecuta Java upstream.
src/native_types.rs adapta la separación asignación/uso-límite y la secuencia de propagación
del fijado JADX TypeInferenceVisitor.java
y TypeUpdate.java.
La worklist acotada en Rust, las comprobaciones de pares de palabras, las alternativas literales y los resultados
explícitos de no resuelto/conflicto son adaptaciones de RDX. Esto es inferencia parcial:
los listeners de elementos de array ahora propagan tipos de carga y restricciones de almacenamiento. La inferencia
general hacia atrás de arrays, los mínimos superiores de referencias, los genéricos y la inserción de conversiones
permanecen incompletos.
src/native_constructors.rs sigue las cadenas de asignación SSA como en el fijado
ConstructorVisitor.java.
RDX verifica la dominancia de la asignación y conserva el origen y el owner invocado original.
Un owner diferente se marca para retargeting solo cuando la jerarquía demuestra que
es un ancestro del tipo de asignación. El encadenamiento a través de un ancestro probado en
this sigue el fijado ConstructorInsn.java. Este análisis no elimina ni mueve
instrucciones, no establece la validez del estado de inicialización ni emite constructores.
La ruta acotada de asignación anidada en native_java/allocation_lowering.rs ahora
consume estos bindings de constructores SSA. Las identidades exactas de asignación/invoke y
una comprobación de eventos de efecto de RDX controlan las expresiones Java de captura compartida. Esta integración
no es un port del pipeline completo de regiones/generación de código de JADX; la emisión de retargeting de owner,
las regiones de excepción y la verificación general del estado de inicialización permanecen
no soportadas en esta ruta.
Las relaciones de asignación de arrays en native_hierarchy.rs siguen
JLS 4.10.3:
covarianza de componentes de referencia, componentes primitivos invariantes y los supertipos estándar
Object/Cloneable/Serializable. El anidamiento de descriptores está acotado; las relaciones de clases
externas faltantes permanecen desconocidas.
La pequeña jerarquía de plataforma también incluye aristas de interfaz verificadas para Throwable / Serializable y SQLException / Iterable. Estos hechos evitan respuestas falsas negativas de subtipo del grafo de padres anterior, que solo contemplaba excepciones; no constituyen un classpath completo de la plataforma Android.
El decodificador acotado de asignaciones reconoce resultados ignorados de StringBuilder.append(String),
guiado por el patrón de uso de builder sin encadenar del fijado
SimplifyVisitor.convertInvoke.
RDX conserva las llamadas reales a constructor/append y las trazas de efectos exactas; no
realiza la transformación completa de concatenación de strings de upstream. Solo se
aceptan la clase exacta final de la plataforma y la sobrecarga con su contrato documentado de retorno del receptor;
los métodos arbitrarios que parecen fluidos permanecen no soportados. Ver
StringBuilder.append(String).
La emisión de invoke-super de clase en native_java/method.rs sigue el manejo de superclase
del fijado InsnGen.callSuper/getClassForSuperCall.
RDX prueba la ascendencia estricta de superclase usando su jerarquía inmutable acotada,
en lugar de requerir que el owner del método DEX sea igual al padre directo. Emite
super.method(...) y conserva la firma DEX original en los metadatos de navegación.
El receptor debe seguir siendo la instancia actual. Los defaults de interfaz, las llamadas qualified-super a clases envolventes
y la ascendencia incompleta/ambigua permanecen no soportadas.
Las distinciones de despacho de clase/interfaz están especificadas por
la documentación de invoke-kind de AOSP.
El fijado JADX ConstructorVisitor.processInvoke elimina el NEW_INSTANCE de origen
y reemplaza el invoke del constructor en su lugar; InsnGen luego emite
new Class(arguments). Fuentes upstream relevantes:
El allocation.rs nativo de RDX mantiene primero su reconstrucción de expresiones más estricta.
Solo para ventanas planas, puede preparar declaraciones de captura ordenadas y colocar new
en la posición del constructor, coincidiendo con el enfoque de reconstrucción legible de upstream.
A diferencia de las clasificaciones de reordenamiento más amplias de upstream, RDX aún verifica
todos los eventos registrados de cast/call/read/string en su orden original. La reubicación intencional
de la asignación puede cambiar el momento de la inicialización de clases, el linkage y el fallo de asignación; la cobertura de salida
no establece equivalencia semántica completa.
src/native_java/synchronized.rs adapta el enfoque de reconstrucción de entrada/cuerpo/monitor-exit
del fijado jadx-core/src/main/java/jadx/core/dex/visitors/regions/maker/SynchronizedRegionMaker.java.
La implementación en Rust añade recorrido acotado del CFG, comprobaciones de cobertura de escritura de registro decodificada y
excepciones, validación exacta de limpieza y rechazo conservador de
formas anidadas/con múltiples liberaciones/excepciones mixtas. Es una implementación parcial,
no un port completo del region maker de upstream. Los términos originales de SPDX/licencia
y los avisos permanecen cubiertos por los archivos anteriores.
native_java/names.rs sigue la separación entre identidad original y alias de código fuente válidos
en el fijado JADX
RenameVisitor.java,
particularmente checkClassName y checkPackage. RDX usa su esquema existente de alias hexadecimal UTF-8 inyectivo
en lugar del proveedor de alias configurable y la pasada global de colisiones de JADX. Los encabezados, constructores, operandos de tipo e imports usan alias;
los enlaces de código fuente conservan los nombres DEX originales. Este no es un port completo de RenameVisitor.
El subconjunto de regiones sincronizadas además maneja un latch de bucle no lanzador fuera del intervalo protegido DEX y emite bucles completamente dentro de una región de monitor probada. Conserva la separación de regiones de monitor del maker fijado mientras exige cobertura para cada instrucción del cuerpo que lanza, excepto la liberación probada.
native_java/finally_regions.rs usa el enfoque de reconocimiento de limpieza duplicada
del fijado JADX MarkFinallyVisitor.java.
Este es un subconjunto acotado en Rust, no un port completo del visitor: una invocación de limpieza void
con entrada estable, una copia normal, un rethrow catch-all y un catch tipado envolvente con rutas terminales.
Verifica el despacho de excepciones original por instrucción, los límites de flujo de control, los operandos de limpieza
y los enlaces de código fuente antes de emitir. Los diseños anidados no soportados aún recurren al fallback.
Los metadatos exactos de excepciones del framework de Android se basan en las declaraciones de la plataforma: ActivityNotFoundException, RemoteException, y IBinder.transact.
La UI de snippets de métodos y el formato de logging en src/frida_snippet.rs siguen
JADX FridaAction.
El generador en Rust lee descriptores de símbolos DEX exactos, siempre selecciona la sobrecarga
exacta, usa nombres de argumentos posicionales y llama a esa sobrecarga capturada.
Cada snippet está limitado dentro de Java.perform para que los snippets pegados no puedan sobrescribir
los handles de método de otros. Los snippets de clase completa y de campos no están implementados.