15.11.2018, 10:26 [+3 UTC]
в нашей команде: 3 106 чел. | участники онлайн: 6 (рекорд: 16)

:: РЕГИСТРАЦИЯ

:: задать вопрос

:: все разделы

:: правила

:: новости

:: участники

:: доска почёта

:: форум

:: блоги

:: поиск

:: статистика

:: наш журнал

:: наши встречи

:: наша галерея

:: отзывы о нас

:: поддержка

:: руководство

Версия системы:
7.55 (06.11.2018)

Общие новости:
24.09.2018, 16:49

Форум:
08.11.2018, 13:36

Последний вопрос:
15.11.2018, 02:05

Последний ответ:
15.11.2018, 08:07

Последняя рассылка:
15.11.2018, 09:15

Писем в очереди:
0

Мы в соцсетях:

Наша кнопка:

RFpro.ru - здесь вам помогут!

Отзывы о нас:
18.11.2016, 00:47 »
АнтонНР
Спасибо большое! Наконец разобрался.. [вопрос № 190036, ответ № 274258]
09.10.2009, 20:50 »
leonid59
Большое спасибо, Japa! Замечательная штука! [вопрос № 173112, ответ № 255224]
19.01.2012, 13:59 »
lamed
Большое спасибо. С уважением. [вопрос № 185209, ответ № 269634]

РАЗДЕЛ • Assembler

Создание программ на языке Assembler.

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

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

Зенченко Константин Николаевич
Статус: Модератор
Рейтинг: 638
Лысков Игорь Витальевич
Статус: Старший модератор
Рейтинг: 131
Evgen aka Chuma
Статус: 6-й класс
Рейтинг: 15

Перейти к консультации №:
 

Консультация онлайн # 193492
Раздел: • Assembler
Автор вопроса: Роман (Посетитель)
Отправлена: 28.08.2018, 10:58
Поступило ответов: 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.
Прошу помочь с решением проблемы. Спасибо.

Код обработчика:
Код (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, 11:21

Состояние: Консультация закрыта

Ответ # 276657 от Лысков Игорь Витальевич (Старший модератор)

Здравствуйте, Роман! Ну давайте разбираться...
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

[подробно]

Сообщение
модераторам

Отправлять сообщения
модераторам могут
только участники портала.
ВОЙТИ НА ПОРТАЛ »
регистрация »

Мини-форум консультации № 193492

Зенченко Константин Николаевич
Модератор

ID: 31795

# 1

= общий = | 28.08.2018, 12:15 | цитировать цитировать  | профиль профиль  |  отправить письмо в личную почту пейджер
Роман:

© Цитата: Роман
3) Что означают эти строки?

Код (Assembler) :: выделить код
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 - см. выше


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

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


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

Этот вопрос Вы будете следующих темах изучать.
1.1: перед установкой своего обработчика делается контрольный запрос, и если получаете правильный ответ, то обработчик уже в памяти. К примеру:
Код (Assembler) :: выделить код
mov	ax,09AAh
int	21h
cmp	ax,0AA09;
jz	inMemory

функцию выбрал просто так, в реальности, там может быть совершенно другие числа.
1.2: Просто перезапустите командную строку, система загрузит всё, но у же без вашего обработчика. Но в реальном DOS'e просто так это не сработает, это может погубить ОСь.

=====
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.
smile

• Отредактировал: Зенченко Константин Николаевич (Модератор)
• Дата редактирования: 28.08.2018, 12:28

 

Возможность оставлять сообщения в мини-форумах консультаций доступна только после входа в систему.
Воспользуйтесь кнопкой входа вверху страницы, если Вы зарегистрированы или пройдите простую процедуру регистрации на Портале.

Яндекс Rambler's Top100

главная страница | поддержка | задать вопрос

Время генерирования страницы: 0.15838 сек.

© 2001-2018, Портал RFPRO.RU, Россия
Калашников О.А.  |  Гладенюк А.Г.
Версия системы: 7.55 от 06.11.2018