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.