Reverse engineering tramite Ghidra
Ghidra è un software di reverse engineering sviluppato dall'Agenzia per la Sicurezza Nazionale degli Stati Uniti (NSA) e reso pubblico nel 2019. Questo strumento open-source è stato progettato per analizzare file binari eseguibili ci può aiutare a comprendere il funzionamento interno di un software senza avere accesso al suo codice sorgente. Ghidra offre molte funzionalità, tra cui un disassemblatore e un decompilatore, ovvero un componente che prova a ricostruire un codice equivalente simile a c, che facilitano la comprensione della logica interna dell'eseguibile. Il software può essere scaricato dal sito ufficiale del progetto.
Analisi di un semplice programma
Prendiamo come esempio questo programma scritto in c.
#include <stdio.h>
int check(char* s) {
if (s[0] != 'g')
return -1;
if (s[1] != 'o')
return -1;
if (s[2] != 'o')
return -1;
if (s[3] != 'd')
return -1;
return 0;
}
int main (){
char buf[4];
scanf("%4s", buf);
if (check(buf) == 0) {
puts("OK");
} else {
puts("NOPE");
}
return 0;
}
Questo programma prende in ingresso una stringa da quattro caratteri, ed esegue un controllo, se è esattamente good
allora stampa OK
, altrimenti stampa NOPE
.
Dal codice sorgente è molto facile capire il suo funzionamento, se proviamo a compilare e a guardare il codice assembly potrebbe essere molto complicato capire la logica.
Ghidra ci può aiutare proprio in questo.
Per prima cosa apriamo Ghidra e importiamo il file binario.
Una volta aperto ci verrà chiesto se vogliamo analizzare il file, e clicchiamo su sì.
A questo punto possiamo navigare tra le funzioni, e cliccare la funzione main
.
Nelle finestre principali, abbiamo sulla sinistra il disassemblatore, e sulla destra un tentativo di decompilazione della funzione main.
In realtà, a parte i nomi delle variabili il risultato della compilazione non è affatto male, ed è possibile capire cosa sta accadendo.
In particolare si vede che viene chiamata la funzione scanf
e la funzione check
.
Il risultato della funzione check
viene poi confrontato con 0
, e viene chiamata la funzione puts
di conseguenza.
La funzione check
è stata decompilata in maniera abbastanza strana, ma ci si può accorgere che ritorna 0
solo se la stringa in ingresso è proprio good
.
Si può rinominare le variabili cliccandoci sopra con il tasto destro, e scegliendo "rename variable", oppure premendo L
, così avremo un decompilato più pulito.
Si può quindi iterativamente migliorare la decompilazione rinominando variabili e funzioni e aggiungendo informazioni di tipo su array e strutture. Per approfondimenti sull'utilizzo di Ghidra si rimanda alla documentazione ufficiale.
Grazie a questi strumenti è possibile capire la logica interna di binari, in generale questo dovrebbe essere un argomento decisamente forte che si oppone al basare delle scelte di sicurezza sul fatto che un binario sia difficile da analizzare, come per esempio accadeva con i software che implementavano un algoritmo nascosto per controllare che l'utente avesse una licenza valida. Se questo algoritmo era presente nel binario, era solo questione di tempo prima che venisse analizzato e si potessero generare nuove chiavi, rendendo il controllo completamente inutile. Questo può essere visto anche come un esempio del fatto che security through obscurity (ovvero basare alcune scelte di sicurezza sul fatto che alcune componenti sono nascoste) spesso non costituisce un buon approccio, e dobbiamo sempre assumer che un attaccante abbia a disposizione tutto ciò di cui ha bisogno.