Все выпуски  

RFpro.ru: Ассемблер? Это просто! Учимся программировать


РАССЫЛКИ ПОРТАЛА RFPRO.RU

Лучшие эксперты в разделе

Kdsfofwe21
Статус: 1-й класс
Рейтинг: 83
∙ повысить рейтинг »
cain52
Статус: 1-й класс
Рейтинг: 4
∙ повысить рейтинг »
Коцюрбенко Алексей aka Жерар
Статус: Мастер-Эксперт
Рейтинг: 0
∙ повысить рейтинг »

∙ Assembler

Номер выпуска:1705
Дата выхода:02.09.2018, 11:15
Администратор рассылки:Лысков Игорь Витальевич (Старший модератор)
Подписчиков / экспертов:61 / 21
Вопросов / ответов:1 / 1

Консультация # 193492: Здравствуйте, уважаемые эксперты! Я изучаю ассембер по книге Олега Калашникова. При написании резидентного обработчика прерывания 21h у меня возник ряд вопросов: 1) Как понять, находится ли в памяти резидентная программа, и как удалить её из памяти? 2) Обработчик, судя по описанию в книге, должен "перехватывать" прерывание 21h у выз...

Консультация # 193492:

Здравствуйте, уважаемые эксперты! Я изучаю ассембер по книге Олега Калашникова. При написании резидентного обработчика прерывания 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.
Прошу помочь с решением проблемы. Спасибо.

Код обработчика:
Код (Assembler) :: выделить код
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

Дата отправки: 28.08.2018, 10:58
Вопрос задал: Роман (Посетитель)
Всего ответов: 1
Страница онлайн-консультации »


Консультирует Лысков Игорь Витальевич (Старший модератор):

Здравствуйте, Роман! Ну давайте разбираться...
3) Начнем с третьего вопроса.

© Цитата:
Что означают эти строки?
Прерывания с некоторым отличием представляют собой дальние процедуры. Об отличии скажем позже.
Т.е. их адрес - длинный и состоит из пары сегмент:смещение.
Поэтому, когда получаем адрес старого обработчика в ES:BX при помощи функции 35h, то должны сохранить именно так:
Код (Assembler) :: выделить код
mov word ptr Int_21h_vect,bx
mov word ptr Int_21h_vect+2,es
Этот адрес необходимо обязательно сохранить. Мы же меняем только одну функцию.
Все остальные функции будут отрабатываться старым обработчиком. Если адрес не сохраним, то старый обработчик потеряется навсегда.

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

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


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

1) Первый вопрос. Данная программа ничего не делает ни для проверки наличия в памяти, ни для удаления
А делается это следующим образом:
Проверка наличия: добавляется некоторая уникальная функция, которая возвращает некоторый уникальный ответ.
По которому и проверяется факт наличия в памяти.
Удаление: первое: восстанавливаем перехваченные вектора прерывания. Тут ес ть опасность: если после нашего резидента будет запущен
еще какой-то, который тоже "сядет" на наши вектора, то восстановление старых векторов не так уж и просто...
Но, это уже давно не актуально... ДОС давно ушла в историю, так что можно особо не переживать.
И второе, что надо сделать: освободить память, занимаемую резидентом.

Консультировал: Лысков Игорь Витальевич (Старший модератор)
Дата отправки: 28.08.2018, 11:58

5
нет комментария
-----
Дата оценки: 28.08.2018, 13:08

Рейтинг ответа:

НЕ одобряю +1 одобряю!


Оценить выпуск | Задать вопрос экспертам

главная страница  |  стать участником  |  получить консультацию
техническая поддержка

Дорогой читатель!
Команда портала RFPRO.RU благодарит Вас за то, что Вы пользуетесь нашими услугами. Вы только что прочли очередной выпуск рассылки. Мы старались. Пожалуйста, оцените его. Если совет помог Вам, если Вам понравился ответ, Вы можете поблагодарить автора - для этого в каждом ответе есть специальные ссылки. Вы можете оставить отзыв о работе портале. Нам очень важно знать Ваше мнение. Вы можете поближе познакомиться с жизнью портала, посетив наш форум, почитав журнал, который издают наши эксперты. Если у Вас есть желание помочь людям, поделиться своими знаниями, Вы можете зарегистрироваться экспертом. Заходите - у нас интересно!
МЫ РАБОТАЕМ ДЛЯ ВАС!


В избранное