Analisi dinamica avanzata di un Malware - Parte prima: Debugging

Tempo di lettura: 7 minuti
debughome
debughome

Negli ultimi articoli ho introdotto in modo abbastanza approfondito l'analisi statica, la quale ricordo,è solo il primo passo per analizzare un programma maligno. La parte più importante e a mio parere più interessante, è l’analisi dinamica, dove si può vedere e modificare in tempo reale ciò che il programma crea, elimina, esegue. Per chi fosse qui per la prima volta, consiglio di leggere l'articolo sull’analisi dinamica di base, in modo da farsi un’idea su come funziona e cosa affronteremo in questo articolo.

Debugging

Un debugger è un software utilizzato per esaminare l’esecuzione di un altro programma, al fine di trovare errori e problemi di programmazione. Rispetto ai disassembler, che offrono uno snapshot del software e non possono fornire informazioni sull’esecuzione delle varie funzioni, un debugger fornisce una vista dinamica del programma, andando ad eseguire passo passo le varie istruzioni.

Quasi tutti i programmatori avranno familiarità con il debugging del codice sorgente di un software. Questo tipo di debugging (detto debugging a livello sorgente) è decisamente più semplice e meno complesso rispetto al tipo di debugging che andremo ad utilizzare noi, chiamato invece debugging a livello assembly. Quest’ultimo, invece che operare sul codice sorgente (che non abbiamo), opera a basso livello, quindi in Assembly.

Utilizzare un Debugger

Ci sono due modi per debuggare un programma:

  1. Avviare il programma con il debugger;
  2. Allegare il programma (già avviato) ad un debugger.

Mentre nel primo caso possiamo analizzare il programma in ogni sua funzione, nel secondo i thread dello stesso sono in pausa e possiamo debuggarli (utile ad esempio per analizzare un singolo processo, infettato dal malware).

Singolo Passo

L’azione più semplice che si può effettuare con un debugger è il singolo passo, ossia avviare un’istruzione singola e ritornare il controllo al debugger. In questo modo è possibile analizzare una specifica funzione nella sua completezza ed osservare tutto ciò che avviene nel programma.

Esempio di codice assembly in OllyDbg
Esempio di codice assembly in OllyDbg

In OllyDbg ci sono due modi di effettuare il singolo passo, che sono:

  1. Step Into: effettua il passo dentro l’istruzione, quindi la prossima istruzione che verrà mostrata sarà la prima istruzione della funzione chiamante;
  2. Step Over: effettua il passo oltre l’istruzione, quindi la prossima istruzione che verrà mostrata sarà l’istruzione dopo il return della funzione in esame.

Lo Stepping Over ci permette di evitare le istruzioni che non vengono mai chiamate ed evitare di analizzarle tutte. Nel caso venga dato errore con lo Step Over, significa che è stata saltata un’istruzione essenziale, ma basterà riavviare il programma, tornare al punto di Step Over ed analizzare con Step Into.

Mettere in pausa l’esecuzione con i Breakpoints

I Breakpoints sono utilizzati per mettere in pausa l’esecuzione e permetterci di esaminare lo stato del programma in quel momento. Essi sono necessari perchè non è possibile accedere ai registri o agli indirizzi di memoria mentre il programma è in esecuzione, visto che i loro valori cambiano in continuazione.

Tipi di breakpoint in OllyDbg
Tipi di breakpoint in OllyDbg

Ci sono tre tipi principali di breakpoints:

  1. _Software Breakpoints: _obbligano il programma a fermarsi quando una particolare istruzione è eseguita. Per fare ciò modificano il il primo byte dell’istruzione con 0xCC in modo che si fermi. Nel caso quel byte sia modificato da qualche altra funzione precedente, rischiamo di perderlo e verrà completamente ignorato;
  2. _Hardware Breakpoints: _in questo caso non importa quale byte sia memorizzato, l’hardware breakpoint rileva il puntatore a quell’istruzione e obbligherà in modo permanente al programma di fermarsi;
  3. Breakpoint condizionali: appartengono alla categoria Software, ma bloccheranno il programma solo se una determinata condizione è vera (condizionali, appunto).

I breakpoint sono molto utili per visualizzare un valore prima che esso venga eliminato da una funzione. Se, ad esempio, stiamo analizzando un Ransomware e questo elimina la chiave (o l’algoritmo) di cifratura dopo una certa funzione, potremmo (in via del tutto teorica, questo varia molto da programma a programma) effettuare un breakpoint, analizzare il codice Assembly, ricavare la chiave o addirittura l’algoritmo e decrittografare tutto ciò che è stato cifrato dal Malware.

Conclusioni

Come sempre, il primo articolo è un’infarinatura teorica in modo da iniziare a familiarizzare con ciò che andremo a mettere in pratica nelle prossime analisi. Il debugging è un passo fondamentale per riuscire ad analizzare in modo profondo un software, per vedere cosa avviene all’interno dello stesso e quali informazioni possiamo estrarre. Nel prossimo articolo introdurrò il software OllyDbg e le sue particolarità, come avevo fatto tempo fa con IDA.