Lingue: English | 简体中文 | 繁體中文 | 日本語 | 한국어 | Français | Deutsch | Español | Italiano | Русский | العربية
neverd mobile recupera Java leggibile da APK, DEX e smali usando esclusivamente il motore integrato di NeverD. I lettori, implementati in modo indipendente, condividono un modello Dalvik tipizzato e un generatore Java con lavoro limitato. Questa funzione CLI sperimentale non promette il recupero completo di qualsiasi APK. I contenitori APK e l’output Java non sono disponibili tramite SDK C nativo, SDK dei plugin Python, caricatore GUI o neverd decompile --language.
Il Java prodotto è una ricostruzione del bytecode. Commenti, formattazione, scelte del linguaggio sorgente originale e identificatori rimossi non sono disponibili; anche il bytecode Kotlin produce Java. Un’esecuzione riuscita non dimostra l’equivalenza semantica e non garantisce che ogni metodo possa essere ricompilato. Questo flusso non avvia le applicazioni analizzate.
Dopo aver compilato NeverD, scegli una nuova directory di output:
neverd mobile app.apk -o recovered-app
neverd mobile classes.dex -o recovered-dex
neverd mobile MainActivity.smali -o recovered-class
neverd mobile decoded/smali -o recovered-javaApri recovered-app/sources/ per leggere i file Java e recovered-app/report.json per consultare l’inventario degli input e i limiti. Se le classi smali si richiamano tra loro, è preferibile fornire una directory.
| Componente | Requisito | Selezione |
|---|---|---|
| NeverD | Compilare il target neverd con una toolchain compatibile con C++20. Il flusso mobile è integrato nella CLI nativa e non richiama un interprete Python. Distribuire l’eseguibile con le librerie native richieste dalla propria compilazione. |
build/bin/neverd / PATH |
Il recupero Android usa esclusivamente il motore integrato di NeverD in C++20 e non richiede runtime Python o Java. Accetta dichiarazioni e operazioni comuni rappresentabili di DEX 035, 037–040 e smali. DEX 041, chiamate dinamiche come invoke-custom, alcuni percorsi di inizializzazione, annotazioni semantiche od operazioni sconosciute e identificatori non esprimibili in Java falliscono esplicitamente. Accettare un formato non significa supportarne tutte le istruzioni e dichiarazioni.
La risoluzione dei nomi Java distingue l’intestazione dal corpo della classe e può gestire i casi noti di oscuramento dei nomi nello stesso package; rifiuta esplicitamente i casi in cui mancano dichiarazioni di superclassi o interfacce esterne e non è possibile determinare i tipi o i riferimenti del codice ausiliario Java generato, assumendo soltanto per java.lang.Object, anche senza una dichiarazione disponibile, l’assenza di tipi membro ereditabili. I letterali in virgola mobile di smali vengono arrotondati direttamente alla precisione singola o doppia di destinazione, preservando la rappresentazione in bit risultante.
Il motore C++ integrato conserva e verifica i metadati Signature supportati di classi, campi e metodi, comprese variabili di tipo, array, wildcard, limiti di tipo e oscuramento dei nomi a livello di metodo. La cancellazione dei tipi deve corrispondere all’identità della dichiarazione DEX originale. Throws viene conservato; una gerarchia di eccezioni non dimostrabile viene rifiutata. Ereditarietà generica o sostituzione dei tipi dei membri, rigenerazione dei metodi ponte, chiamate a metodi generici, tipi interni parametrizzati e corrispondenza dei parametri nascosti dei costruttori restano esplicitamente non supportati senza le prove necessarie.
Il marcatore Java 8 @java.lang.Deprecated, privo di elementi e visibile a runtime, viene conservato su classi, campi, metodi e costruttori. Il motore rifiuta le annotazioni dei parametri, gli inizializzatori statici annotati, gli altri livelli di visibilità e i valori di elementi come since o forRemoval. Dopo la ricompilazione, la CI confronta separatamente l’attributo Deprecated del file di classe e le annotazioni a runtime, comprese le dichiarazioni di controllo non annotate e i metodi ausiliari generati; questi ultimi restano esclusi dal conteggio dei metodi originali.
DEX e smali conservano anche l’annotazione di piattaforma @android.annotation.SuppressLint su classi, campi, metodi e costruttori. Richiede visibilità build e un unico array di stringhe value; array e stringhe vuoti, valori ripetuti, ordine e caratteri con escape vengono mantenuti. Le annotazioni di parametri e inizializzatori statici restano non supportate. La CI usa l’SDK Android per verificare le annotazioni con conservazione CLASS dopo la ricompilazione e confrontare il comportamento del programma.
Il motore integrato conserva anche @Retention, @Target, @Documented e @Inherited, visibili a runtime, sulle dichiarazioni di annotazione supportate, ed emette un vero @interface. Questo sottoinsieme non ammette campi, metodi, parametri di tipo o dichiarazioni annidate. Sono supportate le annotazioni di primo livello e le annotazioni membro statiche con nomi, accessibilità e relazione con il tipo contenitore verificabili; gli ambiti locali o anonimi vengono rifiutati.
L’applicazione di un marcatore vuoto a una dichiarazione di classe, interfaccia o annotazione richiede una definizione corrispondente e accessibile nello stesso insieme di classi analizzate. Retention e Target devono consentire l’applicazione effettiva. Si può ricostruire una dichiarazione SOURCE, ma la sua applicazione persistente nell’input viene rifiutata; CLASS o l’assenza di Retention richiede la visibilità DEX build (0), mentre RUNTIME richiede la visibilità runtime (1). L’assenza di Retention resta distinta da CLASS esplicito, così come l’assenza di Target resta distinta da un array vuoto; l’ordine dell’array Target viene conservato. I valori Target sono limitati a Java 8; valori successivi come MODULE e RECORD_COMPONENT vengono rifiutati. @Inherited viene conservato senza copiare le applicazioni ereditate come annotazioni dirette delle sottoclassi.
Le dichiarazioni degli elementi delle annotazioni e i relativi valori predefiniti, le applicazioni personalizzate non vuote, i marcatori personalizzati su campi/metodi/parametri, le definizioni di annotazione esterne, i contenitori di annotazioni ripetibili e kotlin.Metadata restano non supportati. La definizione di un marcatore viene emessa come dichiarazione di classe senza metodi degli elementi o metodi ausiliari e non aumenta il numero di metodi recuperati.
La CI elabora esempi Java 8 propri del progetto con D8 e NeverD, ricompila tutto il Java generato e confronta i metadati Signature completi, i risultati della reflection e il comportamento. Queste verifiche non certificano il recupero completo di applicazioni reali.
cmake --build build --target neverd
./build/bin/neverd mobile app.apk -o recovered-appRacchiudere tra virgolette i percorsi con spazi.
& .\build\bin\neverd.exe mobile .\app.apk -o .\recovered-appLe compilazioni multiconfigurazione possono collocare l’eseguibile in build/bin/Release/. Seguire i normali requisiti di distribuzione delle librerie native di quella compilazione.
La tabella degli input seguente descrive il recupero. Le modalità query descritte più avanti hanno ambiti di convalida più ristretti.
| Input | Comportamento | Limite importante |
|---|---|---|
.apk |
Convalidare l’intero ZIP, quindi analizzare insieme tutti i classes.dex, classes2.dex e i successivi DEX numerati nella radice dell’archivio |
Solo codice; nessuna decodifica di risorse o manifest |
.dex |
Validazione e analisi di DEX 035 o 037–040 tramite il lettore integrato | DEX 041 e dichiarazioni od operazioni non supportate falliscono; rinominare o troncare un file non produce bytecode valido |
.smali |
Analizzare la classe fornita | Le classi adiacenti referenziate non vengono caricate implicitamente |
| Directory smali | Raccogliere ricorsivamente i file .smali e analizzarli insieme |
Includere le classi annidate e le radici smali dipendenti nella directory di input |
Per analizzare un albero di APK decodificato che contiene smali/ e smali_classes2/, passa la loro directory padre comune. Solo i file .smali arrivano al backend, ma prima viene convalidato e copiato l’intero albero fornito; anche gli asset voluminosi non pertinenti contribuiscono quindi ai limiti di input. Una directory compatta che contiene solo le radici smali rilevanti riduce il lavoro.
Gli APK suddivisi sono input separati. Ogni APK che contiene DEX può essere elaborato indipendentemente, ma questo comando non unisce un insieme di APK; le parti contenenti solo risorse falliscono perché non hanno DEX nella radice. .aab, .apks, .xapk, .odex, .oat e .vdex non sono accettati come input mobili.
Le risorse APK, AndroidManifest.xml, gli asset, le librerie JNI/native e il codice scaricato durante l’esecuzione non vengono ricostruiti in Java. Estrai separatamente una libreria nativa .so e usa neverd decompile library.so -o library.c. Per questo flusso statico, i payload cifrati o protetti da un packer devono essere già disponibili come normali DEX/smali; non vengono eseguiti rimozione del packing, collegamento a dispositivi o aggiramento delle protezioni.
neverd mobile app.apk --list-classes
neverd mobile classes.dex --list-classes --class-prefix com.example
neverd mobile app.apk --list-classes --class-prefix Lcom/example/ --json
neverd mobile app.apk --list-classes -o classes.txtQuesta query legge le identità delle classi senza decodificare i corpi dei metodi
né generare Java. Non richiede directory di preparazione o ambienti di esecuzione
esterni. L’output testuale contiene un descrittore DEX esatto per riga, nell’ordine
della directory ZIP e poi delle definizioni DEX. --class-prefix accetta un
prefisso di descrittore o di package con punti; esegue un confronto letterale del
prefisso, senza verificare i confini del package. Le definizioni duplicate,
anche tra file DEX, falliscono esplicitamente. Falliscono anche le identità delle
classi che non possono essere rappresentate senza perdita in UTF-8.
Senza -o, la query scrive su stdout. In modalità query, -o indica un nuovo
file, non una directory di recupero. I file esistenti restano intatti. I
risultati vengono accumulati finché tutti i DEX selezionati non superano i
controlli: un DEX malformato incontrato dopo gli altri impedisce quindi la
pubblicazione di un inventario parziale. --json include il numero di classi
corrispondenti e totali, il numero di DEX e
validation_scope: "dex-envelope-and-class-identities".
Vengono controllati tutti i nomi ZIP, gli header, gli intervalli e i limiti di
risorse dichiarati. Solo i payload classes.dex e classesN.dex numerati nella
radice vengono decompressi e verificati tramite CRC; l’integrità dei payload
delle risorse non pertinenti non viene verificata. Ogni DEX conserva i controlli
su header, SHA-1, Adler-32, limiti della mappa e metadati delle classi referenziati.
I corpi dei metodi e i metadati non referenziati non vengono convalidati. Questa
è una query di inventario, non un controllo di integrità dell’intero archivio né
una prova di recupero Java. DEX 041 e le sezioni method-handle e custom-call-site
restano non supportati. Il normale percorso di recupero completo continua a
convalidare ogni payload dell’archivio.
Si applicano --timeout, --max-files e --max-bytes. Il limite delle classi
conta tutte le definizioni tra i DEX prima del filtro; le voci ZIP non selezionate
contribuiscono comunque ai limiti dell’archivio. L’operazione di inventario non
accetta opzioni iOS o input smali.
Trova gli operandi diretti delle istruzioni senza generare Java:
neverd mobile app.apk --find-refs string --query 'login failed' --json
neverd mobile classes.dex --find-refs type --query 'Lcom/example/Service;' --exact
neverd mobile app.apk --find-refs method --query '->connect(' --owner 'Lcom/example/Client;'
neverd mobile app.apk --find-refs field --query 'Lcom/example/State;->ready:Z' --exact -o refs.jsonlLa corrispondenza cerca sottostringhe letterali e distingue maiuscole e minuscole.
--exact confronta l’intera destinazione: contenuto della stringa, descrittore
di tipo, identità di metodo come Lpkg/Type;->name(I)V oppure identità di campo
come Lpkg/Type;->name:I. --owner limita il proprietario della destinazione dei
riferimenti a metodi o campi a un descrittore esatto. Non filtra il metodo che
contiene il riferimento. Query vuote, input smali e combinazioni di opzioni di
query e recupero non sono supportati; i metacaratteri delle espressioni regolari
sono normali caratteri letterali.
L’output predefinito contiene un oggetto JSON compatto per occorrenza (JSON Lines).
--json restituisce un report con conteggi e un array references. Ogni riga
registra dex_entry, il method contenitore completo, pc_code_units (unità di
16 bit dalla prima istruzione del metodo), opcode, kind, target_index
(locale al DEX) e target. Tutte le occorrenze vengono conservate, incluso il
codice condiviso attribuito a più definizioni di metodo. Le righe delle stringhe
contengono anche le unità target_utf16 esatte; target è null quando un
surrogato isolato impedisce la pubblicazione UTF-8 senza perdita. Le altre
identità devono essere rappresentabili in UTF-8.
Lo scanner usa i confini delle istruzioni, i controlli degli operandi, la gestione
dei payload e i controlli del flusso del lettore di recupero. Valori immediati e
dati dei payload switch/array non possono diventare riferimenti. Controlla ogni
corpo di codice definito, anche se nessuna destinazione corrisponde, prima di
impostare code_scan_complete: true. defined_method_count include le
dichiarazioni native e astratte; scanned_method_count conta le definizioni con
corpo e scanned_code_item_count conta i corpi fisici distinti per DEX.
matching_pool_entries conta le destinazioni corrispondenti, incluse quelle non
referenziate.
validation_scope: "dex-code-references" comprende l’involucro DEX, le tabelle
degli identificatori, l’appartenenza di classi e membri e i dati di codice,
eccezioni e debug consumati. Annotazioni, valori statici codificati, usi nelle
sole dichiarazioni e metadati non referenziati restano fuori dalla query. Non è
recupero Java né un verificatore ART. Codice non supportato e dati consumati
malformati falliscono esplicitamente. La convalida APK ha lo stesso confine dei
payload selezionati dell’inventario delle classi; l’integrità dei payload delle
risorse non selezionate resta non verificata.
I risultati vengono accumulati per tutti i DEX selezionati prima della
pubblicazione, inclusi i controlli delle classi duplicate tra DEX. L’opzione
facoltativa -o indica un nuovo file. --max-files limita separatamente il totale
delle definizioni di classe, delle definizioni di metodo e delle occorrenze nei
risultati, oltre alle voci ZIP. --max-bytes limita input, dati di query
conservati, memoria di lavoro per corpo e output (con margini conservativi per
l’espansione JSON). Sono budget dell’operazione; l’RSS del processo comprende
anche buffer di input, overhead dell’allocatore e runtime. Si applicano anche i
consueti budget di tempo e lavoro.
neverd mobile app.apk -o recovered-app --platform=android \
--timeout=600 --max-files=30000 --max-bytes=4294967296 --json| Opzione | Valore predefinito | Significato |
|---|---|---|
-o PATH |
Obbligatoria per il recupero | Nuova directory di recupero; con entrambe le modalità query, nuovo file di output facoltativo |
--list-classes |
Disattivato | Interroga le identità delle classi APK/DEX senza recupero Java |
--class-prefix PREFIX |
Tutte le classi | Prefisso letterale di descrittore o con punti; richiede --list-classes |
--find-refs KIND |
Disattivato | Interroga i riferimenti diretti delle istruzioni a stringhe, tipi, metodi o campi |
--query TEXT |
Obbligatoria per i riferimenti | Sottostringa letterale dell’identità della destinazione |
--exact |
Disattivato | Confronta l’intera identità della destinazione del riferimento |
--owner DESCRIPTOR |
Qualsiasi proprietario | Proprietario esatto della destinazione per query su metodi/campi |
--platform=auto|android |
auto |
Selezionare Android esplicitamente o dedurre la piattaforma dall’input |
--timeout N |
300 |
Budget positivo del tempo di analisi in secondi |
--max-files N |
20000 |
Limite positivo del numero di voci, comprese le directory create |
--max-bytes N |
2147483648 |
Limite positivo in byte per input, dati estratti e output finale |
--json |
Disattivato | Stampare un report in JSON; altrimenti le query sui riferimenti emettono JSON Lines |
Una selezione --arch diversa da quella predefinita, --artifact, --metadata-only e un --max-func diverso da zero appartengono a iOS e vengono rifiutati per Android; --arch=auto esplicito è accettato.
Input, dati estratti e output finale conservano i budget di file e byte. I lettori e il generatore integrati controllano anche lavoro limitato e tempo trascorso. Aumentare un limite non disattiva gli altri.
recovered-app/
sources/ package e classi Java recuperati
metadata/android-methods.json copertura dei metodi del motore integrato
report.json inventario con versione e limiti
Gli input temporanei vengono rimossi. Le classi annidate possono condividere il file della classe esterna, quindi il numero di file Java non equivale al numero di classi DEX. I metodi generati possono usare un ciclo di dispatch Java; non eseguono il DEX originale né lo richiamano tramite un ponte a runtime.
Il report integrato include android_method_recovery, scritto anche in metadata/android-methods.json, e conserva ogni metodo originale. Vale method_count = recovered_method_count + projected_method_count + declaration_only_method_count + unrecovered_method_count; un projected_method_count assente vale zero e unrecovered_method_count resta zero prima della pubblicazione. I metodi originali native e abstract hanno stato declaration-only e non contano come corpi recuperati.
Un sottoinsieme di classi locali con nome e senza catture può essere emesso nel metodo statico contenitore esatto. Sono richiesti un metodo ordinario con tipi scalari, una classe priva di campi che estenda direttamente Object, un vero costruttore senza argomenti, metodi di istanza scalari e usi degli oggetti verificati che non escano dall’ambito supportato. Classi anonime, catture, modificatori non supportati e usi non dimostrati continuano a fallire esplicitamente.
I metodi locali e il metodo contenitore ricevono source-projected, con projection_kind: "named-method-local"; la copertura rimane partial anche quando il report generale indica success. I nomi binari e i flag di accesso dopo la ricompilazione restano non verificati. Il compilatore Java può scegliere un nome binario diverso, quindi class_source_bindings conserva classe originale, metodo contenitore esatto, percorso sorgente e nome locale con binary_name_status: "unverified".
generated_source_helpers elenca i metodi aggiuntivi con i tipi esatti throw-helper, constant-helper, default-constructor e field-initializer. L’ultimo indica un <clinit> generato aggiuntivo, assente dall’inventario dei metodi originali. Queste aggiunte non rientrano nel totale dei metodi originali. Una compilazione riuscita o una singola corrispondenza dei nomi non dimostra un recupero completo. L’esempio abbreviato seguente non contiene metodi proiettati:
{
"schema_version": 1,
"status": "success",
"platform": "android",
"source": "app.apk",
"input_kind": "apk",
"backend": {
"name": "neverd",
"version": "1",
"execution": "builtin"
},
"input_code_files": [
"classes.dex",
"classes2.dex"
],
"dex_count": 2,
"smali_count": 0,
"java_source_count": 2,
"java_sources": [
"sources/example/Main.java",
"sources/example/Peer.java"
],
"logs": [],
"android_method_recovery": {
"schema_version": 1,
"status": "recovered",
"class_count": 2,
"method_count": 6,
"recovered_method_count": 5,
"declaration_only_method_count": 1,
"unrecovered_method_count": 0
}
}input_kind è apk, dex, smali o smali-directory. input_code_files elenca i nomi del bytecode o i percorsi smali di input, mentre java_sources e logs sono relativi alla radice dell’output. source è il nome base dell’input. I report effettivi includono altri limiti di ricostruzione; conservali quando presenti i risultati ad altri strumenti.
Per l’automazione, controlla il codice di uscita del processo prima di leggere status e, quando reindirizzi stdout, salva il report fuori dalla nuova directory di output:
neverd mobile app.apk -o recovered-app --json > recovery-result.jsonLa CLI nativa restituisce zero in caso di successo e un valore non nullo in caso di errore. Con --json, gli errori gestiti includono schema_version, status: "error" ed error. Parsing degli argomenti, errori di avvio dell’eseguibile o delle librerie native e interruzioni possono essere segnalati soltanto su stderr. Controllare prima lo stato di uscita.
La pubblicazione è transazionale: l’output esistente viene conservato e i risultati temporanei falliti vengono rimossi. Operazioni non supportate, flussi di registri irrisolti, dichiarazioni non rappresentabili, gestione delle eccezioni malformata e budget esauriti fanno fallire il motore integrato anziché pubblicare corpi mancanti. Un recupero riuscito non prova l’equivalenza semantica.
| Sintomo | Azione |
|---|---|
| DEX, istruzione, dichiarazione o inizializzazione non supportati | Leggere il messaggio diagnostico e verificare il sottoinsieme supportato |
| Input non valido o classe duplicata | Correggere bytecode o insieme di classi; i corpi non supportati non vengono omessi silenziosamente |
| Tempo o budget superato | Ridurre l’input o adattare --timeout, --max-files e --max-bytes alle risorse disponibili |
| Output già esistente | Scegliere una nuova directory di output |
Python serve soltanto agli script di test di sviluppo riportati sotto; il recupero mobile integrato viene eseguito nella CLI nativa C++20.
cmake --build build --target check-neverd-mobile
ctest --test-dir build -L NeverDMobileTests --output-on-failure
python3 scripts/test_mobile_android_internal.py --d8 PATH --neverd build/bin/neverdI test dei componenti e della CLI controllano parsing, contratti di output e pulizia dopo gli errori. Il runner interno di confronto usa un JDK (java e javac) e D8 per costruire esempi DEX/APK indipendenti, poi compilare ed eseguire il Java recuperato. Sono dipendenze di test, non requisiti per il recupero integrato. Eseguirlo sulla build attuale ed esaminarne i risultati prima di dichiarare verificato un caso. Il successo degli esempi non dimostra il recupero completo di qualsiasi applicazione.
Vedere la panoramica mobile per il flusso iOS correlato.