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

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

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

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

Добавлен: 16.02.2019

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

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

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
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 источникприем-
ник
 

Exchang

— обменять 

Обмен регистров  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