Menu principale:
VìRû§
Virus che risiedono in memoria
I virus non residenti in memoria possono "agire" - sia per quanto riguarda
l'infezione che per quanto riguarda gli effetti collaterali - solo nel momento in
cui viene eseguito un file infetto.
I virus residenti in memoria, invece, non appena viene eseguito un file infetto,
si copiano in memoria per poter essere eseguiti assieme ad alcune funzioni del DOS,
i cosiddetti INTERRUPT.
- Cosa sono gli interrupt e come funzionano? -
Gli interrupt sono le funzioni basilari che sono fornite in parte dal BIOS in parte
dal DOS.
Gli interrupt sono numerati, e per eseguire un interrupt in assembler (piu' o meno
come in tutti gli altri linguaggi) l'istruzione e' la seguente:
INT xx
dove xx e' il numero dell'interrupt che vogliamo eseguire.
Alcuni interrupt sono "raccolte" di funzioni, e occorre scegliere la sottofunzione
da eseguire tramite il registro AH. Per molti interrupt occorre fornire dei dati in
input tramite i vari registri... e qui preferisco non dilungarmi perche' se dovessi
descrivervi ogni interrupt e come funziona ci metterei diversi giorni.
Comunque, gli interrupt 0h - 1Fh sono forniti dal BIOS, mentre quelli dal 20h in
poi sono forniti dal DOS.
Facciamo un esempio... diciamo che voglio scrivere qualcosa sullo schermo. Devo
utilizzare l'interrupt 21h, sottofunzione 09h, con la stringa che voglio stampare
(terminata dal caratttere "$") all'indirizzo di memoria DS:DX. Nel mio listato
dovro' scrivere:
Mia_Stringa db "Flamer has been here",13,10,'$' ;Questa e' la stringa che
;voglio stampare
MOV DX,offset Mia_Stringa ;Faccio puntare DS:DX a Mia_Stringa
MOV AX,segment Mia_Stringa
MOV DS,AX
MOV AH,09h ;Sottofunzione 9h
INT 21h ;Interrupt 21h
...semplice, no?
La stessa cosa in Turbo Pascal sarebbe:
var Mia_Stringa:array [1..23] of char;
Reg:TRegisters;
[...]
Mia_Stringa:='Flamer has been here'+#13+#10+'$';
Reg.DX:=ofs(Mia_Stringa);
Reg.DS:=seg(Mia_Stringa);
Reg.AH:=$09;
intr($21,Reg);
Ma in realta' come funziona un interrupt?... Cosa effettivamente succede quando
viene chiamato un interrupt?...
In realta' questo e' quello che succede:
1) Viene fatto un push di tutti i registri, e dell'indirizzo di memoria da cui e'
stato chiamato l'interrupt.
2) Il computer cerca nella tabella degli interrupt l'indirizzo di memoria a cui si
trova la routine di gestione dell'interrupt, e salta a quell'indirizzo.
La tabella degli interrupt si trova nella sezione di memoria che va da 0000:0000 a
0000:0400, in cui ogni doubleword (4 bytes) rappresenta un indirizzo per un
interrupt.
Per cui ad esempio l'indirizzo per la chiamata all'interrupt 0h sta in 0000:0000,
quello per l'interrupt 1h sta a 0000:0004, e cosi' via...
Modificando questa tabella e' possibile "aggangiare" un interrupt, reindirizzandolo
su un altra locazione di memoria, con l'effetto di sostituire la routine di
interrupt con una creata da noi, che al suo interno puo' anche richiamare la
routine originale dell'interrupt. L'effetto di tutto cio' e' che l'interrupt viene
eseguito normalmente, e in piu' succede anche qualcos'altro... ad esempio
l'esecuzione del codice di un virus.
Il fatto che esistano interrupt che vengono chiamati nei momenti piu' svariati
(pressione di un tasto, esecuzione di un file, lettura di un settore del disco,
ecc...) torna tutto a vantaggio dei virus, che possono ad esempio infettare i file
quando vengono eseguiti, senza bisogno di impiegare routine (e dimensioni) per
cercare i file infettabili all'interno delle varie directory...
Oppure anche intercettare comandi tipo DIR, e modificarne l'output in modo che le
dimensioni di eventuali file infetti non risultino sospette...
In definitiva, un virus che riesce ad aggangiarsi ad un interrupt viene a trovarsi
ad un livello piu' basso del DOS stesso, ed ha quindi la possibilita' di essere
molto piu' efficace di un virus non residente in memoria.
- Preesecuzione e postesecuzione -
Ma vediamo piu' in dettaglio come e' fatta una routine aggangiata ad un interrupt.
Esistono 2 metodi di aggangiamento di un interrupt: preesecuzione e postesecuzione.
Nel primo caso la routine chiama il vecchio interrupt e poi riprende il controllo
(eventualmente modificando i dati in output), mentre nel secondo l'interrupt
originale viene chiamato al termine della routine.
Trattare il secondo caso e' molto piu' facile, poiche' la chiamata all'interrupt
avviene molto semplicemente con un JMP FAR, al termine della nostra routine.
Infatti la routine originale termina gia' da se' con l'istruzione IRET (Interrupt
RETurn), che provvede a restituire il controllo al programma che aveva chiamato
l'interrupt e a ripristinare i registri dallo stack.
Nel caso della preesecuzione, invece, bisogna fare i conti con un piccolo problema.
Infatti la nostra routine chiama l'interrupt originale, ma poi il controllo non
deve tornare al programma che ha chiamato l'interrupt, ma alla nostra routine. Per
evitare inconvenienti e' percio' necessario simulare una chiamata ad interrupt in
questo modo:
PUSHF ;Salva tutti i registri nello stack
CALL FAR PTR xxxx:yyyy ;Esegue la chiamata all'interrupt originale
NB: Quando il vostro virus si copia in memoria deve sostituire xxxx:yyyy con il
puntatore che e' stato sostituito nella tabella degli interrupt, cioe' l'indirizzo
della routine di interrupt originale!!
Dopodiche' siamo liberi di inserire tutte le modifiche che vogliamo all'output
dell'interrupt e i vari effetti collaterali del virus, terminando la routine con:
IRET
per restituire il controllo al programma che aveva chiamato l'interrupt (ora si'!!)
- "Ma in memoria DOVE???" -
Riassumendo un virus residente in memoria deve:
1) Controllare di non essere gia' presente in memoria (lo si puo' fare controllando
l'indirizzo dell'interrupt aggangiato e verificando se i primi byte a
quell'indirizzo corrispondono ai primi byte del virus)
2) Scrivere il suo codice in memoria
3) Eventualmente leggere e salvare il vecchio indirizzo dell'interrupt da
aggangiare
4) Modificare la tabella degli interrupt per farlo puntare alla locazione di
memoria in cui si trova il codice del virus
Non vi sara' pero' sfuggito un fatto abbastanza importante, e percepisco gia' la
domanda che state per pormi.
Ma come fare per essere sicuri che il mio virus in memoria sia al sicuro, cioe'
che non venga sovrascritto da qualche altro programma (con conseguenze disastrose)?
Be'... diciamo che esistono svariati metodi per ovviare al problema. Il piu'
semplice e' quello di ricorrere all'interrupt 27h del DOS, che lascia in memoria il
programma (ma ne termina l'esecuzione e lo rende facilmente visibile). Un altro
metodo e' quello di andare ad occupare un'area di memoria che molto difficilmente
verra' utilizzata da un altro programma (come ad esempio l'area in cima alla
tabella degli interrupt, oppure in fondo alla memoria "bassa" cioe' proprio sotto i
640K).