
Un decompilatore APK e DEX nativo scritto in Rust
Il parser DEX Rust iniziale in src/native_dex.rs adatta la logica di parsing da
JADX v1.5.6, fissato al commit
28ff15e4ae69950aebea110a13e5ab895d234dfc.
JADX è copyright di Skylot e dei suoi contributori; le applicabili note dell'Android Open Source
Project e di altre fonti upstream sono conservate in NOTICE.
L'implementazione di riferimento è il
plugin di input DEX,
inclusi DexReader, sections/DexHeader, sections/SectionReader,
sections/DexClassData e utils/Leb128.
Le modifiche RDX traducono la logica del parser in Rust con accesso ai byte verificato, propagazione esplicita degli errori e rappresentazioni di classi/membri di proprietà RDX. L'emettitore di sorgenti nativo è codice RDX nuovo. Questa è un'implementazione iniziale e parziale del parser e del motore nativo, non un port completo della pipeline di decompilazione di JADX né una dichiarazione di copertura di output equivalente.
I file seguenti sono copie non modificate scaricate dalla release fissata:
8dada3edaf50dbc082c9a125058f25def75e625a).5c0b69a0f5298e0b329e33e860f7626f0c2c3891).Il NOTICE upstream completo è conservato, incluse le note storiche sulle librerie e sulle icone incluse. La conservazione non significa che il parser Rust incorpori tutte quelle librerie o risorse. L'implementazione Java e le sue dipendenze runtime non sono più distribuite.
Le distribuzioni che contengono il parser adattato devono includere la licenza e le note applicabili. Le modifiche derivate da ulteriori file upstream dovrebbero conservare le loro note ed estendere questa mappatura delle fonti man mano che il port cresce.
src/native_resources.rs mappa il dispatch dei chunk, il parsing di namespace, elementi e
attributi tipizzati del fissato JADX v1.5.6
jadx-core/src/main/java/jadx/core/xmlgen/BinaryXMLParser.java
su Rust nativo. Il suo lettore di string-pool e l'emettitore XML limitato sono codice RDX.
Il decoder valida i confini di input/chunk/stringa, supporta pool UTF-8/UTF-16
e gestisce i comuni valori di attributi tipizzati Android senza un runtime Java.
Gli ID delle risorse rimangono numerici: la ricerca dei simboli ARSC e i nomi di enum/flag del manifest
non sono ancora portati. Questo non è il sottosistema completo delle risorse upstream.
src/native_java/ è il livello conservativo RDX in Rust di abbassamento dei valori dei registri ed
emissione Java sopra il lettore DEX adattato. Gestisce istruzioni tipizzate supportate, salti in avanti, cicli semplici e
switch in avanti con materializzazione esplicita degli effetti e mappature di sorgente generate.
La gestione degli opcode di array/tipi segue la specifica delle istruzioni DEX AOSP.
Non è un port della pipeline CFG/SSA/type-inference di JADX e non rivendica
la sua copertura di ricostruzione. I metodi non supportati mantengono l'output DEX nativo.
src/native_cfg.rs adatta l'approccio split/connect dal fissato JADX
BlockSplitter.java.
L'implementazione Rust opera direttamente sulle unità di codice DEX verificate, conserva
le istruzioni goto e gli offset originali, esclude i dati di payload e isola in modo conservativo
le istruzioni protette per gli archi eccezionali. Non implementa ancora
le trasformazioni sintetiche dei blocchi di JADX, SSA o la costruzione delle regioni. L'analisi dei dominatori
è una fase separata descritta di seguito.
Questa fase è esposta tramite un audit separato del corpus; il renderer di sorgenti della GUI
usa ancora l'abbassamento esistente dei valori dei registri. Vedi
docs/jadx-port-plan.md per le passate rimanenti.
src/native_dominators.rs adatta il fissato
DominatorTree.java:
l'algoritmo iterativo di immediate-dominator di Cooper/Harvey/Kennedy, l'intersezione dei predecessori
e le visite del dominance-frontier. Le modifiche Rust preservano gli ID originali dei blocchi, usano
traversal iterativo in reverse-postorder, limitano lo storage di lavoro/frontier
e usano intervalli ad albero per le query di dominanza invece di bitset di dominatori per blocco.
Un predecessore di entry virtuale gestisce gli archi all'indietro verso l'entry del metodo.
La raggiungibilità è dall'entry effettivo del metodo su archi normali e eccezionali
conservativi; i blocchi handler disconnessi sono segnalati come irraggiungibili.
Questa è analisi dei dominatori, non la passata completa di trasformazione BlockProcessor.
src/native_ir.rs adatta la mappatura degli operandi delle famiglie di istruzioni dal fissato
InsnDecoder.java.
Il suo lettore verificato di operandi DEX grezzi segue i formati di istruzioni AOSP ed è codice
RDX. Conserva offset/opcode, letture e scritture ordinate dei registri, larghezze di parola,
letterali, riferimenti indicizzati e comportamento conservativo di lancio. A differenza dell'upstream,
non risolve ancora le voci del pool, non unisce i risultati delle chiamate né esegue type inference.
Gli argomenti di invocazione rimangono parole di registro grezze ordinate fino alla risoluzione della firma.
src/native_calls.rs ora risolve le voci del pool dei metodi e raggruppa le parole di receiver/argomento
in base ai loro prototipi effettivi, seguendo le stesse convenzioni invoke/result del fissato InsnDecoder.
Gestisce argomenti wide, owner di array, prototipi secondari polimorfici e filled array, e collega
le istruzioni move-result tipizzate adiacenti. Gli invoke personalizzati rifiutano esplicitamente
i metadati mancanti del call-site.
Questo è binding delle firme, non risoluzione del dispatch virtuale o SSA.
Le categorie dei registri descrivono vincoli di larghezza di storage/riferimento, non tipi Java inferiti. CFG e decodifica degli operandi condividono un unico decoder di larghezza delle istruzioni; il vecchio renderer di sorgenti rimane separato mentre questa pipeline di analisi viene costruita.
src/native_dex_metadata.rs decodifica valori encoded, liste di handler try/catch e
set condivisi di annotazioni di classi/campi/metodi/parametri dal
formato DEX AOSP.
Offset verificati, budget di allocazione/lavoro, storage condiviso degli handler e le rappresentazioni
Rust sono codice RDX. src/native_java/annotations.rs renderizza comuni valori di annotazioni Java,
conservando link di tipo/enum e stringhe/char con escape. Il posizionamento delle annotazioni segue il fissato AnnotationGen.java.
Le annotazioni di build/runtime sono visualizzate, anche sui metodi con corpi di fallback
DEX. Le annotazioni di sistema rimangono metadati; Throws viene anche renderizzato come clausola throws.
I valori Java non supportati sono marcati esplicitamente. I default delle annotazioni e i metadati di debug
non sono completamente ricostruiti.
src/native_java/numeric.rs, strings.rs, liveness.rs e il renderer delle eccezioni
sono implementazioni RDX sulla semantica delle istruzioni DEX. I loro
confini di fallback conservativi e i fixture indipendenti di comportamento Rust sono
documentati in docs/native-engine.md e docs/validation.md. Non
eseguono né incorporano codice Java upstream.
src/native_ssa.rs adatta l'inserimento di phi con dominance-frontier potata live-in e
il renaming dal fissato JADX
SSATransform.java.
Gli adattamenti Rust usano traversal iterativo, identità di parola limitate e blocchi sintetici
normal-success per preservare lo stato eccezionale pre-scrittura. Quest'ultimo sostituisce
la riparazione post-renaming dei try-edge dell'upstream. La semplificazione dei phi rimane non portata;
l'inferenza parziale dei tipi è descritta di seguito. native_call_values.rs collega
i vincoli di firma esistenti alle parole SSA. Nessun Java upstream viene eseguito.
src/native_types.rs adatta la separazione assignment/use-bound e la sequenza di propagazione
dal fissato JADX TypeInferenceVisitor.java
e TypeUpdate.java.
La worklist Rust limitata, i controlli di coppie di parole, le alternative letterali e i risultati
espliciti unresolved/conflict sono adattamenti RDX. Questa è inferenza parziale:
i listener degli elementi di array ora propagano i tipi di load e i vincoli di store. L'inferenza
all'indietro generale degli array, i least upper bound dei riferimenti, i generics e l'inserimento delle conversioni
rimangono incompleti.
src/native_constructors.rs segue le catene di assegnazione SSA come nel fissato
ConstructorVisitor.java.
RDX verifica la dominanza dell'allocazione e conserva l'origine e l'owner invocato originale.
Un owner diverso è marcato per il retargeting solo quando la gerarchia prova che
è un antenato del tipo di allocazione. Il chaining attraverso un antenato provato su
this segue il fissato ConstructorInsn.java. Questa analisi non rimuove né sposta
istruzioni, non stabilisce la validità dello stato di inizializzazione né emette costruttori.
Il percorso limitato di allocazione annidata in native_java/allocation_lowering.rs ora
consuma questi binding SSA dei costruttori. Identità esatte di allocazione/invoke e
un controllo RDX degli eventi di effetto regolano le espressioni Java di shared-capture. Questa integrazione
non è un port della pipeline completa di regioni/code-generation di JADX; l'emissione con retarget dell'owner,
le regioni di eccezione e la verifica generale dello stato di inizializzazione rimangono
non supportate in questo percorso.
Le relazioni di assegnazione degli array in native_hierarchy.rs seguono
JLS 4.10.3:
covarianza dei componenti di riferimento, componenti primitivi invarianti e i supertipi standard
Object/Cloneable/Serializable. L'annidamento dei descrittori è limitato; le relazioni mancanti
con classi esterne rimangono sconosciute.
La piccola gerarchia della piattaforma include anche archi di interfaccia verificati per Throwable / Serializable e SQLException / Iterable. Questi fatti evitano risposte di sottotipo falso negative dal precedente grafo di parent solo-eccezioni; non costituiscono un classpath completo della piattaforma Android.
Il decoder limitato di allocazione riconosce i risultati ignorati di StringBuilder.append(String),
guidato dal pattern di uso del builder non concatenato nel fissato
SimplifyVisitor.convertInvoke.
RDX conserva le chiamate effettive di costruttore/append e le tracce esatte degli effetti; non
esegue la trasformazione completa di concatenazione di stringhe dell'upstream. Sono accettati solo
l'esatta classe finale della piattaforma e l'overload con il suo contratto documentato di receiver-return;
i metodi arbitrari che sembrano fluent rimangono non supportati. Vedi
StringBuilder.append(String).
L'emissione di invoke-super di classe in native_java/method.rs segue la gestione delle superclassi
nel fissato InsnGen.callSuper/getClassForSuperCall.
RDX prova l'ascendenza stretta di superclasse usando la sua gerarchia immutabile limitata,
invece di richiedere che l'owner del metodo DEX sia uguale al parent diretto. Emette
super.method(...) e conserva la firma DEX originale nei metadati di navigazione.
Il receiver deve comunque essere l'istanza corrente. I default delle interfacce, le chiamate qualified-super
di classi enclosing e l'ascendenza incompleta/ambigua rimangono non supportate.
Le distinzioni di dispatch classe/interfaccia sono specificate dalla
documentazione invoke-kind di AOSP.
Il fissato JADX ConstructorVisitor.processInvoke rimuove il NEW_INSTANCE di origine
e sostituisce l'invoke del costruttore sul posto; InsnGen emette poi
new Class(argomenti). Fonti upstream rilevanti:
Il allocation.rs nativo di RDX mantiene prima la sua ricostruzione di espressione più rigorosa.
Solo per finestre piatte, può preparare dichiarazioni di capture ordinate e posizionare new
alla posizione del costruttore, corrispondendo all'approccio di ricostruzione leggibile
dell'upstream. A differenza delle più ampie classificazioni di riordino dell'upstream, RDX controlla comunque
tutti gli eventi registrati di cast/chiamata/lettura/stringa nel loro ordine originale. La
rilocazione intenzionale dell'allocazione può cambiare la class-initialization, il linkage e la tempistica
di fallimento dell'allocazione; la copertura dell'output non stabilisce una piena equivalenza semantica.
src/native_java/synchronized.rs adatta l'approccio di ricostruzione entry/body/monitor-exit
del fissato jadx-core/src/main/java/jadx/core/dex/visitors/regions/maker/SynchronizedRegionMaker.java.
L'implementazione Rust aggiunge traversal CFG limitato, controlli di copertura delle scritture di registro decodificate
e delle eccezioni, validazione esatta della cleanup e rifiuto conservativo di
forme annidate/multiple-release/eccezioni miste. È un'implementazione parziale,
non un port completo del region maker upstream. I termini SPDX/licenza originali
e le note rimangono coperti dai file sopra.
native_java/names.rs segue la separazione tra identità originale e alias di sorgente
validi nel fissato JADX
RenameVisitor.java,
in particolare checkClassName e checkPackage. RDX usa il suo schema esistente di alias esadecimale
UTF-8 iniettivo invece del provider di alias configurabile di JADX e della passata globale
di collisioni. Header, costruttori, operandi di tipo e import usano alias;
i link di sorgente conservano i nomi DEX originali. Questo non è un port completo di RenameVisitor.
Il sottoinsieme delle regioni sincronizzate gestisce inoltre un latch di ciclo non lanciante al di fuori dell'intervallo protetto DEX ed emette cicli interamente dentro una regione monitor provata. Conserva la separazione della regione monitor del maker fissato pur richiedendo copertura per ogni istruzione del corpo che lancia, diversa dal rilascio provato.
native_java/finally_regions.rs usa l'approccio di riconoscimento del cleanup duplicato
del fissato JADX MarkFinallyVisitor.java.
Questo è un sottoinsieme Rust limitato, non un port completo del visitor: una invocazione di cleanup
void con input stabile, una copia normale, un rethrow catch-all e un catch tipizzato
enclosing con percorsi terminali. Controlla il dispatch originale delle eccezioni per istruzione,
i confini del control-flow, gli operandi di cleanup e i link di sorgente prima di emettere.
I layout annidati non supportati ricadono comunque nel fallback.
I metadati esatti delle eccezioni del framework Android si basano sulle dichiarazioni della piattaforma: ActivityNotFoundException, RemoteException, e IBinder.transact.
L'interfaccia degli snippet di metodo e il formato di logging in src/frida_snippet.rs seguono
JADX FridaAction.
Il generatore Rust legge i descrittori esatti dei simboli DEX, seleziona sempre l'overload
esatto, usa nomi posizionali degli argomenti e chiama quell'overload catturato.
Ogni snippet è limitato all'interno di Java.perform così gli snippet incollati non possono sovrascrivere
i method handle l'uno dell'altro. Gli snippet a livello di classe e di campo non sono implementati.