Total Hack Cheat
Benvenuto/a su Total hack Cheat....
non aspettate altro tempo Registratevi!!

parte 6 e ultima guida linguaggio C

Vedere l'argomento precedente Vedere l'argomento seguente Andare in basso

parte 6 e ultima guida linguaggio C

Messaggio Da RaYoZ il Gio Mag 20, 2010 12:19 pm

Programmi residenti in memoria

Ogni programma residente in memoria si basa sulla ridirezione di uno

o piu' vettori di interruzione.
Fondamentalmente possiamo suddividere questo genere di programmi
in due tipi differenti.
Il primo tipo e' costituito da quei programmi che modificano una routine di interrupt per svolgere particolari compiti.
Supponiamo, ad esempio, di voler bloccare il settaggio video in una determinata modalita'.
Potremmo modificare la routine dell'interrupt 10H, quello che si interessa della gestione screen, in modo che ad ogni chiamata a questo venga vagliato il servizio richiesto.
Nel caso che si tratti di un servizio estraneo al settaggio del video ci sarebbe una chiamata al vecchio vettore di interrupt e quindi l'esecuzione della funzione richiesta.
Se la call e' relativa a un settaggio video allora si potrebbe eseguire una forzatura del valore relativo al modo e il successivo salto alla routine di interrupt originale.
In questo testo abbiamo gia' visto alcuni esempi relativi al tipo di programma appena accennato.
L'altro tipo di programmi residenti sono quelli del tipo di SideKick (Tm).
In quest'ultimo caso la ridirezione dei vettori d' interrupts avviene allo scopo di testare se in input sono stati battuti certi tasti corrispondenti a quelli per l'attivazione.
Come vedremo successivamente potrebbe verificarsi la necessita' di ridirigere o addirittura di scrivere altre routine.
Parlando dell'interrupt 27H avevo accennato alla difficolta' di scrivere in linguaggio C simili programmi.
In alcuni casi i problemi sono minimi ma in altri possono essere talmente complicati da far preferire una scrittura in linguaggio assembler.
In ogni caso non voglio lasciare ad intendere che scrivere un
programma residente in memoria mediante quest' ultimo risulti una
cosa semplice.
Le strade percorse da coloro che hanno scritto programmi di questo tipo sono svariate e non si puo' in nessun caso parlare di tecniche uniche.
In un esempio riportato nel capitolo riguardante la gestione della tastiera avevamo visto un programma che modificava il vettore dell' interrupt 16H allo scopo di eseguire l'intercettazione del tasto CTRL B.
Essenzialmente un programma residente si puo' suddividere in due
parti ovvero la parte che rimarra' in memoria e la parte d'installazione non residente.
Questo e' a livello semplicistico in quanto come vedremo esistono
ben altre problematiche.
Quando esiste la possibilita' conviene scrivere un programma in modo che risulti un .COM.
In ogni caso, per tornare al discorso di prima, possiamo fare la seguente schematizzazione.

segmento codice
origine 100H
salta all'installazione

procedura residente interrupt
abilita interrupt
e' una richiesta input tastiera ?
se si chiama vecchio interrupt (CALL)
altrimenti salta vecchio interrupt (JMP)
controlla il tasto
..................
nostro programma
..................
ritorna interrupt (IRET)
procedura residente fine

installazione parte NON residente

controllo se la procedura e' gia' stata installata
disattivazione CTRL BREAK
salvataggio vecchio vettore interrupt
settaggio nuovo vettore interrupt indirizzo procedura
residente
termina ma rimani residente
fine segmento codice

Come avrete notato ho segnato tra parentesi due diversi tipi di richiami alle vecchie routine d'interrupt.
Come sapra' chi conosce l'assembler il salto (JMP) non e' condizionato al ritorno mentre la chiamata (CALL) mediante l'istruzione RET ripristina l'indirizzo successivo alla CALL.
Questo significa che il controllo all'interno della modifica della routine d'interrupt avverra' prima sul registro AH, che come sapete contiene il numero del servizio, allo scopo di controllare se si tratta di una richiesta d'input da tastiera.
Nel caso che AH contenga il codice relativo ad un altro servizio e' inutile proseguire e quindi mediante un salto senza ritorno si ripassa il controllo alla vecchia routine d'interrupt.
In caso affermativo allora ci sara' una chiamata con ritorno in quanto dopo che la vecchia routine d'interrupt ha inputato il tasto ci dovra' essere il controllo sul suo codice al fine di accertare che questo sia quello da noi aspettato.
Chiaramente se questo equivale allora prima dell' IRET ci sara' il richiamo al nostro programma residente.
In altre parole quando ci serve una chiamata con ritorno al vecchio interrupt potremo simulare questa con

pushf
cli
call DWORD PTR cs:vecchio_vettore

Nel caso che il salto debba essere incondizionato allora

pop registri salvati
cli
jmp DWORD PTR cs:vecchio_vettore

In questo ultimo caso non avremo piu' il controllo del programma.
Voglio ripetere il discorso relativo alla chiamata dell'interrupt a costo di sembrare pedante in quanto penso che sia necessario capire il suo meccanismo.
Normalmente quando viene chiamato un interrupt viene letto il segmento e l'offset della routine di servizio dalla tavola dei vettori.
Supponendo di aver ridiretto l' int 16H e' chiaro che l'indirizzo contenuto in questa tabella e' quello relativo alla nostra routine residente in quanto l'operazione e' stata eseguita mediante la funzione d'installazione.
Come sapete un' interrupt potrebbe svolgere piu' servizi selezionabili, mediante opportuno settaggio prima della chiamata stessa, all'interno del registro AH.
Tutto questo significa che quando ci sara' una chiamata all'interrupt 16H il controllo passera' alla nostra routine.
Ora si dovra' vedere se si tratta di una richiesta d' input.

_key_i proc near
sti
cmp ah,0 ;e' una richiesta d'input
jne kio ;se no salta alla vecchia
;routine.
pushf ;se si simula una chiamata
cli ;al vecchio interrupt e dopo
call dword ptr cs:o_kio ;che ha eseguito la sua
;funzione
sti
cmp ax,4900H ;controlla se e' PgUp
jne fine ;se no ritorna dall'int
NOSTRE FUNZIONI........ ;se si richiama funzioni
fine:
iret
kio:
jmp dword ptr cs:o_kio
_key_i endp


L'esempio precedente non e' completo in quanto entrando nella routine d'interrupt si dovrebbero salvare tutti i registri che pensiamo vengano cambiati per poi ripristinarli prima di uscire.
Il discorso della memorizzazione e del ripristino vale anche per quanto riguarda l'ambiente precedente alla possibile esecuzione delle nostre funzioni.
Supponiamo che si stia lavorando con un programma di WP e che la nostra utility residente sia una finestra in cui appare un calcolatore tipo quello di SideKich.
Prima di eseguire il richiamo alle funzioni di questo dovremo salvare il modo video utilizzato dal programma di WP, la schermata presente ecc. in modo che terminando il nostro lavoro con l' utility sia possibile ripristinare l'ambiente originale del WP.
Sempre nell'esempio precedente avrete notato l'uso delle istruzioni CLI e STI.
Quando una routine d'interrupt e' chiamata il flag d'interruzione e' settato in modo che non possa essere richiesto nessun altro interrupt mascherabile.
Lasciare disabilitati questi interrupts per un tempo abbastanza lungo puo' creare dei problemi in quanto potrebbero esserci alcune periferiche i cui programmi agiscono in background che, nel frattempo che la nostra utility e' attiva, eseguono chiamate.
Appena si presenta la possibilita' conviene riabilitare il tutto mediante l'istruzione STI.
Il problema maggiore per la stesura di programmi residenti in memoria e' dato dagli interrupts non rientranti.
Il termine "rientrante" mi lascia un po' perplesso in quanto non so' se e' la traduzione esatta della parola inglese "reentrancy".
Tra questo tipo di interrupts troviamo quelli del Dos.
Mi spiego meglio.
Il Bios quando esegue una routine d'interrupt utilizza i registri e lo

stack per salvare alcuni valori usati durante l'elaborazione.
Il Dos, al contrario, utilizza delle zone di memoria per eseguire lo stesso compito.
Supponendo che venga effettuata una chiamata ad un servizio del Dos questa verrebbe eseguita e alcuni valori verrebbero salvati all'interno di variabili in memoria.
Se per puro caso venisse eseguita una seconda call al Dos mentre la prima non e' ancora terminata si potrebbe verificare che i dati salvati in una determinata area dal primo servizio vengano ricoperti da quelli scritti dal secondo.
Questo ci spinge a pensare che nei nostri programmi residenti dobbiamo vagliare l'istante in cui eseguire una call al Dos.
Un eventuale chiamata ad un servizio potrebbe avvenire solo nell'istante in cui il Dos risulta essere libero.
Allo scopo di girare intorno a questo tipo di problema ci si presenta una soluzione.

Tra gli interrupts e le calls non documentate visti precedentemente c'era il servizio 34H dell'interrupt 21H (Find
active byte).

Il metodo per accertarsi se e' in corso o meno una call del Dos e' quello di utilizzare questa funzione.
Questo servizio riporta il numero di chiamate al Dos che sono in esecuzione.
Il valore riportato dal servizio puo' essere 0, nel caso che il Dos sia libero, oppure maggiore di 0, nel caso che ci sia una call attiva.
Questo detto in altre parole significa che durante la stesura di un programma residente non potremo chiamare direttamente un servizio del Dos ma potremo farlo chiamando una nostra funzione che prima di eseguire la call dovra' accertarsi che il Dos non sia attivo.
Un esempio come quello che segue potrebbe sembrare essere esatto:


........... ; ERRATO !!!!!!!
attivo dw ?,?
...........
jmp init

new_interrupt proc far
...........
mov ah,00H ;prima di richiedere la call 00H
call active ;dell'int 21H guarda se il DOS e'
int 21H ;attivo.
...........
new_interrupt endp

active proc near
push di
push bp
mov di,attivo
mov ax,attivo[2]
mov bp,ax
a_1:
cmp BYTE PTR [bp][di],0
jne a_1
pop bp
pop di
ret
active endp

init:
...........
push es
mov ah,34H
int 21H
mov attivo,bx
mov attivo[2],es
pop es
...........


Purtroppo si rivela inefficace in quanto se nella routine active ci si entra nell' istante in cui il Dos non e' attivo allora si esce normalmente.
Nel caso in cui ci si entra quando l'active byte e' attivo allora il programma si blocca miseramente in quanto ci si entra in un loop infinito.
Il nostro programma occuperebbe per eseguire il loop tutto il tempo macchina non dando la possibilita' al Dos di finire i servizi che erano attivi e quindi di settare l'active byte a off.
La nostra funzione destinata a controllare lo stato del Dos dovra' essere abbinata ad un interrupt come l'int 8.
Questo come saprete viene richiamato varie volte al secondo.
In altre parole potremmo scrivere una piccola routine collegata a questo interrupt che testi tutte le volte che viene richiamato, in genere 18.2 volte al secondo, l'active byte e che setti un flag ad indicare che il Dos e' attivo o meno.
Dal nostro programma dovremo successivamente testare questo flag per sapere se esiste o meno la possibilita' di richiamare una call del Dos.
C'e' anche la possibilita' di utilizzare l'int 28H che come abbiamo visto viene richiamato quando il Dos attende un input.
Un altro esempio legato all'active byte e' il seguente.
Si tratta di una routine collegata all'interrupt 1CH (Timer Tick) che testa lo stato dell'active byte e lo stampa 18 volte al secondo nell'angolo in alto a sinistra.


;
; Show Active Byte - ACTIVE.ASM
;

code segment para 'code'
assume cs:code, ds:code
org 100H
;
active dw ?,?
;
jmp init
;
new proc far
push ax
push ss
push bp
push ds
push di
push cx
push dx
push bx
push es
sti
;
mov ax,0B800H

push ds
mov ds,ax
mov cx,active[2]
mov bp,cx
mov di,active
;
mov al,BYTE PTR [bp][di]
add al,10
mov ds:[0],al
pop ds
;
pop es
pop bx
pop dx
pop cx
pop di
pop ds
pop bp
pop ss
pop ax
iret
new endp
;
init:
;
mov ah,25H
mov al,1CH
mov bx,SEG new
mov ds,bx
mov dx,OFFSET new
int 21H
;
push es
mov ah,34H
int 21H
mov active,bx
mov active+2,es
pop es
;
mov dx,OFFSET init+100H
int 27H
code ends
end


Potrebbe essere adottata per piccole routine il seguente caso.
L'interrupt 16H (o al limite il 9H) viene ridiretto in modo che testi i caratteri in input alla ricerca del tasto di attivazione.
Quando questo viene intercettato la routine collegata all'interrupt di input da tastiera setta un flag che indichera' all'interrupt 8H lo stato di attivo.
Questo con il flag non settato tutte le volte che viene chiamato ritorna mediante un IRET.
Nel caso che l'int 8H testi il flag e verifichi la condizione di attivazione eseguira' le altre funzioni legate alla nostra utility.
In questo caso la routine collegata all'int 8H non ha solo piu' lo scopo di controllare lo stato del Dos ma bensi' quello di eseguire il nostro programma in quanto questo difatti diventa parte della routine di servizio dell'interrupt.
Nel seguente esempio viene utilizzato solo l'interrupt 16H che intercetta CTRL F1 o CTRL F2 e attiva l'applicazione.
Il programma serve al monitoraggio delle porte seriali COM1 e COM2.

;
;----------------------------------------------------------
; TSR.ASM
;----------------------------------------------------------
; NOTA: Il programma e' in grado di stabilire il tipo di
; scheda video installata. I tipi validi sono CGA ed
; Hercules.
;----------------------------------------------------------
;
attivable equ 0
noattiva equ 1
;
;
code segment para public 'code'
assume cs:code
;
;----------------------------------------------------------
; Salta a inizializzazione vettore interrupt 16H
;----------------------------------------------------------
;
jmp init
;
;----------------------------------------------------------
; Vecchi vettori d'interrupts e flag indicanti attivazione
;----------------------------------------------------------
;
dtr_on db '1'
db '$'
dtr_off db '0'
db '$'
error db 10,10,13
db 7
db 'Non ci sono porte seriali'
db 10,13
db 'Impossibile installare Monitor'
db 10,10,13
db '$'
buffer dw 2000 dup(0)
m_1 db '+---[COM Monitor 1.0]---+'
db 10,13
db ': :'
db 10,13
db ': DCD RNG DSR CTS DTR :'
db 10,13
db ': +-+ +-+ +-+ +-+ +-+ :'
db 10,13
db ': : : : : : : : : : : :'
db 10,13
db ': +-+ +-+ +-+ +-+ +-+ :'
db 10,13
db ': :'
db 10,13
db '+-------------------------+'
db '$'
attivo db '1'
db '$'
non_att db '0'
db '$'
;
;
cur_type_ch db 0
cur_type_cl db 0
cur_pos_x db 0
cur_pos_y db 0
;
old_int_16 dw ?,?
utile db 0
flag db 0
status db 0
video_type dw ?
port_attive db 0
num_port db 0
port_address dw 0
port_cl dw 0
port_lsb dw 0
port_msb dw 0
port_cm dw 0
com_1 db '1'
db '$'
com_2 db '2'
db '$'
msb db 0
lsb db 0
boh db '????'
db '$'
baud300 db ' 300'
db '$'
baud1200 db '1200'
db '$'
baud2400 db '2400'
db '$'
baud4800 db '4800'
db '$'
baud9600 db '9600'
db '$'
parity_ev db ',E'
db '$'
parity_no db ',N'
db '$'
data_bit_8 db ',8,'
db '$'
data_bit_7 db ',7,'
db '$'
stop_bit_1 db '1'
db '$'
stop_bit_2 db '2'
db '$'
;
;----------------------------------------------------------
; Routine interrupt 16H
;----------------------------------------------------------
;
new_int_16 proc far
sti
cmp ah,0
jne old_int_jmp
pushf
call DWORD PTR cs:old_int_16
cmp ax,5E00H
jne com2
com1:
call set_port_1
mov cs:port_attive,1
jmp test_ok
com2:
cmp ax,5F00H
jne end_int
cmp cs:num_port,2
jne com1
call set_port_2
mov cs:port_attive,2
test_ok:
cmp cs:flag,attivable
jne end_int
mov cs:flag,noattiva
call new_direct
mov cs:flag,attivable
end_int:
iret
old_int_jmp:
jmp DWORD PTR cs:old_int_16
new_int_16 endp
;
;----------------------------------------------------------
; Setta porte COM1
;----------------------------------------------------------
;
set_port_1 proc near
mov cs:port_address,3FEH
mov cs:port_cl,3FBH
mov cs:port_lsb,3F8H
mov cs:port_msb,3F9H
mov cs:port_cm,3FCH
ret
set_port_1 endp
;
;----------------------------------------------------------
; Setta porte COM2
;----------------------------------------------------------
;
set_port_2 proc near
mov cs:port_address,2FEH
mov cs:port_cl,2FBH
mov cs:port_lsb,2F8H
mov cs:port_msb,2F9H
mov cs:port_cm,2FCH
ret
set_port_2 endp
;
;----------------------------------------------------------
; Procedura principale
;----------------------------------------------------------
;
new_direct proc near
push ax
push bx
push cx
push dx
push si
push di
push es
push ds
call get_video
call save_cur
mov ah,1
mov ch,13H
mov cl,13H
int 10H
call leggi
call clear
mov dh,0
mov dl,0
call at
lea dx,m_1
call print
mov dh,0
mov dl,8
call at
cmp cs:port_attive,2
jne a_35
lea dx,com_2
jmp pok
a_35:
lea dx,com_1
pok:
call print
call f_read
call spy_baud
call dtr
call parity
mov ah,0
int 16H
call scrivi
mov dh,cs:cur_pos_y
mov dl,cs:cur_pos_x
call at
mov ah,1
mov ch,cs:cur_type_ch
mov cl,cs:cur_type_cl
int 10H
;
pop ds
pop es
pop di
pop si
pop dx
pop cx
pop bx
pop ax
ret
new_direct endp
;
;---------------------------------------------------------
; Controlla parita', data bit e stop bit
;---------------------------------------------------------
;
parity proc near
mov dx,port_cl
in al,dx
mov cs:utile,al
mov dh,6
mov dl,12
call at
mov al,cs:utile
and al,8
jz none
lea dx,parity_ev
jmp end_p_a
none:
lea dx,parity_no
end_p_a:
call print
mov al,cs:utile
and al,3
cmp al,2
jne otto
lea dx,data_bit_7
jmp stampa
otto:
lea dx,data_bit_8
stampa:
call print
mov al,cs:utile
and al,8
cmp al,8
jne uno
lea dx,stop_bit_2
jmp end_stop
uno:
lea dx,stop_bit_1
end_stop:
call print
ret
parity endp
;
;---------------------------------------------------------
; Controlla dtr
;---------------------------------------------------------
;
dtr proc near
mov dh,4
mov dl,23
call at
mov dx,port_cm
in al,dx
test al,1
jz no_dtr
lea dx,dtr_on
jmp end_pa
no_dtr:
lea dx,dtr_off
end_pa:
call print
ret
dtr endp
;
;---------------------------------------------------------
; Legge baud rate, parity, data bit, stop bit e dtr
;---------------------------------------------------------
;
spy_baud proc near
mov dh,6
mov dl,8
call at
mov dx,port_cl
in al,dx
or al,128
out dx,al
mov dx,port_lsb
in al,dx
mov cs:lsb,al
mov dx,port_msb
in al,dx
mov cs:msb,al
cmp msb,01H
jne no_300
lea dx,baud300
jmp end_spy
no_300:
cmp lsb,60H
jne no_1200
lea dx,baud1200
jmp end_spy
no_1200:
cmp lsb,30H
jne no_2400
lea dx,baud2400
jmp end_spy Segue ....

RaYoZ
Admin
Admin

Messaggi : 1040
Punti : 2245
Data d'iscrizione : 03.04.10
Età : 22
Località : immerso nei pensieri

Tornare in alto Andare in basso

Vedere l'argomento precedente Vedere l'argomento seguente Tornare in alto

- Argomenti simili

 
Permesso di questo forum:
Non puoi rispondere agli argomenti in questo forum