home *** CD-ROM | disk | FTP | other *** search
- ;* ------------------------------------------------------- *
- ;* PROTECT.ASM *
- ;* *
- ;* Utility zum Schutz vor Viren *
- ;* (c) 1988 by Jörg Peter und TOOLBOX *
- ;* ------------------------------------------------------- *
- ;* Achtung, innerhalb des residenten Teils dürfen keine *
- ;* DOS-Funktionen benutzt werden. Da das Programm selbst *
- ;* DOS-Funktionen über den Interrupt 9 unterbricht, *
- ;* würde dies zu Stack-Kollisionen führen. *
- ;* Assemblieren mit: masm protect.asm *
- ;* Linken mit : link protect.obj *
- ;* --> protect.exe *
- ;* ------------------------------------------------------- *
-
- keystroke equ 1 ;Tastencode Programm (de)aktiviert
- seite equ 0 ;Nummer der zu verwendenden
- ;Bildschirmseite
- max_intvektor equ 29H*4 ;25H = letzter nicht berücksichtigter
- ;Int-Vektor
- max_lines equ 10 ;Anzahl der Zeilen, die auf dem
- ;Bildschirm ausgegeben werden, bevor
- ;eine Warteabfrage gestellt wird
-
- CODE SEGMENT PARA 'CODE'
- assume cs:code, ds:code, es:code
- org 100H
- jmp hp
-
- pointer dw offset puffer ;zeigt auf den noch verbleibenden
- ;Platz im Puffer "puffer"
- puffer db 1000 dup (0) ;dient zum Abspeichern der Namen
- ;der geöffneten Dateien
- puffer_ende: ;Dient zum Erkennen des Pufferendes
- ;dadurch kann "puffer" ohne Pro-
- ;bleme in der Größe geändert werden
-
- int_vektoren db max_intvektor dup (?)
- ;Feld dient zum Sichern der Interruptvektoren
-
-
- geladen db 13,10,'** PROTECT geladen, Copyright (c) 1988 '
- db 'by Jörg Peter **'
- db 13,10,' (De)Aktivieren über <Ctrl>+<Alt>+'
- db '<Esc>',13,10,'$'
- aktivieren db 13,'*** ACHTUNG !, PROTECT aktiviert ',13,'$'
- deaktivieren db 13,'*** PROTECT deaktiviert ! ***',13,13
- db 'Schreibversuche Diskette $'
- da_2 db 13,' Festplatte ','$'
- warnung db 13,13,'Versuchter Zugriff auf Spur 0','$'
- dateinamen db 13,13,'Folgende Dateien wurden geöffnet :'
- ausgabe_cr db 13,'$'
- warten db 13,'Weiter --> eine Taste betätigen ',13,'$'
- int_veraenderung db 13,'Diese Interrupt Vektoren wurden '
- db 'verändert, Wiederherstellen (J/N) ? $'
-
- int_13 dd ? ;Pointer auf die Interrupt 13H
- ;Handling Routine im BIOS
- int9 dd ? ;Pointer Interrupt 9 Routine im BIOS
- int21 dd ? ;Pointer auf die Interrupt 21H Routine
-
- warning db 0 ;Byte wird auf den Wert 255 gesetzt,
- ;falls ein Zugriff auf die
- ;Bootspur erfolgt
- attribut db ? ;dient zum Sichern des festgestellten
- ;Ausgabeattributs
- on db 0 ;=255 wenn Protect aktiv, =0 wenn nicht
- f_count dw 0 ;Zähler für Floppy Schreibzugriffe
- h_count dw 0 ;Zähler für Harddisk Schreibzugriffe
-
- page_count db 0 ;wichtig für die Prozedur Textausgabe,
- ;zählt wie viele Zeilen
- ;auf dem Bildschirm ausgegeben wurden
-
- change_int db 0 ;wird auf 255 gesetzt, falls das Programm
- ;eine Veränderung eines oder mehrerer
- ;Interruptvektoren festellt
-
- aktiv db 0 ;enthält den Wert 255, falls das residente
- ;Programm bereits über den Interrupt 9
- ;aktiviert wurde
-
-
- LESE_CURSOR_POSITION PROC NEAR
- ;Prozedur liest die aktuelle Cursorposition
- ;und gibt diesen Wert in DX zurück
- push ax
- push cx
- mov ah,3
- mov bh,seite
- int 10H
- pop cx
- pop ax
- ret
-
- LESE_CURSOR_POSITION ENDP
-
- WERT_AUSGEBEN PROC NEAR
- ;Prozedur gibt den Wert in AX an der
- ;aktuellen Cursorposition aus, der
- ;Cursor bleibt auf der letzten Ziffer
- ;der ausgegebenen Zahl stehen.
- ;Voranstehende Nullen werden unterdrückt
- ;Die Register AX,BX,CX werden verändert
- push dx ;AX an aktueller Cursorposition ausgeben
- xor dx,dx
- mov bx,10
- div bx ;AX durch 10 teilen, Ergebnis in AX,
- ;Restwert steht dann in DX
- push dx ;letzte Ziffer wird auf den Stack gelegt
- cmp ax,0 ;Wenn Ausgangswert kleiner 10 war, ist AX
- ;jetzt null. Somit muß kein weiterer Wert
- ;ausgegeben werden
- je wa_1
- xor dx,dx
- div bx ;Vorletzte Ziffer errechnen ...
- push dx ;... und auf dem Stapel ablegen
- cmp ax,0
- je wa_2
- xor dx,dx
- div bx
- push dx
- cmp ax,0
- je wa_3
- xor dx,dx
- div bx
- push dx
- call lese_cursor_position ;erstes Zeichen ausgeben
- mov cx,1
- pop ax
- mov ah,10
- add al,'0'
- int 10H
- inc dl
- mov ah,2
- int 10H
- ;zweites Zeichen
- wa_3:
- call lese_cursor_position
- pop ax
- mov ah,10
- add al,'0'
- int 10H
- inc dl
- mov ah,2
- int 10H
- wa_2:
- call lese_cursor_position
- ;drittes Zeichen
- pop ax
- mov ah,10
- add al,'0'
- int 10H
- inc dl
- mov ah,2
- int 10H
- wa_1:
- call lese_cursor_position
- ;viertes Zeichen
- pop ax
- mov ah,10
- add al,'0'
- int 10H
- pop dx
- ret
-
- WERT_AUSGEBEN ENDP
-
-
- WRITE_CR PROC NEAR
- ;Schreibt CR in den Tastatur-Puffer. Dadurch
- ;wird an das Programm, das als nächstes über
- ;den Interrupt 16 die Tastatur ausliest, ein
- ;<Return> übergeben.
- push ds
- push ax
- mov ax,40H
- mov ds,ax
- mov ds:word ptr[1AH],1EH
- mov ds:word ptr[1CH],20H
- mov ds:word ptr[1EH],1C0DH
- pop ax
- pop ds
- ret
-
- WRITE_CR ENDP
-
-
- LF PROC NEAR
- ;Input: DH=aktuelle Zeile des Cursors(0..24)
- ; DL=aktuelle Spalte
- ;Prozedur erhöht die aktuelle Zeile, wird
- ;dabei der Bildschirmbereich verlassen,
- ;führt die Prozedur ein Scrolling durch. DH
- ;bleibt dann konstant. Die entstehende
- ;Leerzeile am unteren Bildschirmrand wird
- ;wird mit dem Attribut, das in "attribut"
- ;steht, gefüllt.
- ;Die Register DX,CX werden verändert
- cmp dh,24
- jb kein_scrolling
- push dx
- mov ax,601H
- mov cx,0
- mov dh,24
- mov dl,79
- mov bh,cs:Attribut
- int 10H
- pop dx
- dec dh
- kein_scrolling:
- inc dh
- mov dl,0
- ret
-
- LF ENDP
-
-
- TEXT_AUSGABE PROC NEAR
- push ds ;Input: DS:SI -> zeigt auf den auszugebenden
- ;Text. '$' muß als Endekennung am Ende der
- ;Zeichenkette stehen.
- ;Die Prozedur entspricht der Funktion 9 des
- ;Interrupts 21H, dieser konnte nicht ver-
- ;wendet werden, da die Gefahr einer Stack-
- ;kollision besteht.
- push si ;Lesen der aktuellen Cursorposizion,
- ;wird in DX zurückgegeben
- call lese_cursor_position
- cld
- ausgabe_loop:
- ;Bildschirm voll ?
- cmp cs:page_count,max_lines
- ;Festellen, ob Abfrage erfolgen soll
- jb nicht_voll
- mov cs:page_count,0
- mov si,offset warten
- call text_ausgabe ;Ausgabe des Textes "Weiter --> Eine .."
- xor ax,ax
- int 16H ; Warte bis Taste gedrückt wird
- nicht_voll:
- ;Cursor setzen ;setzen des Cursors auf die Position, die
- ;in DX stehen muß
- mov ah,2
- mov bh,seite
- int 10H
- pop si ;Restaurieren des Pointers auf den
- ;auszugebenden Text
- lodsb ;Zeichen holen
- push si ;aktuelle Lesepostion wieder sichern
- cmp al,'$' ;Ende erreicht ?
- je ausgabe_ende
- cmp al,13 ;Soll ein LF erfolgen
- jne kein_lf
- call lf
- inc cs:page_count ;Anzahl der ausgegebenen Zeilen erhöhen
- jmp ausgabe_loop ;Rücksprung, nächstes Zeichen holen
- kein_lf:
- ;Zeichen ausgeben
- mov ah,10
- mov bh,seite
- mov cx,1
- int 10H ;Zeichen in AL ausgeben
- inc dl ;Spaltenpsosition erhöhen
- cmp dl,80 ;letzte Spalte erreicht ?
- jl ausgabe_loop
- call lf ;LF ausführen und
- inc cs:page_count ;Anzahl der ausgebenen Zeilen erhöhen
- jmp ausgabe_loop
- ausgabe_ende:
- mov cs:page_count,0
- pop si
- pop ds
- ret
-
- TEXT_AUSGABE ENDP
-
-
- SAVE_INT_VEKTOREN PROC NEAR
- ;Diese Prozedur sichert alle Interrupt-
- ;vektoren bis zum Vektor "max_intvektor"/4
- ;in den Puffer "int_vektoren"
- push cx
- push si
- push di
- push ds
- push es
- mov ax,0
- mov ds,ax
- mov ax,cs
- mov es,ax
- mov si,0
- mov di,offset int_vektoren
- mov cx,max_intvektor
- shr cx,1
- cld
- rep movsw
- pop es
- pop ds
- pop di
- pop si
- pop cx
- add dh,2
- ret
-
- SAVE_INT_VEKTOREN ENDP
-
-
- CURSOR_WEITERSETZEN PROC NEAR
- ;liest die aktuelle Cursorposition aus und
- ;setzt Cursor um eine Stelle weiter
- push cx
- mov bh,seite
- mov ah,3
- int 10H
- inc dl
- mov ah,2
- int 10H
- pop cx
- ret
-
- CURSOR_WEITERSETZEN ENDP
-
-
- RESTORE_INT_VEKTOREN PROC NEAR
- ;Stellt fest, ob Interruptvektoren verändert
- ;wurden (durch Vergleich mit dem entspre-
- ;chenden Puffer. Falls eine Veränderung
- ;stattgefunden hat, wird nachgefragt, ob
- ;diese wieder restauriert werden soll
- push cx
- push di
- push si
- push ds
- push es
- mov cs:change_int,0
- mov si,offset ausgabe_cr ;SI zeigt auf zwei CR-Zeichen
- call text_ausgabe
- ;Hat ein Veränderung stattgefunden ?
- mov ax,0
- mov es,ax
- mov ax,cs
- mov ds,ax
- mov di,0
- mov si,offset int_vektoren
- cld
- mov cx,max_intvektor
- shr cx,1
- push dx
- next_intvektor:
- repe cmpsw ;Vergleich des Puffers "int_vektoren" mit
- ;den Interruptvektoren
- cmp di,max_intvektor
- ;Falls Ende erreicht, Vergleich beenden
- jae restore_control_ende
- push cx
- mov cs:change_int,255
- ;Unterschied festgestellt daher Kennungsbyte
- ;auf 255 setzen und
- mov ax,di
- mov cl,2
- shr ax,cl
- push ax
- call wert_ausgeben
- ;Nummer des geänderten Interrupts ausgeben
- call cursor_weitersetzen
- mov al,',' ;Komma ausgeben
- mov ah,10
- mov bh,seite
- mov cx,1
- int 10H
- call cursor_weitersetzen
- pop ax
- ;Wiederherstellen des Pointers auf das
- ;Zeichen innerhalb von "int_vektoren" an
- ;der Vergleich fortgesetzt werden soll
- inc ax
- mov cl,2
- shl ax,cl
- mov di,ax
- add ax,offset int_vektoren
- mov si,ax
- pop cx
- jmp next_intvektor
- restore_control_ende:
- pop dx
- inc dh
- cmp cs:change_int,255
- jne restore_ende
- mov si,offset int_veraenderung
- ;Textausgabe "Diese Interruptvektoren..."
- call text_ausgabe
- xor ax,ax
- int 16H
- cmp ah,24H ;Ist die gedrückte Taste "J" ?
- jne restore_ende ;Falls nicht, Prozedur beenden
- mov di,0 ;ansonsten Interruptvektoren restaurieren
- mov si,offset int_vektoren
- mov cx,max_intvektor
- shr cx,1
- cld
- rep movsw
- restore_ende:
- pop es
- pop ds
- pop si
- pop di
- pop cx
- ret
-
- RESTORE_INT_VEKTOREN ENDP
-
-
- DATEN_AUSGABE PROC NEAR
- ;Diese Prozedur wird nach dem Deaktivieren
- ;des Programmes aufgerufen. Sie übernimmt
- ;die gesamte Datenausgabe
- ;Ausgabe der Anzahl der Schreibzugriffe auf
- ;Disketten und Festplatten
- mov ax,cs
- mov ds,ax
- mov si,offset deaktivieren
- call text_ausgabe
- mov ax,cs:f_count
- call wert_ausgeben
- mov si,offset da_2
- call text_ausgabe
- mov ax,cs:h_count
- call wert_ausgeben
-
- ;Ausgabe Warnung ?
- cmp cs:warning,255
- ;Wurde ein Schreibversuch auf die Bootspur
- ;versucht ?
- jne keine_warnung
- mov si,offset warnung
- ;Ja, daher spezielle Meldung ausgeben
- call text_ausgabe
- keine_warnung:
- ;Kontrolle, ob Interruptvektoren verändert
- ;wurden. Falls Ja, Abfrage ob diese wieder
- ;restauriert werden sollen
- call restore_int_vektoren
- ;Ausgabe der Dateinamen, auf die nach dem
- ;Aktivieren von Protect zugegriffen wurde
- mov si,offset dateinamen
- call text_ausgabe
- mov si,offset puffer
- cld
- da_loop:
- cmp si,[pointer]
- je da_loop_ausgabe
- lodsb
- cmp al,0
- jne da_loop
- mov ds:byte ptr[si-1],13
- jmp da_loop
- da_loop_ausgabe:
- mov ds:byte ptr[si],'$'
- mov si,offset puffer
- call text_ausgabe
- ret
-
- DATEN_AUSGABE ENDP
-
-
- INT13_HANDLING PROC NEAR
- ;Diese Prozedur übernimmt die Kontrolle des
- ;Interrupt 13H. Sie wird nur aktiv, wenn die
- ;die Speicherzelle "on" den Wert 255 enthält
- cmp cs:on,255
- je handling
- jmp dword ptr cs:[int_13]
- handling:
- ;Prüfen ob ein Schreibzugriff oder Formatie-
- ;rungversuch erfolgen soll. Falls nein, wird
- ;die ursprüngliche BIOS Routine aufgerufen.
- ;Falls Ja, wird notiert, ob der Zugriff auf
- ;Diskette oder Festplatte erfolgen sollte
- ;und wieviele Sektoren geschrieben werden
- ;sollten. Findet ein Zugriff auf Spur Null
- ;statt, wird die Speicherzelle "warning" auf
- ;255 gesetzt, danach kehrt die Routine zum
- ;aufrufenden Programm zurück
- cmp ah,3 ;Funktionsnummer: Schreiben
- je stop
- cmp ah,5 ;Funktionsnr.: Formatieren
- je stop
- cmp ah,11 ;Funktionsnr.: Erweitertes Schreiben
- je stop
- jmp dword ptr cs:[int_13]
- stop:
- cmp ch,0 ;Zugriff auf Spur 0,
- ;CH enthält Teil der Zylindernummer
- jne no_warning
- cmp dh,0
- jne no_warning
- mov ah,cl
- and ah,11000000B
- ;Bit 8&7 sind Bit 10&9 der Zylindernummer
- cmp ah,0
- jne no_warning
- mov cs:warning,255
- no_warning:
- xor ah,ah
- cmp dl,80H ;Zugriff auf Festplatte ?
- jae ih_hd
- add cs:f_count,ax
- ;Nein, daher Anzahl der zu schreibenden
- ;Sektoren zu "f_cound" addieren
- jmp ih_e
- ih_hd:
- add cs:h_count,ax ;ansonsten Wert zu "h_count" addieren
- ih_e:
- ;Carry Flag löschen, um dem Programm ein
- ;fehlerfreies Schreiben vorzugaukeln
- push bp
- mov bp,sp
- mov ax,ss:[bp+6] ;Flags nach AX bringen
- and ax,11111110B ;Carry löschen
- mov ss:[bp+6],ax ; und zurückschreiben
- pop bp
- iret ;Zurück zum aufrufenden Programm
-
- INT13_HANDLING ENDP
-
-
- SWITCH PROC NEAR
- ;Diese Prozedur übernimmt das Umschalten von
- ;"on"
- ;1: Prozedur wird aufgerufen, und "on"
- ; erhält den Wert 0. Kommentar "Protect
- ; aktiviert" wird ausgegeben
- ; Interuptvektoren werden über die Prozedur
- ; "save_int_vektoren" gesichert.
- ; "on" wird auf 255 gesetzt, die Funtionen
- ; "int13_handling" und "int21_handling"
- ; werden damit 'scharf' gemacht
- ;2: Prozedur wird aufgerufen und "on"
- ; erhält den Wert 255. Kommentar "Protect
- ; deaktiviert" wird ausgegeben
- ; Prozedur "daten_ausgabe" wird aufgerufen
- ; "on" wird auf 0 gesetzt
- push ax
- push bx
- push cx
- push dx
- push si
- push di
- push ds
- push es ;Attribut lesen
- mov ah,8
- mov bh,seite
- int 10H
- mov cs:attribut,ah
- cmp cs:on,0
- je einschalten
- call daten_ausgabe
- mov cs:on,0
- ;Löschen der restlichen Parameter
- mov cs:f_count,0
- mov cs:h_count,0
- mov cs:[pointer],offset puffer
- mov cs:warning,0
- jmp switch_ende
- einschalten:
- call save_int_vektoren
- mov ax,cs
- mov ds,ax
- mov si,offset aktivieren
- call text_ausgabe
- mov cs:on,255
- switch_ende:
- call write_cr
- pop es
- pop ds
- pop di
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
- ret
- ret
-
- SWITCH ENDP
-
-
- SAVE_FCB PROC NEAR
- ;Input: DS:DX muß auf den normalen oder
- ;erweiterten File Control Block zeigen
- ;Die Prozedur hat die Aufgabe, den
- ;Dateinamen aus dem FCB in den Puffer
- ;"puffer" zu übertragen.
- push ax
- push bx
- push cx
- push dx
- push si
- push di
- push ds
- push es
- mov si,dx
- mov al,ds:[si] ;erstes Byte des FCB
- cmp al,255 ;Handelt es sich um einen erweiterten FCB ?
- jne fcb_weiter
- add dx,8 ;JA, daher DX auf Dateiname setzen
- fcb_weiter:
- mov ax,cs
- mov es,ax
- mov di,cs:pointer ;ES:DI -> "puffer"
- mov cx,8 ;CX = Länge des Dateinamen, ohne Extension
- mov si,dx
- cld
- cmp di,offset puffer_ende-15
- ;Ist im Puffer noch genügend Platz für den
- ;Dateinamen ?
- jbe fcb_loop_name
- mov di,offset puffer
- ;Pointer wieder auf den Pufferanfang setzen
- fcb_loop_name:
- rep movsb ;Dateinamen übertragen
- mov al,'.'
- stosb ;Punkt nach Dateinamen setzen, Ziel ist die
- ;Trennung von Namen und Extention
- mov cx,3
- rep movsb ;Extention übertragen
- mov al,0 ;Endekennung schreiben
- stosb
- mov cs:pointer,di ;neues Pufferende sichern
- pop es
- pop ds
- pop di
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
- ret
-
- SAVE_FCB ENDP
-
-
- SAVE_HANDLE PROC NEAR
- ;Input DS:DX zeigt auf den Dateinamen
- push ax
- push bx
- push cx
- push dx
- push si
- push di
- push ds
- push es
- cld
- mov ax,cs
- mov es,ax
- mov si,dx
- mov di,cs:pointer
- cmp di,offset puffer_ende-15
- ;noch genügend Platz im Puffer ?
- jbe loop_open_name
- mov di,offset puffer
- ;Nein, daher Pointer wieder auf Pufferanfang
- loop_open_name: ;Übertragen des Dateinamens
- lodsb
- stosb
- cmp al,0 ;Solange, bis Endekennung "0"
- ;übertragen wurde
- jne loop_open_name
- mov cs:pointer,di ;Neues Pufferende sichern
- pop es
- pop ds
- pop di
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
- ret
-
- SAVE_HANDLE ENDP
-
-
- INT21_HANDLING PROC NEAR
- ;Diese Prozedur übernimmt die Kontrolle des
- ;Interrupt 21H, falls die Speicherzelle "on"
- ;den Wert 255 enthält. Sie stellt fest, ob
- ;eine Datei über eine FCB- oder eine Handle-
- ;Funktion geöffnet werden soll. Falls dies
- ;der Fall ist, wird über die entsprechende
- ;Funktion ("save_fcb","save_handle") der
- ;Name der zu öffnenden Datei gesichert.
- ;Danach wird die Interrupt 21H-Routine
- ;von DOS angesprungen. Es wird keinerlei
- ;Schreibzugriff unterbunden, das erledigt
- ;die Prozedur "int13_handling".
- cmp cs:on,255
- je start
- jmp cs:dword ptr[int21]
- start:
- cmp ah,15 ;Funktionsnr.: öffne Datei über FCB
- je fcb
- cmp ah,61 ;Funktionsnr.: öffne Datei über Handle
- je handle
- jmp cs:dword ptr[int21]
- fcb:
- call save_fcb
- jmp cs:dword ptr[int21]
- handle:
- call save_handle
- jmp cs:dword ptr[int21]
- ;Entsprechende DOS Funktion aufrufen
- INT21_HANDLING ENDP
-
-
- INT9_HANDLING PROC NEAR
- ;übernimmt die Kontrolle der Hotkeys
- push ax
- cmp cs:aktiv,255 ;Wird die Routine gerade abgearbeitet ?
- je int9_ende
- in al,60H ;Nummer der gedrückten Taste vom Keyboard-
- ;Controller holen
- cmp al,keystroke
- ;handelt es sich dabei um die oben defi-
- ;nierte Taste, wird kontrolliert, ob auch
- ;<Ctrl> und <Alt> gedrückt sind.
- ;Ist dies der Fall wird die Routine
- ;"switch" aufgerufen
- je status_byte
- pop ax
- jmp cs:dword ptr[int9]
- status_byte:
- push ds
- mov ax,40H
- mov ds,ax
- mov al,ds:[17H]
- and al,1100B
- pop ds
- cmp al,12
- je int9_start
- int9_ende:
- pop ax
- jmp cs:dword ptr[int9]
- int9_start: ;Tastenkombination wurde gedrückt
- mov cs:aktiv,255
- ;Verhindern, daß Routine zweimal aufgerufen
- ;wird, Tastatur wieder freigeben
- in al,61H
- mov ah,al
- or al,80H
- out 61H,al
- mov al,ah
- out 61H,al ;Interruptsperre löschen
- mov al,20H
- out 20H,al
- sti
- call switch
- cli
- pop ax
- mov cs:aktiv,0 ;Betreten der Routine ist wieder erlaubt
- iret
- INT9_HANDLING ENDP
-
- HP: ;Meldung ausgeben, daß Programm geladen wurde
- mov ax,cs
- mov ds,ax
- mov dx,offset geladen
- mov ah,9
- int 21H ;Intvektor 13H sichern & ändern
- mov ax,3513H
- int 21H
- mov word ptr[int_13],bx
- mov word ptr[int_13+2],es
- mov dx,offset int13_handling
- mov ax,2513H
- int 21H ;Interrupt 9 sichern und ändern
- mov ax,3509H
- int 21H
- mov word ptr [int9],bx
- mov word ptr [int9+2],es
- mov dx,offset int9_handling
- mov ax,2509H
- int 21H ;Interrupt 21H sichern und ändern
- mov ax,3521H
- int 21H
- mov word ptr [int21],bx
- mov word ptr [int21+2],es
- mov dx,offset int21_handling
- mov ax,2521H
- int 21H ;Programm resident beenden
- mov dx,offset hp
- mov cl,4
- shr dx,cl
- add dx,21H
- mov ax,3100H
- int 21H
-
- CODE ENDS
- END