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

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

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

114 

Таблица 11.3. Функция 

05h

прерывания 

10h

:  

установить текущую видеостраницу 

Вход 

Выход 

ah = 05h 

al 

= номер видеостраницы 

Ничего 

 
Попробуйте поэкспериментировать с данными прерываниями. 
Несколько дополнений: 

 

как  правило,  все  страницы  дисплея  (кроме  нулевой)  чистые,  если  некоторая 
программа не заносила в них данные; 

 

при  переключении  режима  дисплея  с  помощью  функции 

00h

  прерывания 

10h

очищается не только нулевая, но и все видеостраницы; 

 

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

*   *   * 

На этом данная глава заканчивается. В главе 12 мы начнем рассматривать пер-

вую резидентную программу. 

background image

Глава 12 

Повторная загрузка резидента 
 

12.1. Резидент 

В данной главе рассмотрим один из вариантов применения резидента. Но сперва 

изучим файлы-приложения resid12.asm и test12.asm. 

Загрузите файл resid12.com в память, а затем запустите test12.com. 
Resid12.com  оставляет  в  памяти  процедуру,  которая  выводит  на  экран  строку 

ASCIZ (ASCII-строка, заканчивающаяся символом 0). Причем процедура 

Int_10h_proc

перехватывает  прерывание 

10h

 (это прерывание BIOS (ПЗУ)). Нечто похожее рас-

сматривалось в главе 10. В данном случае мы добавляем еще одну функцию (

88h

)  

к  прерыванию 

10h

,  которой,  естественно,  может  воспользоваться  любая  другая 

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

88h

, нам нужно вызвать прерывание 

10h

, а в регистры загрузить не-

обходимые числа (данные). А именно: 

ah = 88h — номер нашей функции; 
ds:si = адрес строки, которую нужно вывести на экран (ds — сегмент, si — смещение). 

Обратите еще раз внимание, что мы в 

ds

 (сегмент) ничего не загружаем, только 

в 

si

 (смещение). Заметьте, что при старте любого COM-файла сегментные регист-

ры 

cs

, 

ds

, 

es

, 

ss

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

программа. Сегмент может быть любым. Все зависит от того, сколько резидентных 
программ уже загружено в память, каков объем ядра ОС и пр. 

12.2. Проверка на повторную  
загрузку резидента 

Первое, что делает программа, — переходит на метку инициализации. При ини-

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

Перво-наперво проверим, загружен ли уже наш резидент в память или нет. Как 

это  сделать?  Так  как  мы  перехватили  прерывание,  то  можем  из него сделать "от-
клик". Вызываем прерывание 

10h

, заносим в регистр 

ax

 "магическое число" 

8899h

. 

Можно любое другое, главное — чтобы не конфликтовало с какой-нибудь функцией 

background image

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

116 

данного прерывания. Понятно, что в 

ah

 заносится 

88h

, а в 

al

 — 

99h

. Функции 

88h

  

у  прерывания 

10h

  не  существует  (не  дошли  пока  разработчики  до  этого  числа).  

Это можно с уверенностью предположить на 99,9%. Так как номер прерывания 

10h

еще не задействован, то произойдет немедленный выход из  прерывания 

10h

 (регист-

ры, как правило, не меняются), что легко проверить в отладчике. Следовательно, вы-
звав прерывание 

10h

 с числом 

8899h

 в 

ax

 и получив также ответ 

8899h

 в том же 

ax

, 

мы уверены, что наш резидент еще не загружен. На рис. 12.1 изображено окно про-
граммы в состоянии после вызова прерывания 

10h

 и получения отклика от резидента. 

Рис. 12.1. Проверка на присутствие резидента в памяти: отзыв получен! 

Теперь о нашем обработчике прерывания 

10h

. Если файл resid12.com уже нахо-

дится в памяти, перехватив прерывание 

10h

, то, процедура обработки прежде всего 

должна проверить, вызывают ли ее с числом 

8899h

 в 

ax

. Если так, то нужно будет 

послать какой-нибудь ответ. Какой? В нашем примере мы меняем местами содер-
жимое  регистров 

ah

  и 

al

  и  немедленно  выходим  из  прерывания.  Проще  говоря, 

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

9988h

. Здесь важно запомнить, что если нашего резидента нет в памяти, то 

вернется 

8899h

 в 

ax

, причем BIOS регистры не изменит, т. к. такой функции просто 

не существует. Если же в 

ax

 вернулось 

9988h

, то, значит, наша программа уже за-

гружена.  То есть  процедура 

Int_10h_proc

  поменяла  местами  регистры  (а  что  еще 

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

ah 

и

 al

 (листинг 12.1). 

Листинг 12.1. Часть обработчика прерывания 10h программы resid12.com 

... 
Int_10h_proc proc 

background image

Глава 12. Повторная загрузка резидента 

117 

pushf              ;Сохраним флаги в стеке, т. к. они поменяются... 
 
cmp ax,8899h       ;Проверим на повторную загрузку в память  
jne Next_test      ;Если не проверка, то смотрим дальше... 
 
;Меняем местами ah и al — признак того, что мы в памяти, 
;что-то вроде ответного сигнала. 
xchg ah,al 
popf               ;Выровняем стек 
iret               ;Выйдем из прерывания (вернемся в нашу программу) 
;ax при возврате будет равен 9988h!!! 
... 

Познакомимся с новым оператором 

xchg

 (табл. 12.1 и листинг 12.2). 

Таблица 12.1. Оператор 

xchg

Команда 

Перевод 

Назначение 

Процессор 

xchg источник, прием-
ник
 

Exchange 

— обменять 

Обмен регистров  8086 

Листинг 12.2. Использование оператора xchg 

... 
mov ax,10h 
mov bx,15h 
xchg ax,bx         ;Теперь ax=15h, bx=10h 
... 

Как вам уже известно, регистр 

cs

 (от англ. code segemt — сегмент кода) всегда 

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

ip

  (от  англ. 

instruction  pointer —  указатель  инструкций) —  смещение.  Допустим,  процедура 
обработки прерывания 

10h

  расположена  по  адресу 

0010:0400h

, а наша программа 

загрузилась в сегмент 

1234h

. Тогда получаем: 

;cs:ip = 1234:0100h 
... 
[1234:0100h] mov ax,8899h 
;После выполнения данной инструкции cs:ip=1234:0103h 
 
[1234:0103h] int 10h 
;Теперь cs:ip = сегменту/смещению адреса (вектора) прерывания 10h, 
;т. е. 0010:0400h 
 
[1234:0105h] mov bx,10 
;Работаем дальше после того, как прерывание завершило свою работу... 
... 

background image

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

118 

Выход  из  прерывания  осуществляется  с  помощью команды 

iret

, в отличие от 

выхода  из ближней процедуры — 

ret

. Это видно из приведенного выше примера 

обработчика прерывания 

10h

. 

Очень  просто  все  выглядит  на  практике.  Попробуйте  запустить  наш  резидент 

(resid12.com)  в  отладчике.  Внимательно  следите  за  состоянием  пары  регистров 

cs:ip

.  Вы  заметите,  что  они  постоянно  меняются.  Обратите  особое  внимание  на 

значения, которые они принимают при вызове прерываний (для этого нужно зайти 
внутрь прерываний; в AFD — <F1>, в CodeView — <F8>) (рис. 12.2). 

Рис. 12.2. Резидент посылает отклик 

12.3. Команды работы со строками 

Рассмотрим  некоторые  новые  инструкции,  встречающиеся  в  нашем  резиденте: 

stos

, 

lods

, 

rep

. Это очень мощные и быстрые команды ассемблера. Они предназна-

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

Инструкция 

lods

 загружает в регистр 

ax

/

al

 число, которое находится по адресу, 

указанному в регистрах 

ds:si

, при этом 

si

 автоматически увеличивается на едини-

цу или на двойку. 

Почему мы написали 

ax

/

al

? Дело в том, что эта инструкция имеет две разновид-

ности: 

lodsb

  и 

lodsw

. 

Lodsb

  (

b

 —  byte,  байт)  загружает  в 

al

,  а 

lodsw

  (

w

 —  word, 

слово) — в 

ax

 (листинг 12.3, рис. 12.3 и 12.4). 

Листинг 12.3. Использование операторов lodsb и lodsw 

... 
mov si,offset String ;si указывает на начало String, т. е. на '1' 
 
lodsb 

Источник: https://files.student-it.ru/previewfile/2839