Int_21h_proc endp

Popf

Pop ds

Pushf

Mov dx,offset My_string

Pop ds

Push dx

Je Ok_09

Int_21h_proc proc

pushf ;сохраним в стеке регистр флагов

cmp ah,9 ;проверим: это функция 09h?

popf ;восстановим регистр флагов

;Если нет, прейдем на оригинальный обработчик прерывания 21h. Все, на метку Ok_09 программа уже не вернется

jmp dword ptr cs:[Int_21h_vect]

Ok_09:

push ds ;Сохраним регистры

push cs ;Адрес троки должен быть DS:DX

; Выводим нашу строку (My_string) вместо той, которую должна была вывести программа, вызывающая 21h-е прерывание

call dword ptr cs:[Int_21h_vect] ;Вывели нашу строку вместо той, которую надо было

pop dx ;восстановим использованные регистры

iret ;продолжим работу (выйдем из прерывания)

; Программа, выводящая строку, считает, что на экран было выведено её сообщение. Но на самом деле это не так!

Int_21h_vect dd? ;переменная для хранения оригинального адреса обработчика 21h

My_string db 'My string!$'

;Со следующей метки нашей программы уже не будет в памяти (это нерезидентная часть). Она затрется сразу после выхода (после вызова прерывания 27h).

Init:

;Установим наш обработчик (Int_21h_proc) (адрес нашего обработчика) на прерывание 21h. Это позволяет сделать функция 25h прерывания 21h. Но прежде нужно запомнить оригинальный адрес этого прерывания. Для этого используется функция 35h прерывания 21h:

mov ah,35h ;AH содержит номер функции

mov al,21h ;AL указывает номер прерывания, адрес (или вектор) которого нужно получить

int 21h ;тепрь в ES:BX адрес (вектор) прерывания 21h (ES - сегмент, BX - смещение)

mov word ptr Int_21h_vect,bx

mov word ptr Int_21h_vect+2,es

;итак, адрес сохранили. Теперь перехватываем прерывание:

mov ax,2521h

mov dx,offset Int_21h_proc; DS:DX должны указывать на наш обработчик (т.е. Int_21h_proc)

int 21h

;Теперь, если какая-либо программа вызовет 21h, то вначале компьютер попадет на наш обработчик (Int_21h_proc). Далее следует корректно завершить программу, оставив ее резидентной в памяти (чтобы никто не затер наш обработчик. Иначе компьютер просто зависнет!)

mov dx,offset Init

int 27h

; Прерывание 27h выходит в DOS (как 20h), при этом оставив нашу программу резидентной. DX должен указывать на последний байт, оставшийся в памяти (это как раз метка Init). То есть в памяти остаётся от 0000h до адреса, по которому находится метка Init.

CSEG ends

end Start

_______________

Как проверить работу программы? В данном случае нам понадобится отладчик, который способен заходить внутрь прерываний. Например, AFD и пр., но не как не CodeView. То, что нам сейчас нужно! Если нет AFD, то его можно взять на сайте: https://www.Kalashnikoff.ru

Затем создайте простейшую программу, которая будет выводить на экран некоторую строку путем вызова 09 функции 21h прерывания. Например, так:

Программа N 02

CSEG segment

assume CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG

org 100h

Begin:

mov ah,9

mov dx,offset String

int 21h

int 20h

String db 'My string.$'

end Begin

CSEG ends

Запускаем сперва Программу N 01. После того, как она вернется в DOS (в Norton Commander, DOS Navigator, Far и пр. оболочки), запускайте Программу N 02. Что вы увидите?

Теперь запустите Программу N 02 в отладчике. Заходите смело "внутрь" 21h-ого прерывание. Что вы видите теперь?



Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: