TSR

Terminate and stay resident (TSR), ovvero programmi residenti in memoria.Il mondo del TSR è un passo molto importante, specialmente per i virus.Stando residente in memoria possiamo controllare tutti i movimenti eseguiti dal nostro sistema operativo.

Iniziamo con un esempio con il quale carichiamo un programma nella memoria, e tramite un'altra opzione lo rimuoviamo di nuovo.

push cs ; salviamo cs

pop ds;e lo carichiamo direttamente in ds

mov si, 81h

cld ; iniziando con la riga di comando segue il codice che controlla se è stato

premuto il tasto per la rimozione o meno

lodsb ; nulla di nuovo

cmp al,0dh ; qui controlliamo se la nostra stringa è finita, in caso affermativo

ciò significa che nella riga di comando non si trova nessun'altra lettera.Quindi

possiamo continuare ad eseguire il codice che installa il programma, oppure

prima controlla se è già stato installato.

jne XXX ; Se non corrisponde vuol dire che è stato inserito un'altra lettere.

Quindi a questo punto bisogna inserire un jump condizionale al codice che

controlla se la lettera corrisponde, come esempio, alla lettera "r", che useremo

per la rimozione.

jmp continua_normalmente ; altrimenti andiamo direttamente al codice d'installazione

Adesso controlliamo se la lettera inserita nel caso del jne ,cioè se la riga di

comando non fosse finita, corrisponde ad una "r"

cmp al,"r" ; lettera è una "r" ?

je rimuovi ; allora andiamo alla rimozione

cmp al, "R" ; in caso la lettera fosse maiuscola

jne XXX ; se non corrisponde possiamo uscire a questo punto ,oppure ritornare

al lodsb, come preferite.

Ora diamo uno sguardo alla parte del codice che si occupa della rimozione.

call siamo_residenti ; prima di tutto dobbiamo verificare bene se il nostro

programma è caricato in memoria

siamo_residenti: mov dx, 0

mov bh,192 ; qui controlliamo i numeri dal 192 al 255, visto che i numeri fino al

192 sono riservati

mov ah, bh ; copiamo il valore in ah

mov al,0 ; funzione 0 dell'interrupt 2f = installation check

push bx,ds

int 2fh ; esegue la funzione

pop ds bx ; ripristiniamo i valori

cmp al, 0ffh ; vediamo se questo numero è usato o meno

In caso che fosse occupato dobbiamo controllare tutti i numeri.Per questo

inseriamo un jump condizionale che ci porterebbe a questo codice

inc bh ; incremente bh di 1 = al prossimo numero

jnz siamo_residenti ; in caso il zero flag non sia settato, continuiamo con siamo_residenti

mov si, identificazione ; ora carichiamo la stringa d'identificazione (quella che volete)

mov cx, lunghezza_identificazione; adesso invece l'intera lunghezza della stringa ( lunghezza_identificazione = $ - identificazione)

cld

repe cmpsb ; corrisponde alla nostra stringa ?

jne XXX; se no andiamo dal codice che incrementa il numero cercando l'intera

memoria della nostra string

mov dx, 1

jmp finiamo_check ; se abbiamo trovato la nostra stringa possiamo concludere

il nostro check

mov ax, dx ; ecco fatto

Adesso continuiamo con il codice della rimozione

cmp ax,1 ; stringa installata ?

je continua ; bene, allora continuiamo

mov dx, offset non_residente ; carichiamo il messaggio che il programma non

è residente,quindi ovviamente non sarà possibile rimuoverlo

mov ah, 9 ; lo facciamo visualizzare sullo schermo

int 21 ; fatto

mov ax, 4c00h ; ed usando la funzione 4c00

int 21 ; possiamo tornare direttamente al DOS

Ora invece dobbiamo controllare se ci sono stati dei cambiamente al vettore dell'interrupt 2fh.Se ci sarà qualche problema non saremo in grado di rimuovere il nostro programma dalla memoria.

mov ax,352fh

push es ; salviamo es

int 21h

pop es ; quindi ripristiniamo es

cmp bx, es: nuovo_handler ;corrisponde al nuovo handler dlel'interrupt 2fh ?

je ripristina ; si=allora continuiamo con la rimozione

Adesso però vediamo in che cosa consiste il nuovo_handler

cmp ah,cs:corrisponde ; si tratta del nostro programma ? (corrisponde db ?)

je controlla ; allora si continua con il controllo dell'installazione

jmp cs:vecchio_handler ; altrimenti andiamo dal handler vecchio (vecchio_handler dd ? )

controlla: cmp al,0 ; ora controlliamo se il programma è installato o meno

jne ritorna ; altrimenti metteteci qualche riga che ritorna al codice della rimozione

mov al, 0ffh ; è residente ,quindi carichiamo il valore in al

push cs ; qui salviamo cs

pop es ; e lo ripristiniamo in es

mov di , offset cs:identificazione ; carica la nostra stringa d'identificazione

Ritornando al codice di sopra, nel caso che non fosse uguale ci manca solo un messaggio d'errore.

mov dx, offset impossibile

mov ah,9

int 21h ; usando come stringa per esempio: impossibile db " Impossibile rimuovere

programma dalla memoria.

Ora invece il codice "ripristina"

mov ax,252fh ; iniziamo a ripristinare il vecchio vettore dell'interrupt 2fh

push ds ; salviamo ds

lds dx,es:vecchio_handler ; carichiamo il pointer a 32 bit

int 21h ; esegue tutto ciò

pop ds ; ripristiniamo ds

Adesso dobbiamo ripristinare i segmenti e gli indirizzi dell'installazione

mov word ptr es:(16h),cs ; per quanto riguarda il program segment prefix

mov word ptr es:(0ah),offset segmenti; dopo continuiamo con il resto dei segmenti

mov word ptr es:(0ch),cs ; ecco fatto

mov sp_salvato,sp ; ora salviamo l'sp in sp_salvato (dw ?)

mov ss_salvato,ss ; lo stesso vale per il stack segment

mov ds_salvato,ds ; ed infine salviamo anche il ds

mov ah, 50h ; funzione 50h dell'interrupt 21h = set current process

mov bx,es

int 21h ; e lo eseguiamo

Ecco quello che riguarda il resto dei segmenti

cli ; clear interrupt flag, per disabilitare interrupts

mov ds,cs:ds_salvato

mov ss,ss_salvato ; copiamo il valore di nuovo in ss

mov sp;sp_salvato ; la stessa cosa per il stack pointer

sti ; set interrupt flag , per riabilitare interrupts

mov dx,offset rimosso ; il messaggio finale dopo la rimozione

mov ah,9

int 21; come esempio scegliamo " rimosso db " Programma rimosso dalla memoria"

mov ax,4c00h

int 21h ; e quindi possiamo uscire

 

Se invece non è stata inserita alcuna lettera dopo la stringa, andiamo subito alla parte che si occupa dell'installazione.Nel nostro caso, corrisponde a continua_normalmente.

Prima di tutto, anche qua, facciamo un controllo se il programma è già residente in memoria o meno.

call siamo_residenti; una call va benissimo, visto che il codice che controlla tutto

l'abbiamo già scritto.

cmp ax,0 ; vediamo se non è ancora installato

je vai ; in questo caso iniziamo con il codice d'installazione

mov dx,gia_installato

mov ah,9

int 21 ; quindi carichiamo un messaggio se il nostro programma è già residente

con un semplice gia_installato db " Programma già residente in memoria"

E poi possiamo tranquillamente uscire al DOS

Adesso l'installazione vera e propria

mov bh,192 ; qui controlliamo i numeri dal 192 al 255, visto che i numeri fino al

192 sono riservati

mov ah,bh ; adesso abbiamo caricato il numero in ah

mov al,0 ; ecco l'installation check

push bx ds ; ora salviamo

int 2fh; eseguiamo tutto ciò

pop ds bx ; ripristiniamo i nostri valori salvati

cmp al,0 ; verifichiamo il numero attuale è usato o meno

je installa ; se è libero possiamo installare il programma

inc bh ; altrimenti aumenteremo bh fino a quando non avremo trovato un numero

libero

jnz XXX; ecco il ciclo, che dovrà essere ripetuto se non abbiamo trovato un

numero non usato

installa: mov ah, salva_num ; salviamo il numero trovato (salva_num db ?)

mov ax,352fh ; ora iniziamo a salvare il vettore vecchio

int 21h

mov word ptr vecchio_handler(0),bx

mov word ptr vecchio_handler(2),es ; ecco fatto

mov ax,252fh ; adesso procediamo all'installazione del nuovo handler

mov dx, offset nuovo_handler ; ecco che lo carichiamo (il codice lo trovate più sopra)

int 21h ; eseguito !

mov dx,offset installato

mov ah,9

int 21h ; e allora finiamo un un piccolo messaggio che ci segnala il successo,tipo

installato db " Programma residente in memoria"

mov dx, offset installazione; ricordate l'inizio dove verificavamo la "r" ?

shr dx,4

inc dx ; incrementa dx di 1

mov ax,3100h

int 21h; Bene..e siamo giunti alla conclusione..il programma di installazione e rimozione in memoria è finito.

 

Adesso invece ci rivolgiamo ad un altro campo della programmazione, sempre in memoria.Si tratta di una tecnica indispensabile per ogni virus residente in memoria, l'aggancio di un interrupt, ovvero il cosiddetto "interrupt hooking".In questo caso prenderemo il controllo totale dell'interrupt.Quello che segue è un semplice programma che, una volta installato, vi farà ascoltare un "beep" quando l'interrupt agganciato è in uso.E' un esempio abbastanza semplice, e come interrupt sceglieremo quello che si occupa della stampante, cioè l'interrupt 17h

mov es, enseg ; abbiamo bisogno del environment segment

mov ah,49h ; funzione 49h dell'interrupt 21= release memory

int 21h

Ora agganciamo l'interrupt

mov ax,3500h + aggancio ; carichiamo il vecchio interrupt handler.Abbiamo detto

che come sempio useremo l'interrupt 17h, quindi il nostr aggancio corrisponde a   (aggancio equ 17h)

mov word ptr interrupt_vecchio,bx ; salviamo l'indirizzo del interrupt handler vecchio ( interrupt_vecchio dd ?)

mov word ptr interrupt_vecchio + 2,es; salviamo l'interrupt segment vecchio

mov ax,2500h + aggancio; funzione 25h dell'interrupt 21h = set interrupt vector. Con questo iniziamo ad installare il nostro nuovo interrupt handler

mov dx, offset interrupt_nuovo ; ecco che carichiamo il nuovo interrupt handler che constiste in

pushf ; simula la chiamata dell'interrupt al handler vecchio

cli

call CS:interrupt_vecchio ; ora ritroviamo il nostro interrupt_vecchio

push ds ; salva ds

push cs

pop ds ; quindi abbiamo cs in ds

sti ; riabilitiamo gli interrupts

push ax

push bx

push cx

push dx

push si

push di

push bp

push es ; Prima di accedere alla memoria salviamo tutti i registri

Ed ora la routine del signale acustico

mov al,07h

mov bh,0

mov cx,1

mov ah,0eh

int 10h ; quindi eseguiamo tutto ciò

Quando scrivetere il vostro codice che termina il programma non dimenticatevi di ripristinare tutti i registri.

Ora possiamo caricare un messaggio d'installazione

mov dx,offset installato

mov ah,9

int 21h ; Per esempio :installato db " Programma residente caricato"

Adesso,tramite la funzione 31h dell'interrupt 21h possiamo stare residenti nella memoria.

 

L'assembly - VAI         Indice - VAI