Rimuovere il controllo sui permessi di root da una app Android

Lavorando nell’ambito della consulenza mi capita di dover analizzare il funzionamento di app e programmi realizzati da terzi, come avevo già avuto modo di raccontare in un talk sul reverse engineering dei dispositivi IoT. Lo scopo di questo articolo è raccontarvi un esempio pratico di quanto mi è capitato a febbraio, spiegando la metodologia utilizzata e fornendovi alcuni spunti di approfondimento.

In realtà in questo caso non si è trattato di lavoro, ma di una scena quantomeno bizzarra accaduta al bar assieme ad altri membri del GrappaLUG. Un amico mi ha esposto il suo problema:

Andrea guarda, la banca ora non ci manda più gli SMS con comunicazioni e codici, ci hanno detto di installare questa app. Quando l’ho avviata mi ha detto di disattivare il debug USB, ora mi dice che ho il root. Ma io non l’ho mai fatto, né ho cambiato il software di sistema, uso il telefono così come l’ho comprato.

Un’applicazione problematica

L’app bancaria in questione è Notify, la quale ha ricevuto moltissime recensioni da 1 stella per malfunzionamenti vari. Molti dei commenti lamentano lo stesso problema trattato in questo post.

All’avvio l’app tenta di effettuare un paio di controlli di sicurezza, presumibilmente per proteggere gli utenti da potenziali furti di codici. Il problema è che si rifiuta totalmente di funzionare se pensa non siano stati superati. L’utente non viene avvertito, ma totalmente tagliato fuori dall’app.

Mentre il debug USB è molto semplice da disattivare, togliere il root è più complicato… specialmente se il telefono non è sbloccato ma la app si rifiuta lo stesso di funzionare!

Dopo aver ragionato per qualche minuto ho capito che il mio amico non aveva molte opzioni ed era necessario modificare l’app per rimuovere il controllo per poter continuare a usare il conto corrente.

Cosa dice la legge

A questo punto, se siete persone prudenti e magari anche fan dei film di Antonio Albanese, vi sarà sicuramente venuta in mente una citazione:

Sì ma, è legale questa cosa?

Cetto La Qualunque

Si tratta di una giusta osservazione, in quanto il reverse engineering di codice di terze parti potrebbe sembrare una potenziale violazione di copyright. Fortunatamente la “Direttiva 2009/24/CE del Parlamento europeo e del Consiglio, del 23 aprile 2009, relativa alla tutela giuridica dei programmi per elaboratore” è piuttosto esplicita su questo punto:

Possono comunque sussistere circostanze in cui tale riproduzione del codice e la traduzione della sua forma sono indispensabili per ottenere le informazioni necessarie per conseguire l’interoperabilità con altri programmi di un programma creato autonomamente. Si deve pertanto ritenere che, solo in tali limitate circostanze l’esecuzione degli atti di riproduzione e traduzione della forma del codice, da parte o per conto di una persona avente il diritto di usare una copia del programma, è legittima e compatibile con una prassi corretta e pertanto essa non richiede l’autorizzazione del titolare del diritto. Uno degli obiettivi di tale eccezione è di consentire l’interconnessione di tutti gli elementi di un sistema informatico, compresi quelli di fabbricanti differenti, perché possano funzionare insieme.

Problema risolto. Il mio obiettivo era proprio quello di rendere interoperabile l’app della banca con il sistema operativo Android del mio amico, nonostante ci fosse un piccolo bug che ne impediva il corretto caricamento.

Analisi e modifica dell’app

L’ultima volta che ho parlato di analisi di un’app Android, avevo fatto riferimento al fatto che è abbastanza facile decompilare un file APK e ottenere del codice Java che spesso è praticamente perfetto. Questo è estremamente comodo per leggere come funziona un’applicazione, ma si tratta di un problema se si vuole modificarla e creare un nuovo APK.

Infatti se il codice decompilato è “quasi” giusto ma non perfetto, ricompilarlo risulta impossibile. Quello che invece conviene fare è lavorare sul codice smali, che è praticamente l’equivalente di assembly per Dalvik, la macchina virtuale Java di Android.

La procedura per modificare un’app si suddivide quindi nei seguenti passi:

  1. Estrarre il bytecode classes.dex dall’APK
  2. Disassemblarlo in codice smali
  3. Modificare il codice con attenzione
  4. Riassemblare il codice
  5. Rigenerare un APK con il codice modificato
  6. Firmare digitalmente l’APK

Questo procedimento richiede l’uso di vari strumenti, tra cui apktool e dex2jar. Si tratta di passaggi semplici (a parte la modifica del codice), ma sono ripetitivi ed è meglio automatizzarli. A tale scopo sono nati vari progetti per tutte le piattaforme. Per esempio, su Linux si può usare Adus.

Mentre ero lì che cercavo qualche idea su come agire, ho casualmente scoperto APK Easy Tool, un programma per Windows molto pratico che fornisce poche icone a portata di mouse. Siccome volevo sbrigarmela in pochi minuti e avevo una macchina virtuale Windows sul portatile, ho deciso di provarlo.

APK Easy Tool in azione

Dopo aver reperito una copia dell’app da APKMonk, ho provveduto a caricarla e ho premuto il tasto Decompile. In breve tempo ho trovato il risultato nella cartella Decompiled APKs, con un bel po’ di file da analizzare.

Cercando la stringa Errore: ho trovato subito una corrispondenza nel file smali/it/phoenixspa/notify/MainActivity.smali, in particolare nel metodo ALY6W. Lo stesso metodo viene invocato al termine del metodo SKMXK e dal codice notiamo delle parti molto interessanti:

.method public SKMXK()V
.locals 2
new-instance v0, Lit/phoenixspa/notify/check/CheckerService;
invoke-direct {v0}, Lit/phoenixspa/notify/check/CheckerService;->()V
invoke-virtual {v0, p0}, Lit/phoenixspa/notify/check/CheckerService;->ELG2Z(Lit/phoenixspa/notify/MainActivity;)Ljava/lang/String;

move-result-object v1
const-string v0, "phone"
invoke-virtual {p0, v0}, Lit/phoenixspa/notify/MainActivity;->getSystemService(Ljava/lang/String;)Ljava/lang/Object;
move-result-object v0
check-cast v0, Landroid/telephony/TelephonyManager;
invoke-virtual {v0}, Landroid/telephony/TelephonyManager;->getDeviceId()Ljava/lang/String;
move-result-object v0
invoke-virtual {v1, v0}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v0
if-nez v0, :cond_0
invoke-virtual {p0, v1}, Lit/phoenixspa/notify/MainActivity;->ALY6W(Ljava/lang/String;)V
:goto_0
return-void
:cond_0
invoke-virtual {p0}, Lit/phoenixspa/notify/MainActivity;->O2SHI()V
goto :goto_0

.end method

Ho tolto le righe bianche per questioni di spazio. Il metodo richiama un CheckerService e il codice presente in smali/it/phoenixspa/notify/check/CheckerService.smali ha chiari riferimenti alla libreria rootbeer. Perciò verifica se lo smartphone ha i permessi di root.

Alla fine del codice c’è un controllo. Se il valore di v0 è uguale a 0, viene invocato ALY6W, dando un messaggio di errore. Altrimenti, l’esecuzione salta all’etichetta :cond_0 che invoca 02SHI e poi salta nuovamente a :goto_0 per restituire void.

Il flusso di esecuzione è abbastanza semplice e si dovrebbe capire leggendo lo smali, ma per renderlo più chiaro ho generato questo diagramma di flusso con androguard:

Flusso di esecuzione del metodo SKMXK originale

Il controllo si può aggirare rimuovendo l’if-nez e i relativi salti, invocando sempre 02SHI senza controllare v0. Ho modificato l’ultima parte in questo modo:

    invoke-virtual {v1, v0}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v0
invoke-virtual {p0}, Lit/phoenixspa/notify/MainActivity;->O2SHI()V
return-void

.end method
Flusso di esecuzione del metodo SKMXK con patch

Tramite APK Easy Tool è bastato un click per ottenere un nuovo APK firmato automaticamente e pronto per essere installato. Per l’installazione, il modo più semplice è usare adb (va attivato il debug USB):

adb install it.phoenixspa.notify_2018-10-05.apk 

Ricordatevi che prima la versione originale deve essere rimossa, perché non abbiamo il certificato “vero” dello sviluppatore e perciò la nostra versione modificata è incompatibile con quella scaricata da Google Play.

L’app in esecuzione dopo la modifica

Conclusioni

Tutto il lavoro di analisi e modifica ha richiesto circa 15 minuti, seduti al tavolo di un bar, senza conoscenze troppo approfondite di smali. Volendo si sarebbe potuto rimuovere anche il controllo sul debug USB, ma quello è facile da disattivare e non è un grosso problema.

Sono comunque rimasto perplesso dalla necessità di dover arrivare a tanto per colpa di una scelta di sviluppo poco attenta, che di fatto taglia fuori alcune persone dall’utilizzo del proprio conto corrente. Ho detto al mio amico:

Accidenti, ti rendi conto di cosa è stato necessario fare? Una persona “comune” cosa fa? O cambia smartphone, o cambia banca… è assurdo.

Se non altro ora ho una copia dell’APK che posso usare per aiutare eventuali altri conoscenti che usano la stessa banca. Mi è già capitato con un famigliare!

L’analisi delle applicazioni Android è un argomento molto affascinante, utile anche per testarne la sicurezza o effettuare analisi forensi relative al funzionamento interno dell’app e di come vengono gestiti eventuali dati memorizzati.

In questo post abbiamo visto un semplice esempio di come una piccola modifica possa essere risolutiva, ma l’argomento è molto vasto. Perciò vi vorrei segnalare alcune risorse interessanti per approfondire l’argomento:

15 pensieri su “Rimuovere il controllo sui permessi di root da una app Android

  1. BRAVISSIMO! Spero tu abbia mandato il link di questo articolo a chi ha fatto il software!!

  2. Ottimo lavoro, analisi e non da ultimo articolo.
    Una curiosità: credo (non so e non la posseggo) che l’app Netflix faccia la stessa cosa per evitare copie pirata. Il tipo di controllo è altrettanto facilmente (per te, non certo per me, sei troppo avanti!) escludibile?
    Altra domanda: sempre in maniera fraudolenta (e sempre per ipotesi) aggirando questi ostacoli (root & usb) adesso il tuo amico potrebbe fare il root e continuare ad usare l’app. Ma è possibile anche sottrarre i codici?
    Grazie ancora del buon lavoro che fai.

  3. Dario, in realtà non ho mandato nulla. 😀 Gli autori dell’app hanno il codice e quindi possono risolvere in modo meno “artigianale”.

    Massimo, premetto che io Netflix non l’ho mai usato per cui ti rispondo in termini generici. Immagino che da qualche parte ci sia un pezzo di codice che fa il controllo… basta modificare quello e fargli sempre dire “no, niente root”. Nell’articolo io ignoro il risultato del controllo (lasciato immutato) ma è anche possibile modificare direttamente il risultato, così poi non si deve gestire la logica che decide cosa farsene. 🙂

    Non c’è niente di “fraudolento” nel fare il root del proprio cellulare. Certo è che se lui dovesse installare qualche app di dubbia provenienza e concedere ad essa i permessi di root, tale app potrebbe sfruttarli per rubargli i codici e spedirli a qualche malintenzionato.

  4. Ciao Andrea, ho letto l’articolo con interesse ed anche con un certo senso di disgusto, mi spiego meglio: mi sono proprio recentissimamente trovato in una situazione quasi analoga a quella del tuo amico, ovvero, trovandomi all’estero ho scoperto che non posso fare pagamenti MAV online tramite la mia banca (sono tentato di farne il nome ma dato che sono di buon umore evito). Ho risolto tramite un amico in Italia che ha gentilmente fatto il pagamento per me dal suo c/c online ed io sono riuscito a rimborsarlo facendo un bonifico online sul suo conto, che giro! Ecco perché ho scritto “disgustato”, trovo inconcepibile che applicazioni ed anche siti non certamente ludici siano così malfatti. Ciao

  5. non posso fare pagamenti MAV online tramite la mia banca

    Ohibò, questo è veramente assurdo. Io non ho problemi a pagare i MAV né con l’home banking né con altri servizi tipo le carte prepagate (per esempio Hype).

    Comunque capisco il senso di disgusto, io oggi ho scoperto che:

    • generalmente i bollettini postali si possono pagare online
    • il Ministero dell’Economia e delle Finanze ha esplicitamente bloccato i pagamenti online, quindi per pagare la quota di rilascio del passaporto bisogna necessariamente andare all’ufficio postale

    Poi parlano di digitalizzazione. :\

  6. Meglio evitare perché sarebbe legalmente problematico. Notify è solo un esempio per raccontare l’argomento del post (togliere un controllo da una app), comunque le istruzioni sono scritte in modo sufficientemente dettagliato da essere replicabile. 🙂

  7. Veramente un bell’articolo, trovato perché ho lo stesso problema del suo amico. Ho provato a replicare, ma nella decompilazione ho il seguente errore:

    I: Using Apktool 2.4.0 on it.phoenixspa.notify_2019-10-11.apk
    I: Loading resource table...
    I: Decoding AndroidManifest.xml with resources...
    S: WARNING: Could not write to (C:\Users\user\AppData\Local\apktool\framework), using C:\Users\user\AppData\Local\Temp\ instead...
    S: Please be aware this is a volatile directory and frameworks could go missing, please utilize --frame-path if the default storage directory is unavailable
    I: Loading resource table from file: C:\Users\user\AppData\Local\Temp\1.apk
    I: Regular manifest package...
    I: Decoding file-resources...
    I: Decoding values <em>/</em> XMLs...
    Exception in thread "main" java.lang.NullPointerException
        at brut.androlib.res.data.value.ResEnumAttr.serializeBody(ResEnumAttr.java:56)
        at brut.androlib.res.data.value.ResAttr.serializeToResValuesXml(ResAttr.java:64)
        at brut.androlib.res.AndrolibResources.generateValuesFile(AndrolibResources.java:704)
        at brut.androlib.res.AndrolibResources.decode(AndrolibResources.java:263)
        at brut.androlib.Androlib.decodeResourcesFull(Androlib.java:131)
        at brut.androlib.ApkDecoder.decode(ApkDecoder.java:124)
        at brut.apktool.Main.cmdDecode(Main.java:167)
        at brut.apktool.Main.main(Main.java:76)
    

    Ha qualche indicazione per risolvere l’errore? Oppure è la nuova versione dell’app?
    Grazie Lazza

  8. Non ho idea di come sia la versione attuale di Notify, dallo screenshot nel post vedo che al tempo era disponibile la versione 2018-10-05.

  9. Tanto per aggiornare. L’ultima versione che apk easy tool decompila e quella del 16/9/2019, però non sono riuscito a capire il codice. Ho seguito con successo la procedura sulla versione del 5/10/2018.

  10. Per tutti: per favore, non utilizziamo lo spazio commenti del blog per postare versioni modificate dell’app.

    L’articolo ha prima di tutto uno scopo didattico, se poi qualcuno vuole modificare un’app che ha installato nel proprio smartphone è libero di farlo in proprio (o chiedendo a un proprio consulente) seguendo metodologie simili. 🙂

    Gendibal, ah OK, probabilmente ogni versione è un po’ diversa dalla precedente.

Che cosa ne pensi?

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo di WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione /  Modifica )

Google photo

Stai commentando usando il tuo account Google. Chiudi sessione /  Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione /  Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione /  Modifica )

Connessione a %s...

Questo sito utilizza Akismet per ridurre lo spam. Scopri come vengono elaborati i dati derivati dai commenti.