Файл: О.А.Калашников. Ассемблер Это Просто. Учимся программировать.pdf

ВУЗ: Не указан

Категория: Книга

Дисциплина: Программирование

Добавлен: 16.02.2019

Просмотров: 29253

Скачиваний: 1689

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
background image

 

 

 

Глава 27 

 

Удаление резидента из памяти 

 

27.1. Обзор последнего резидента 

27.1.1. Перехват прерывания 21h 

В  этой  главе  приведен  последний  пример  резидентной  программы  под  DOS,  

в которой мы рассмотрим принцип удаления резидента из памяти. 

Казалось бы: неужели так сложно удалить резидентную программу из памяти?  

С одной стороны, ничего сложного в этом нет, с другой — существуют некоторые 
сложности: 

 

во-первых,  не  всегда  есть  возможность  удалить  из  памяти  резидентную  про-
грамму; 

 

во-вторых,  необходима  некоторая  подготовка  и  проверка  определенных  пара-
метров перед удалением резидента; 

 

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

файлы-приложения. 

Рекомендую  вам  внимательно  ознакомиться  с  приведенной  в  данной  главе  ин-

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

Итак, представим, что никакая резидентная программа не перехватывает преры-

вание 

21h

. То есть его адрес (вектор) указывает непосредственно на ядро DOS, как 

это показано в табл. 27.1.  

Таблица 27.1. Вектор 

21h

 

указывает на ядро DOS 

Адрес 

Что перехватывает 

Куда отправляет после обработки 

1234:0000h 

Ядро DOS 

Никуда (возврат из прерывания) 


background image

Глава 27. Удаление резидента из памяти 

265 

Как вам уже известно, MS-DOS имеет свои обработчики некоторых прерываний 

(например, 

20h

,

  21h

 и пр.). Использовать прерывания DOS без загрузки самой ОС 

невозможно.  При  попытке  это  сделать,  компьютер  просто  зависнет.  Например,  
в  программе  загрузочного  сектора  диска  (которая  загружается  первая,  т. е.  до  за-
грузки  DOS)  нельзя  пользоваться  функциями  DOS,  т. к.  они  еще  недоступны.  Но 
программе  ничего  не  мешает  использовать  прерывания  BIOS,  т. к.  они  находятся  
в области ПЗУ и могут вызываться из любой ОС и в любое время. 

Теперь  внимательно  посмотрите  на  табл. 27.1.  Допустим,  что  процедура  обра-

ботки 

21h

-го прерывания MS-DOS загрузилась вместе с ОС по адресу 

1234:0000h

Никакая иная программа данное прерывание еще не перехватила. Таким образом, 
выполняя  команду 

int  21h

,  процессор  передаст  управление  напрямую  процедуре 

обработки 

21h

-го прерывания MS-DOS, т. е. на адрес 

1234:0000h

. Данная процеду-

ра,  отработав  и,  например,  выведя  на  экран  строку,  передаст  управление  нашей 
программе. Это простейшая схема. 

Теперь допустим, что пользователь загружает некий резидент с именем progA.com, 

который перехватывает прерывание 

21h

. В результате мы получим именно то, что 

изображено в табл. 27.2.  

Таблица 27.2. Наша программа перехватила прерывание 

21h

 

Адрес 

Что перехватывает 

Куда отправляет после обработки 

1234:0000h 

Ядро DOS 

Никуда (возврат из прерывания) 

2345:0000h 

progA.com 

1234:0000h 

(ядро DOS)  

 
Из  табл. 27.2  видно,  что  программа  progA.com  перехватила  прерывание 

21h

Прерывание как бы стало фильтром на пути к оригинальному обработчику (обра-
ботчику MS-DOS (

1234:0000h

)). 

После вызова прерывания 

int 21h

 первым получит управление обработчик пре-

рывания 

21h

  программы  progA.com.  Процедура  обработки  прерывания 

21h

  про-

граммы progA.com (в нашем случае она находится по адресу 

2345:0000h

), получив 

управление,  сделает  все  необходимое,  а  затем  передаст  управление  ядру  DOS  на 
адрес 

1234:0000h

. Ядро DOS выполнит определенные действия, а затем выйдет из 

прерывания командой 

iret

, передав управление программе, которая вызывала пре-

рывание 

21h

Отметим  важный  момент.  Допустим,  пользователь загружает обычную нерези-

дентную  программу,  которая  работает  с  прерыванием 

21h

.  Вызов  данного  преры-

вания этой программы (

int 21h

) находится по адресу 

3456:0100h

. Таким образом, 

при выполнении команды 

int 21h

 в стек будет занесен адрес 

3456:0102h

, т. е. ад-

рес  следующей  команды,  а  процессор  получит  адрес  прерывания 

21h

  из  таблицы 

векторов прерываний и передаст управление по этому адресу, т. е. на 

2345:0000h

программе  progA.com.  В  свою  очередь,  progA.com  отработает  (может,  например, 
изменить значения каких-либо регистров, как наш резидент) и передаст управление 
ядру DOS. 


background image

 

Часть III. Файловая оболочка, вирус, резидент 

266 

Вот  только  вопрос:  а  куда  именно  передать  управление,  на  какой  адрес?  Для 

этой цели наши резиденты сперва получают текущий адрес обработчика того или 
иного  прерывания,  а  затем,  когда  обработчик  отработал,  передают  управление  на 
сохраненный адрес, т. е. дальше по цепочке.  

Программа progA.com поступит точно так же. Перед установкой обработчика на 

свою процедуру она получает адрес прежнего (оригинального) обработчика (в дан-
ном случае — ядра DOS, т. к. никакие резидентные программы не загружены), вы-
звав функцию 

35h

 прерывания 

21h

 либо прочитав адрес напрямую из таблицы век-

торов прерываний. 

ProgA.com отработает и передаст управление по предварительно сохраненному 

адресу на предыдущую процедуру обработки прерывания 

21h

Управление получит ядро DOS. Выполнит свои действия и вернется. Спрашива-

ется: куда вернется и как? Естественно, с помощью команды 

iret

, которая вытас-

кивает из стека предварительно занесенный в него адрес. Какой? Адрес progA.com 
или адрес программы, которая была запущена пользователем и инициировала вы-
зов 

int 21h

Все зависит от того, каким образом программа progA.com, выполнив необходи-

мые  команды  в  обработчике 

21h

,  передала  управление  ядру  DOS.  Как уже не раз 

отмечалось  в  предыдущих  главах,  существуют  два  способа  передачи  управления 
прежнему (оригинальному) обработчику:  

  jmp dword ptr cs:[Int_21h_vect] 
  pushf 

call dword ptr cs:[int_21h_vect] 

В первом случае команда 

iret

 ядра DOS передаст управление непосредственно 

программе пользователя, которая вызывала прерывание 

21h

 командой 

int 21h

. Это 

и понятно: инструкция 

jmp

 в стек ничего не кладет. Получается, что перед выпол-

нением команды 

jmp

 в стеке находится адрес возврата на программу пользователя 

(если,  конечно,  progA.com  не  нарушает  работу  стека).  Команда 

iret

  обработчика 

21h

 ядра DOS вытащит из стека адрес возврата на программу пользователя, которая 

будет работать дальше, даже не "подозревая" о том, что некая progA.com "сидит"  
в памяти и контролирует вызов прерывания 

21h

Во  втором  случае  после  выполнения 

iret

  управление  получит  progA.com.  Здесь 

также все понятно: команда 

call

 заносит в стек адрес возврата. Команда 

iret

 и вы-

тащит его из стека! Зачем мы перед 

call

 используем 

pushf

 — вам уже известно... 

Итак,  после  завершения  работы  оригинального  обработчика 

21h

  (ядра  DOS) 

программа  progA.com  снова  получила  управление.  Что  теперь  будет  делать 
progA.com?  Она  может  посмотреть,  что  вернула  подпрограмма  обработки 

21h

  

и выполнить определенные действия, если необходимо. После этого командой 

iret

 

продолжить  работу  пользовательской  программы.  Иными  словами, 

iret

  вытащит 

из стека адрес возврата на программу, которая и вызывала изначально прерывание 
командой 

int 21h

Для  чего  нужно  программе  progA.com  перехватывать 

int  21h

?  Да  по  разным 

причинам.  Например,  чтобы  контролировать  открытие/закрытие  файла,  чтение/ 
запись,  да  и  все,  что  выполняет  прерывание 

21h

! Некоторые варианты мы с вами 

рассматривали в предыдущих главах. 


background image

Глава 27. Удаление резидента из памяти 

267 

Итак, progA.com "повисла" на прерывании 

21h

, предварительно сохранив в сво-

ем  теле  адрес  оригинального  обработчика,  т. е.  обработчика  ядра  DOS,  который  
в  нашем  примере  расположен  по  адресу 

1234:0000h

.  Теперь  при  выполнении  ко-

манды 

int 21h

 управление получает сперва progA.com, а затем уже ядро DOS. 

Теперь мы загружаем еще одну программу progB.com, которая также перехватит 

прерывание 

21h

. В табл. 27.3 показано, что у нас получится. 

Таблица 27.3. Загружена вторая резидентная программа 

Адрес обработчика 

Кто перехватывает 

Куда отправляет после обработки 

1234:0000h 

Ядро DOS 

Никуда (возврат из прерывания) 

2345:0000h 

progA.com 

1234:0000h (

ядро DOS) 

3456:0000h 

progB.com 

2345:0000h (progA.com) 

 
Теперь некая загруженная пользователем программа (например, NC.EXE) вызы-

вает прерывание командой 

int 21h

. Что происходит? 

Инструкция 

int 21h

 кладет в стек адрес возврата, достает из таблицы векторов 

прерываний  адрес  прерывания 

21h

  (

3456:0000h

)  и передает ему управление. Про-

грамма progB.com выполняет то, что программист ей "приказал", и передает управ-
ление  на  адрес  прежнего  (оригинального)  обработчика  прерывания 

21h

,  который 

ею  был  предварительно  сохранен  (на 

2345:0000h

,  т. е.  progA.com).  ProgA.com,  

в  свою  очередь,  выполняет  необходимые  действия  и  так  далее,  по  цепочке,  пока 
управление  в  итоге  не  получит  ядро  DOS.  Таким  образом,  на  одно  прерывание 
можно "насаживать" неограниченное число резидентов. 

27.1.2. Как удалять загруженный резидент  
из памяти? 

Загрузим  в  память  Resid27.com —  написанную  нами  программу  для  практики. 

Состояние памяти отображено в табл. 27.4. 

Таблица 27.4. Состояние памяти после загрузки нашего резидента 

Адрес 

Что перехватывает 

Куда отправляет после обработки 

1234:0000h 

Ядро DOS 

Никуда (возврат из прерывания) 

2345:0000h 

Resid27.com 

1234:0000h 

(ядро DOS) 

 
Сразу возникает несколько вопросов. 

 

Как узнать, по какому адресу в памяти загрузилась программа Resid27.com? 

 

Как узнать адрес обработчика прерывания ядра DOS? 

 

Как удалить программу из памяти? 
Все ответы достаточно просты. 


background image

 

Часть III. Файловая оболочка, вирус, резидент 

268 

Помните, как мы передавали "позывной" нашему резиденту? Если резидент от-

кликался, это означало, что он уже загружен. 

Таким же способом можно получить сегмент и смещение процедуры обработки 

прерывания 

21h

. Сперва проверим на повторную загрузку (

mov ax,9988h

/

int 21h

), 

а затем отправим в ответ какое-нибудь число (в нашем примере — 

9999h

). 

Наш  резидент,  получив 

9999h

  в 

ax

,  моментально  выходит  из  процедуры,  пере- 

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

21h

  (в  данном  случае —  ядра  DOS).  Этого  будет  вполне  достаточно 

для удаления резидента. 

Затем,  убедившись,  что  резидент  загружен,  и  получив  необходимую  информа-

цию для удаления, можно приступать к освобождению памяти. 

Делаем буквально следующее: 

1.  Запрещаем все прерывания командой 

cli

2.  Восстанавливаем адрес оригинального обработчика (т. е. ядра DOS). 
3.  Освобождаем память функцией 

49h

4.  Разрешаем прерывания командой 

sti

Все! Резидент удален из памяти! 

27.1.3. Случаи, когда резидент  
удалить невозможно 

Представим такую ситуацию. Вслед за Resid27.com загружается еще одна рези-

дентная программа, которая также перехватывает прерывание 

21h

 (в нашем приме-

ре это будет progA.com). Тогда получаем то, что показано в табл. 27.5. 

Таблица 27.5. Загружена сторонняя программа после нашего резидента 

Адрес 

Что перехватывает 

Куда отправляет после обработки 

1234:0000h 

Ядро DOS 

Никуда (возврат из прерывания) 

2345:0000h 

Resid27.com 

1234:0000h (

ядро DOS) 

3456:0000h 

progA.com 

2345:0000h (Resid27.com) 

 
Возникает вопрос: что произойдет, если мы удалим Resid27.com из памяти? 
Процессор, выполнив команду 

int 21h

 любой программы, передаст управление на 

адрес 

3456:0000h

, т. е. программе progA.com. Последняя, отработав, передаст управле-

ние на адрес 

2345:0000h

. И что же будет находиться по этому адресу, если мы удалили 

Resid27.com? Обычный "мусор". Компьютер, скорее всего, просто зависнет. 

Возникает еще один вопрос: а можно ли удалить Resid27.com, если после него 

загрузился  еще  один  резидент,  который  также  перехватывает  прерывание 

21h

?  

К сожалению, в таком случае наш резидент уже удалить не получится. Чтобы это 
сделать, нам нужно вначале удалить progA.com, а затем уже удалять Resid27.com.