Decompilare ed offuscare il codice di un’app Android

16 febbraio 2016

La crescente popolarità di Android, negli ultimi anni, ha contribuito ad aumentare il numero di sviluppatori mobile e delle app da essi prodotte. Tuttavia molte di queste, pur utilizzando dati sensibili, non sempre tengono conto della sicurezza. Senza grandi difficoltà, infatti, è possibile entrare in possesso del codice sorgente di un’app e di altri dati sensibili, tramite un processo di reverse engineering del pacchetto APK (contenente tutti i file binari da eseguire su Android).

In questo articolo, focalizzeremo l’attenzione sui contenuti di un generico pacchetto APK ed illustreremo il processo di decompilazione e di offuscamento del codice in esso contenuto. Per farlo, lavoreremo su Windows, sebbene questo processo può essere opportunamente adattato su altri sistemi operativi.

Anatomia di un APK

Terminato il processo di compilazione di un progetto Android, l’output generato dal nostro IDE sarà un file con estensione .apk composto da quattro elementi:

NomeDescrizione
classes.dexContiene tutti i file .class dell’app convertiti nel formato bytecode interpretato dalla Dalvik Virtual Machine (una versione modificata della Java Virtual Machine, utilizzata da Android per l’esecuzione del codice)
resources.arscContiene le risorse compilate della nostra applicazione
Uncompiled resourcesRappresenta tutte le risorse non compilate dell’applicazione (ad esempio i contenuti della cartella assets nel progetto)
AndroidManifest.xmlContiene molte informazioni fondamentali per l’utilizzo dell’app. Di questo file si è approfonditamente discusso nella Guida Android di HTML.it

Di seguito è rappresentato il processo di creazione di un .apk ed il relativo contenuto.

Figura 1. Contenuto di un Android Package (fonte: developer.android.com) (click per ingrandire)

Contenuto di un Android Package

Un file .apk è semplicemente un archivio di dati contenente i suddetti file. Per poter avere accesso a tali file basterà quindi cambiare l’estensione del file in .zip ed estrarne il contenuto, ottenendo l’output seguente:

Figura 2. Anatomia di un APK (click per ingrandire)

Anatomia di un APK

Pur potendo esplorare il contenuto di un APK, non è sempre possibile leggerne i contenuti, in quanto i file .xml, .dex e .arsc sono codificati. È necessario, quindi, decompilare l’APK.

Prima di proseguite è bene sottolineare che, di per sé, tale procedura non è un operazione illegale, purché essa non sia usata per scopi di pirateria o analoghi.

Decompilazione di un APK

La decompilazione di un APK può essere effettuata impiegando tool come Android APK Decompiler e ApkAnalyser. Tali strumenti condividono lo stesso nucleo software di base, che si compone di tre elementi fondamentali:

  • Dex2jar, un convertitore di file .dex in file .class archiviati in un file .jar (consente anche di effettuare l’operazione inversa);
  • Apktool, strumento necessario per decodificare le risorse del progetto nel formato originale e per ricompilarlo salvando le modifiche apportate;
  • Java Decompiler (JD), un decompilatore Java dotato di un interfaccia grafica che permette di analizzare il bytecode contenuto in un file .jar.

L’opportuna combinazione di questi elementi rende il processo di decompilazione replicabile senza l’ausilio di software di terze parti. Vediamo come.

Creiamo una nuova cartella nel nostro ambiente di lavoro che conterrà:

  • i tre tool scaricati per il nostro sistema operativo;
  • l’APK che vogliamo analizzare;
  • l’archivio decompresso del suddetto APK, contenuto nell’omonima cartella.

Figura 3. Contenuto della cartella con gli strumenti e i dati necessari per la decompilazione (click per ingrandire)

Contenuto della cartella con gli strumenti e i dati necessari per la decompilazione

Il primo passo da compiere è la decompilazione del file classes.dex, presente nella cartella decompressa dell’APK, utilizzando Dex2jar.

Spostiamoci all’interno della cartella dex2jar-2.0 e apriamo la finestra di comando dalla cartella corrente (SHIFT + tasto_destro -> Apri finestra di comando qui). Dal prompt dei comandi digitiamo quindi:

    d2j-dex2jar.bat "[PERCORSO_FILE]\classes.dex"

ottenendo come risposta:

    dex2jar [PERCORSO_FILE]\classes.dex -> .\classes-dex2jar.jar

Questo ci informa che la decompilazione del file classes.dex (posizionato nel percorso indicato) è avvenuta con successo e il risultato della compilazione è il file classes-dex2jar.jar che si trova nella cartella corrente.

Figura 4. classes-dex2jar.jar è stato inserito nella cartella dex2jar2.0 (click per ingrandire)

classes-dex2jar.jar è stato inserito nella cartella dex2jar2.0

A questo punto per poter leggere il codice sorgente della nostra applicazione basta eseguire JD con doppio click sull’icona, e caricare il file classes-dex2jar.jar appena creato.

Figura 5. I sorgenti dell’APK decompilato, visualizzati tramite JD (click per ingrandire)

I sorgenti dell’APK decompilato, visualizzati tramite JD

Come mostrato in figura 5, è possibile esplorare il sorgente dell’APK decompilato e di carpirne il funzionamento.

Dex2jar permette solo di decompilare il codice sorgente ma non il file resources.arsc. Per farlo usiamo Apktool, che necessita dei seguenti file

  • apktool.bat;
  • apktool_2.0.3.jar;
  • l’APK da decompilare.

I file apktool.bat e apktool_2.0.3.jar sono disponibili sul sito ufficiale di Apktool. Il file apktool_2.0.3.jar deve essere rinominato in apktool.jar e inserito all’interno della stessa cartella contente il file .bat. Fatto ciò, posizioniamoci all’interno della cartella contente i file necessari, apriamo il prompt dei comandi da qui e digitiamo:

    apktool d "[PERCORSO_FILE]\NOME.apk"

Di seguito è mostrato il risultato del prompt dei comandi che conferma la avvenuta decompilazione con successo e mostra i passi compiuti per effettuarla.

Figura 6. Processo di decompilazione con Apktool (click per ingrandire)

Processo di decompilazione con Apktool

Il risultato di questa operazione è una cartella con il nome dell’APK, che conterrà il codice smali, i file originali codificati, le risorse contenute nella cartella res e l’AndroidManifest.xml, tutto perfettamente leggibile e modificabile. Lo smali è un assemblatore per il formato .dex usato dalla DVM con una sintassi simile a Jasmin e Dedexer, ma specifico per Android.

Figura 7. Risultato del processo di decompilazione dell’APK tramite Apktool (click per ingrandire)

Risultato del processo di decompilazione dell’APK tramite Apktool

Grazie all’utilizzo di questi strumenti è dunque possibile effettuare il reverse engineering dell’APK senza l’utilizzo di tool di terze parti e riuscendo ottenendo tutte le informazioni di interesse.

Offuscamento del codice

Avendo capito quanto è semplice analizzare il contenuto di un APK, è bene capire in che modo possiamo proteggere il codice sorgente per impedire a utenti malintenzionati di entrare in possesso del cuore della nostra app.

Una delle soluzioni più diffuse è ProGuard, un software che permette di:

  • ridurre il codice eliminando le classi e le variabili non utilizzate nell’applicazione;
  • ottimizzare il codice e le risorse, permettendo una riduzione del peso dell’APK;
  • offuscare il codice tramite la rinominazione di classi, attributi e metodi con nomi semanticamente non significativi.

Tale soluzione consente di avere un APK ottimizzato in termini di codice e dimensioni, ma soprattutto rende più complicato il processo di decompilazione e reverse engineering dell’APK. Inoltre, ProGuard può essere integrato nel sistema di build di Android, automatizzandone quindi gli effetti tutte le volte che viene generato un nuovo APK. Non è quindi obbligatorio abilitare ProGuard, ma è fortemente consigliato farlo nel caso in cui l’applicazione dispone di funzioni sensibili per la sicurezza.

Se abilitato, ProGuard verrà eseguito dal sistema di build solo in release mode (e quindi durante la creazione dell’APK di produzione), permettendo allo sviluppatore di lavorare in debug mode e di comprendere i possibili errori riportati senza decodificare l’informazione. Per abilitarlo nel proprio progetto, basta modificare la proprietà minifyEnabled nel file build.gradle cambiando il valore da false a true.

Creato l’APK in release mode il progetto avrà una nuova cartella chiamata mapping e contenuta all’interno della cartella outputs di build (figura 8), contenente i file seguenti:

FileDescrizione
dump.txtDescrive la struttura interna dell’APK
mapping.txtContiene la lista delle corrispondenze tra classi, metodi, attributi originali e offuscati, ed è fondamentale per interpretare i bug report provenienti dal Play Store
seeds.txtÈ la lista delle classi che non sono state offuscate
usage.txtSpecifica le porzioni di codice che sono state eliminate

Figura 8. Struttura del Progetto dopo l’attivazione e l’esecuzione di ProGuard (click per ingrandire)

Struttura del Progetto dopo l’attivazione e l’esecuzione di ProGuard

Per ulteriori dettagli su ProGuard si rimanda all’apposita pagina sulla documentazione ufficiale di Android.

Se vuoi aggiornamenti su Decompilare ed offuscare il codice di un’app Android inserisci la tua e-mail nel box qui sotto:
 
X
Se vuoi aggiornamenti su Decompilare ed offuscare il codice di un’app Android

inserisci la tua e-mail nel box qui sotto:

Ho letto e acconsento l'informativa sulla privacy

Acconsento al trattamento di cui al punto 3 dell'informativa sulla privacy