Il Reverse Engineering (ingegneria inversa) è il recupero della logica e della struttura di un'applicazione mobile senza accesso al codice sorgente. Nel contesto di Android e iOS, ciò significa decompilare file binari DEX/APK e Mach-O/IPA per estrarre algoritmi, chiavi di crittografia, endpoint API e logica di business. Secondo Veracode Security Research (2025), oltre il 60% delle applicazioni mobili nella top 200 contiene almeno un indicatore che semplifica il reverse engineering. Il Reverse Engineering viene utilizzato non solo per attacchi, ma anche per audit di sicurezza, analisi di brevetti e test di penetrazione.
Punti chiave
Reverse Engineering (ingegneria inversa) è la disciplina dell'analisi del software volta a recuperare le caratteristiche, la logica e la struttura di un'applicazione dalla sua rappresentazione binaria. Per le applicazioni mobili, gli oggetti di analisi sono i file APK (Android) e IPA (iOS), che contengono codice compilato, risorse, manifesti e certificati. Il risultato del reverse engineering è l'estrazione di algoritmi, protocolli, chiavi di crittografia, schemi API e logica di business.
Gli obiettivi del reverse engineering si dividono in legittimi e illegittimi. Legittimi: analisi di malware per creare strumenti di sicurezza, audit delle proprie applicazioni per vulnerabilità, garanzia di compatibilità con protocolli chiusi, analisi di brevetti e formazione. Illegittimi: furto di proprietà intellettuale, elusione di restrizioni di licenza, creazione di copie pirata e modifica di applicazioni per rubare dati degli utenti. Secondo Google Play Protect (2025), il 78% delle modifiche dannose delle applicazioni bancarie vengono create sulla base dell'APK originale elaborato tramite reverse engineering.
La metodologia del reverse engineering include due direzioni principali: l'analisi statica (senza eseguire l'applicazione) e l'analisi dinamica (durante l'esecuzione). Ogni approccio fornisce un diverso livello di informazione. L'analisi statica fornisce un quadro completo del codice, ma senza dati di runtime. L'analisi dinamica rivela il comportamento reale, il flusso di dati e le chiamate di rete, ma solo all'interno di uno scenario di esecuzione specifico. Il reverse engineering professionale combina sempre entrambi gli approcci.
L'analisi statica è la prima fase del reverse engineering. L'APK o IPA originale viene decompresso e ogni componente viene analizzato separatamente. Gli obiettivi principali: bytecode DEX, risorse, manifesto, librerie native (.so, .dylib) e metadati.
jadx è lo strumento principale per l'analisi statica delle applicazioni Android. Converte il bytecode DEX in codice Java leggibile con perdita minima. jadx supporta: decompilazione multidex, riconoscimento di lambda e classi Kotlin inline ed esportazione in progetto Gradle. Per codice offuscato (ProGuard), jadx mostra codice con nomi a, b, c, ma la struttura delle classi e la sequenza delle chiamate vengono preservate. Secondo test indipendenti, jadx decompila correttamente l'85–92% del codice anche con offuscamento.
apktool decodifica l'APK in codice smali (assembler DEX) e ripristina le risorse in forma leggibile: AndroidManifest.xml viene convertito da AXML a XML leggibile, i layout diventano marcatori XML, strings.xml diventa testo semplice. apktool consente di modificare le risorse e ricostruire l'APK. Dopo la decompressione tramite apktool e la sostituzione delle risorse, l'applicazione può essere installata con contenuto modificato.
Ghidra (NSA) è un framework di reverse engineering essenziale per analizzare le librerie .so su Android e .dylib su iOS. Ghidra disassembla il codice ARM64, ricostruisce il pseudo-codice C e costruisce grafici delle chiamate. Per il reverse engineering mobile, Ghidra viene utilizzata per analizzare le implementazioni native della crittografia e dei meccanismi DRM. Ghidra supporta scripting in Python e Java per automatizzare l'analisi.
# Decompressione e decompilazione APK
$ jadx -d output_dir app.apk
# Decompressione delle risorse tramite apktool
$ apktool d app.apk -o app_unpacked
# Analisi della libreria nativa tramite Ghidra
$ ghidra app.apk/lib/arm64-v8a/libnative.so
# Ricerca di costanti stringa in DEX
$ strings classes.dex | grep -i api_key
L'analisi dinamica viene eseguita su un'applicazione in esecuzione. L'analizzatore si connette al processo e intercetta le chiamate alle funzioni, gli argomenti e i valori di ritorno in tempo reale.
Frida è lo strumento leader per l'analisi dinamica delle applicazioni mobili. Frida inietta un motore JavaScript nel processo dell'applicazione (Android ART o app iOS) e consente di intercettare chiamate sia a funzioni Java/Objective-C che C/C++. Con Frida, gli ingegneri inversi possono: registrare tutte le chiamate al metodo AES.decrypt() con parametri, sostituire arbitrariamente i valori di ritorno, disabilitare l'SSL-pinning tramite Universal Android SSL Unpin e tracciare le chiamate native tramite Stalker. Frida funziona senza modificare l'APK/IPA, rendendola indispensabile per i test di penetrazione.
Objection fornisce comandi pronti per compiti comuni di reverse engineering senza scrivere script JavaScript: disable-pinning (disabilitazione SSL pinning), dump-keychain (iOS), explore (esplorazione della gerarchia delle classi), memory search (ricerca di stringhe in memoria). Objection consente di eseguire un'analisi dinamica completa senza una singola riga di codice. Per le applicazioni iOS, Objection trova e registra automaticamente le chiamate a NSURLSession, CFNetwork e NSKeyedArchiver.
Xposed è un framework per Android che funziona sostituendo il file app_process in Zygote. A differenza di Frida, Xposed non richiede accesso root dopo l'installazione. I moduli Xposed possono intercettare chiamate a metodi in qualsiasi applicazione. Per il reverse engineering, Xposed è comodo per analisi a lungo termine: il modulo viene installato e funziona continuamente, registrando il comportamento dell'applicazione in diversi scenari. Xposed supporta Android fino alla versione 8.1; per Android 9+ viene utilizzato EdXposed basato su SandHook.
// Frida: intercettazione del metodo decrypt() in un'applicazione
let aesClass = Java.use("javax.crypto.Cipher");
aesClass.doFinal.overload(
"[B", "int", "int"
).implementation = function(
input, offset, len
) {
console("[AES] decrypt called, len=" + len);
return this.doFinal(input, offset, len);
};
Il flusso di lavoro standard del reverse engineering consiste in passaggi sequenziali, ciascuno dei quali fornisce un certo livello di informazione.
L'analista esamina l'APK a livello di metadati: targetSdk, uses-permission (quali autorizzazioni sono richieste), intent-filter e componenti esportati. Le autorizzazioni possono rivelare quali API vengono utilizzate (android.permission.CAMERA → fotocamera, android.permission.RECORD_AUDIO → audio). Le attività esportate identificano punti di ingresso senza autenticazione. Questa fase viene eseguita tramite aapt o ApkAnalyzer e richiede 1–2 minuti.
L'APK viene decompresso e classes.dex (o multidex) viene inserito in jadx. L'output è codice Java/Kotlin organizzato in pacchetti. L'analista cerca classi chiave: CryptoUtils, ApiClient, AuthManager, DatabaseHelper e verifica quali algoritmi vengono utilizzati. Se il codice contiene stringhe come AES/CBC/PKCS5Padding, l'applicazione utilizza la crittografia e la chiave deve essere trovata. In questa fase vengono identificati: chiavi hardcoded, URL API, token OAuth e segreti. Senza offuscamento, l'intero codice dell'applicazione si legge come un normale progetto Java.
Dopo aver configurato Frida o Objection per disabilitare l'SSL-pinning, l'analista avvia l'applicazione e intercetta il traffico di rete tramite Burp Suite o mitmproxy. I dati del traffico rivelano lo schema API: quali endpoint, quali parametri e in quale formato. Se possibile, l'analista modifica le richieste e verifica la risposta del server a dati errati o malevoli. La mancanza di validazione lato server è una vulnerabilità diretta scoperta in questo passaggio.
I risultati dell'analisi vengono registrati in formato strutturato. Per ogni punto vulnerabile trovato vengono indicati: classe e metodo, descrizione della vulnerabilità, vettore di sfruttamento e raccomandazione di correzione. Questo dataset viene trasmesso al team di sviluppo o utilizzato per compilare un report di test di penetrazione. In ambienti automatizzati (MobSF), il report viene generato automaticamente sulla base dei risultati dell'analisi statica e dinamica.
Il reverse engineering delle applicazioni iOS è più difficile di Android a causa dell'architettura di sicurezza più rigorosa di Apple e della mancanza di accesso diretto al file system sui dispositivi standard. È necessario il jailbreak per l'analisi iOS.
Un archivio IPA contiene un binario Mach-O — il formato universale di file eseguibili di Apple. Per la decompilazione vengono utilizzati Hopper Disassembler o IDA Pro. A differenza di Android DEX, che si decompila in Java con perdita minima, Mach-O contiene codice ARM64 nativo che viene ricostruito in pseudo-codice C con minore precisione. Hopper raggiunge il 60–70% di ricostruzione; il resto deve essere analizzato a livello assembly.
Frida su iOS richiede jailbreak e installazione di frida-server. Dopo la connessione, Frida intercetta i metodi Objective-C tramite il routing dei messaggi API. Per le applicazioni iOS, uno scenario tipico include: intercettare NSURLSession.dataTaskWithRequest per registrare le richieste HTTP, intercettare NSKeyedUnarchiver per analizzare dati serializzati e tracciare le query CoreData tramite frida-trace. Frida è diventata disponibile per iOS 15–17 con il rilascio del jailbreak Dopamine.
Il reverse engineering può comportare la modifica dell'IPA seguita dal reimpacchettamento e dall'installazione sul dispositivo. Gli strumenti includono: ipatool per decomprimere, MachOView per visualizzare le sezioni e optool per l'iniezione di codice. Dopo la modifica, l'IPA viene firmata tramite ldid o fastlane sigh per l'installazione su un dispositivo jailbreakato. Per iOS 16+, la firma del codice viene verificata a livello di Secure Enclave e un IPA modificato non verrà eseguito su un dispositivo non jailbreakato.
// Frida: intercettazione di richieste HTTP in un'applicazione iOS
if (ObjC.available) {
let NSURLSession = ObjC.classes.NSURLSession;
let dataTaskWithRequest = ObjC.protocol("NSURLSessionDelegate")
.method("- URLSession:dataTask:didReceiveData:");
Interceptor.attach(dataTaskWithRequest.implementation, {
onEnter(args) {
let data = ObjC.Object(args[3]);
console("[HTTP Response]", data.toString());
}
});
}
La protezione dal reverse engineering segue il principio della sicurezza a strati: nessun singolo metodo fornisce una protezione al 100%, ma una combinazione rende il reverse engineering economicamente non sostenibile.
Il livello base è ProGuard per Android, che sostituisce i nomi di classi e metodi con nomi di un singolo carattere. Per una protezione avanzata, DexGuard aggiunge l'induzione di overload (più metodi con firme diverse e lo stesso nome) e la crittografia delle stringhe AES-256. L'offuscamento aumenta il tempo di analisi del codice da 5 minuti a 5–20 ore a seconda del livello. DexGuard offusca inoltre il flusso di controllo, rendendo il codice illeggibile per jadx.
Tutte le costanti stringa — URL, chiavi, token, query SQL — vengono crittografate in fase di compilazione e decrittografate in fase di esecuzione. Ciò protegge dall'analisi statica delle stringhe nei file DEX. Un utente malintenzionato che esegue strings su app.apk non vedrà alcun endpoint API. Anche dopo la decompilazione, tutte le stringhe appaiono come dati binari. Ogni stringa può utilizzare una chiave separata, complicando la deoffuscazione.
Un agente RASP all'interno dell'applicazione rileva Frida e il debug in fase di esecuzione. I controlli di integrità tramite hash SHA-256 dell'APK impediscono l'esecuzione di una versione modificata dell'applicazione. Se l'hash APK non corrisponde all'hash di riferimento (memorizzato nel livello nativo), l'applicazione termina. Ciò blocca gli attacchi basati sulla modifica dell'APK, incluso il reimpacchettamento.
La logica di business critica dovrebbe essere eseguita sul server, non sul client. Anche se un utente malintenzionato decompila completamente l'applicazione, il codice del server rimane inaccessibile. La validazione lato server di tutte le richieste e dei parametri impedisce lo sfruttamento delle vulnerabilità scoperte durante il reverse engineering. L'attestazione del server tramite Play Integrity API o App Attest conferma che la richiesta proviene da un'applicazione autentica e non modificata.
Domande frequenti
Negli Stati Uniti, il reverse engineering è regolamentato dal DMCA — è consentito per interoperabilità, test di sicurezza e scopi di archiviazione. L'elusione delle misure di protezione tecnologica (DRM) è vietata. In Europa, l'articolo 6 dell'EUCD è simile al DMCA. In Russia, il reverse engineering senza il consenso del titolare del diritto d'autore può essere considerato violazione del diritto d'autore. La consulenza legale è obbligatoria prima del reverse engineering commerciale.
No. Qualsiasi codice eseguito sul dispositivo di un utente malintenzionato può essere analizzato — questo è un limite fondamentale del modello di sicurezza lato client. L'obiettivo della protezione è rendere il reverse engineering economicamente poco attraente: i costi di tempo e risorse devono superare il valore del risultato ottenuto. La combinazione di offuscamento, RASP e logica lato server è lo standard di protezione attuale.
Il reimpacchettamento è la modifica di un'applicazione tramite reverse engineering seguita dal riassemblaggio dell'APK. L'utente malintenzionato decompressa l'APK tramite apktool, aggiunge codice dannoso o sostituisce chiavi API, lo riassembla e lo firma con il proprio certificato. Il reimpacchettamento rappresenta l'86% di tutti gli attacchi su Android, secondo il Kaspersky Threat Report (2025). Contromisura: verificare la firma digitale in fase di esecuzione.
Lo script Frida Universal Android SSL Unpin intercetta le chiamate a TrustManager.checkServerTrusted e ServerTrustManager su iOS, sostituendo l'implementazione con un approccio allow-all. Viene utilizzata anche l'intercettazione dei metodi X509TrustManager in OkHttp e URLConnection. L'SSL-pinning può essere bypassato con Frida in 10 secondi usando uno script pronto. Una protezione più robusta è la trasparenza dei certificati tramite verifica del certificato lato server.
Il codice nativo C/C++ nelle librerie .so/.dylib è significativamente più difficile da reversare rispetto a Java in DEX. Swift con PGO e compilazione Osize produce un binario più offuscato di Objective-C. Rust si compila in codice nativo senza metadati di runtime e senza i wrapper standard di Objective-C, rendendolo il più difficile da reversare tra i linguaggi moderni di sviluppo mobile.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche