;             Prog10.asm - программа к Главе № 10

 

; (С) Авторские права на файлы-приложения принадлежат автору книги

; "Ассемблер? Это просто! Учимся программировать под MS-DOS"

; Автор: Калашников Олег Александрович (e-mail: Assembler@Kalashnikoff.ru)

;     http://www.Kalashnikoff.ru

 

; --- Ассемблирование (получение *.com файла) ---

;При использовании MASM 6.11 - 6.13:

;ML.EXE prog10.asm /AT

 

;При использовании TASM:

;TASM.EXE prog10.asm

;TLINK.EXE prog10.obj /t/x

 

 

CSEG segment

assume cs:CSEG, ds:CSEG, es:CSEG, ss:CSEG

org 100h

 

Start:

 

;Переходим на метку инициализации. Нам нужно будет перехватить прерывание 21h,

;а также оставить программу резидентной в памяти

      jmp Init

 

 

 

;           ==== Обработчик 21h-ого прерывания ====

 

;Ниже идет, собственно, обработчик 21h прерывания (он будет резидентный).

;После того, как программа выйдет, процедура Int_21h_proc останется в памяти

;и будет контролировать функцию 09 прерывания 21h.

 

Int_21h_proc proc

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

      je Ok_09                ;Если так, то на метку Ok_09

 

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

;Всё. На метку Ok_09 программа уже не вернется.

      jmp dword ptr cs:[Int_21h_vect]

 

 

Ok_09:

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

      push dx

 

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

      pop ds

 

;Выводим нашу строку (My_string) вместо той, которую должна вывести

;программа, вызвавшая 21h-ое прерывание

      mov dx,offset My_string

      pushf             ;Так надо! Позже рассмотрим

      call dword ptr cs:[Int_21h_vect]

 

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

      pop ds

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

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

;сообщение. Но на самом деле это не так!

 

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

Int_21h_vect dd ?

 

;Строка, которая будет выводится

My_string db 'Моя строка!$'

 

int_21h_proc endp

 

;           ==== Конец обработчика 21h-ого прерывания ====

 

 

 

 

;Со следующей метки нашей программы уже не будет в памяти

;(это нерезидентная часть). Она затрется сразу после выхода (после

;вызова прерывания 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   ;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

Hosted by uCoz