Консультация № 193492
28.08.2018, 10:58
0.00 руб.
28.08.2018, 11:21
0 2 1
Здравствуйте, уважаемые эксперты! Я изучаю ассембер по книге Олега Калашникова. При написании резидентного обработчика прерывания 21h у меня возник ряд вопросов:
1) Как понять, находится ли в памяти резидентная программа, и как удалить её из памяти?
2) Обработчик, судя по описанию в книге, должен "перехватывать" прерывание 21h у вызывающих его программ и подставлять адрес (регистры ds:dx) своей строки, заставляя выводить свою и только свою строку. Почему этого не происходит?
3) Что означают эти строки?
Код:

...
jmp dword ptr cs:[Int_21h_vect]
...
call dword ptr cs:[Int_21h_vect]
...
mov word ptr Int_21h_vect,bx
mov word ptr Int_21h_vect+2,es
...

Моя ОС - Windows 7, ассемблер - MASM 6.11.
Прошу помочь с решением проблемы. Спасибо.

Код обработчика:
[code lang=asm h=200] CSEG segment
assume cs:CSEG, ds:CSEG, es:CSEG, ss:CSEG
org 100h
Start:
;Переходим на метку инициализации. Нам нужно будет перехватить прерывание 21h,
;а также оставить программу резидентной в памяти
jmp Init

;Ниже идет, собственно, код обработчика прерывания 21h (он будет резидентным).
;После того как программа выйдет, процедура Int_21h_proc останется в памяти
;и будет контролировать функцию 09h прерывания 21h.
;Мы выделим код обработчика полужирным шрифтом.
Int_21h_proc proc
cmp ah, 9 ;Проверим: это функция 09h?
je 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 'My string!$'
int_21h_proc endp

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

;al указывает номер прерывания, адрес (или вектор) которого нужно получить
mov al,21h
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
[/code]

Обсуждение

давно
Посетитель
7438
7205
28.08.2018, 11:58
общий
это ответ
Здравствуйте, Роман! Ну давайте разбираться...
3) Начнем с третьего вопроса.
Что означают эти строки?
Прерывания с некоторым отличием представляют собой дальние процедуры. Об отличии скажем позже.
Т.е. их адрес - длинный и состоит из пары сегмент:смещение.
Поэтому, когда получаем адрес старого обработчика в ES:BX при помощи функции 35h, то должны сохранить именно так:
[code lang=asm]mov word ptr Int_21h_vect,bx
mov word ptr Int_21h_vect+2,es[/code]Этот адрес необходимо обязательно сохранить. Мы же меняем только одну функцию.
Все остальные функции будут отрабатываться старым обработчиком. Если адрес не сохраним, то старый обработчик потеряется навсегда.

Тут надо сказать следующее. Обработчики прерывания обычно строятся, как цепочка обработчиков. Вплоть до самого первого.
Самый верхний проверяет, надо ли ему отработать. Надо - отрабатывает. Нет - отдает предыдущему.
Это и делается при помощи длинного перехода по адресу:[code lang=asm]jmp dword ptr cs:[Int_21h_vect][/code]Обратите внимание, указывается cs:, т.к. во время работы прерывания актуальным является только содержимое cs, поэтому его и используем для адресации.

Бывает, надо вызвать старый обработчик, чтобы что-то сделать. При этом остаемся в своем коде.
Тогда старый обработчик можно вызвать при помощи команды call. При этом надо учитывать отличие длинного вызова
обычной дальней процедуры и программного вызова вектора прерывания.
Когда вызывается прерывание, как аппаратное, так и программное, в стек сначала заносится флаги.
Только потом длинный адрес точки возврата!
Именно поэтому, чтобы вызвать старый обработчик прерывания при помощи call делаем так:[code lang=asm]
pushf
call dword ptr cs:[Int_21h_vect]
[/code]

2) Второй вопрос. Чтобы увидеть перехваченное сообщение, надо в одной сессии cmd (например, из одного батника)
вызвать сначала наш резидент, затем какую-нибудь программу, выводящую сообщение при помощи функции 9
Рекомендую изменить выводимую строку на английскую, чтобы не видеть абракадабру...
Дело в том, что в коде строка в кодировке CP-1251, а отображается в досовской CP-866
Как вариант, перекодировать файл в CP-866. Проще всего, да данном этапе, писать на английском.

1) Первый вопрос. Данная программа ничего не делает ни для проверки наличия в памяти, ни для удаления
А делается это следующим образом:
Проверка наличия: добавляется некоторая уникальная функция, которая возвращает некоторый уникальный ответ.
По которому и проверяется факт наличия в памяти.
Удаление: первое: восстанавливаем перехваченные вектора прерывания. Тут есть опасность: если после нашего резидента будет запущен
еще какой-то, который тоже "сядет" на наши вектора, то восстановление старых векторов не так уж и просто...
Но, это уже давно не актуально... ДОС давно ушла в историю, так что можно особо не переживать.
И второе, что надо сделать: освободить память, занимаемую резидентом.
5
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Старший Модератор
31795
6196
28.08.2018, 12:15
общий
28.08.2018, 12:28
Адресаты:
Цитата: Роман
3) Что означают эти строки?

[code lang=asm]jmp dword ptr cs:[Int_21h_vect] - сделать длинный переход на старый обработчик, по адресу, который хранится в переменной Int_21h_vect
...
call dword ptr cs:[Int_21h_vect] - сделать длинный вызов старого обработчика, по адресу, который хранится в переменной Int_21h_vect
...
mov word ptr Int_21h_vect,bx -тут в переменную записывается сегмент : смещение старого обработчика
mov word ptr Int_21h_vect+2,es - см. выше [/code]

Цитата: Роман
2) Обработчик, судя по описанию в книге, должен "перехватывать" прерывание 21h у вызывающих его программ и подставлять адрес (регистры ds:dx) своей строки, заставляя выводить свою и только свою строку. Почему этого не происходит?

Все происходит, prog10 - наш обработчик, test10 - контрольная программа.


Цитата: Роман
1) Как понять, находится ли в памяти резидентная программа, и как удалить её из памяти?

Этот вопрос Вы будете следующих темах изучать.
1.1: перед установкой своего обработчика делается контрольный запрос, и если получаете правильный ответ, то обработчик уже в памяти. К примеру:
[code lang=asm]mov ax,09AAh
int 21h
cmp ax,0AA09;
jz inMemory[/code]
функцию выбрал просто так, в реальности, там может быть совершенно другие числа.
1.2: Просто перезапустите командную строку, система загрузит всё, но у же без вашего обработчика. Но в реальном DOS'e просто так это не сработает, это может погубить ОСь.
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

Форма ответа