Attenzione: per questo articolo consiglio delle basi di programmazione ad alto livello (C o Java ad esempio), o per lo meno una conoscenza generica di come funziona un programma di base (funzioni, oggetti, if, while, for, etc.).
Cercherò come sempre di inserire approfondimenti o link per comprendere al meglio.
Come detto negli scorsi articoli sull’analisi dei malware, l’analisi statica e dinamica di base sono ottimi metodi per ottenere informazioni semplici, ma sono solo la punta dell’iceberg del processo.
Per esempio, se utilizziamo l’analisi di base su di un malware, possiamo osservare una particolare funzione importata, ma non potremo sapere quando e in che modo viene utilizzata. È qui che ci viene in aiuto il disassemblaggio ed è questo che verrà introdotto in questo articolo, cercando come sempre di poter dare un’infarinatura di base e link vari di approfondimento.
Nell’architettura dei computer, un sistema è suddiviso in diversi livelli di astrazione, i quali nascondono i dettagli di implementazione all’utente finale. Nel nostro caso, gli autori di Malware creano programmi con linguaggi ad alto livello e utilizzano un compilatore per generare il codice che verrà poi utilizzato; noi, per analizzarli, utilizziamo un dissassemblatore per generare codice assembly (il livello più vicino al linguaggio macchina) che potremo leggere e analizzare in modo da capire come il malware funziona.
In modo molto generale, i livelli principali sono:
Ogni istruzione del linguaggio assembly corrisponde ad un opcodes**_, _**il quale “dice” alla CPU quali operazioni effettuare. Gli operatori sono utilizzati per identificare i dati usati da un istruzione. Ci sono tre tipi:
I registri sono piccoli porzioni di dati disponibili nella CPU, il cui contenuto può essere trasferito e salvato in altre parti. I registri principali sono:
L’istruzione più comune e semplice è mov, la quale è utilizzata per spostare dati da una locazione ad un’altra. In altre parole per leggere e scrivere nella memoria. Il formato in cui è scritta è
mov destinazione, sorgente
Ad esempio possiamo trovare:
L’aritmetica nel codice assembly è la stessa di sempre, per cui gli operatori sono:
Altre operazioni possono essere xor, _or, shl _e_ ror. _Una guida scritta davvero bene sull’architettura x86 la potete trovare qui.
Un branch è una sequenza di codice eseguita condizionalmente, ossia in base al valore di una determinata variabile (in sostanza come se fosse un for o un while in linguaggio ad alto livello).
Il più popolare è l’istruzione jump _locazione, _composto da più di 30 tipi diversi. Alcuni sono:
Nel corso dell’articolo cercherò comunque di introdurre al meglio le modalità di utilizzo di ogni istruzione, in modo che possa essere capita. Come vedere sono molte, perciò non posso ovviamente fare un elenco di ognuna (che risulterebbe poco comprensibile senza esempi reali).
Poichè i Malware sono solitamente scritti in C, è importante sapere come un programma è tradotto dal C all’assembly. Questa conoscenza aiuterà anche a capire la differenze che intercorre tra i due linguaggi.
Questo è un semplicissimo programma C, convertito in assembly (gentilmente preso da C to Assembly). Come potete notare, anche con il più semplice dei programmi, decompilato in assembly, non si inizia a capire più nulla (provate, sempre tramite il sito, a convertire l’esempio Bubble sort).
Il software più potente e completo è indubbiamente IDA Pro. Purtroppo, essendo un software commerciale, costa e non poco (il pacchetto Starter 529 euro). È disponibile la versione gratuita a questo indirizzo, la quale ha alcune funzioni limitate (non è infatti da utilizzare in ambito professionale), ma per usi didattici può andare benissimo.
Altri software da poter utilizzare sono:
Nel prossimo articolo andrò ad analizzare un malware e cercherò di spiegare passo per passo tutte le funzioni e (quasi) tutte le informazioni da sapere per poter effettuare un’analisi statica avanzata.