Файл: О.А.Калашников. Ассемблер Это Просто. Учимся программировать.pdf
Добавлен: 16.02.2019
Просмотров: 29245
Скачиваний: 1689
Часть III. Файловая оболочка, вирус, резидент
234
Данная команда устанавливает флаг переноса, а следующая — сбрасывает его.
Таблица 23.7. Команда
clc
Команда Перевод
Назначение
Процессор
clc
Clear carry flag
— сбросить флаг
переноса
Сброс флага переноса
8086
Для чего нужны данные команды? Где они обычно применяются?
В наших примерах мы ими в основном пользуемся перед выходом из процеду-
ры. Например, возьмем часть такого кода (листинг 23.4).
Листинг 23.4. Использование команд управления флагом переноса
...
call Find_symbol
jc Not_found
...
В данном примере вызывается процедура поиска какого-то символа в памяти.
В конце этой процедуры мы устанавливаем флаг переноса, если символ найден,
и сбрасываем, если нет. Это проще и быстрее, чем если бы мы использовали для
этой цели какой-нибудь регистр (листинг 23.5).
Листинг 23.5. Использование регистра
...
call Find_symbol
cmp ax,1
je Not_found
...
Если
ax=1
, то символ не найден. Как видите, удобнее пользоваться флагом пе-
реноса. Однако следует помнить, что некоторые команды могут менять этот флаг.
Поэтому нужно придерживаться следующих правил:
между установкой/сбросом флага переноса и его проверкой не следует вызывать
никакие прерывания или пользоваться командами типа
add
,
sub
,
mul
и пр.;
после установки/сброса флага его нужно проверять как можно быстрее.
Рассмотрим еще две команды управления флагами направления (табл. 23.8, 23.9).
Таблица 23.8. Команда
std
Команда
Перевод
Назначение
Процессор
std
Set destination flag
— устано-
вить флаг направления
Установка флага направ-
ления
8086
Глава 23. Область PSP и DTA. Системные переменные (окружение DOS)
235
Таблица 23.9. Команда
cld
Команда
Перевод
Назначение
Процессор
cld
Clear destination flag
— сбро-
сить флаг направления
Сброс флага направления
8086
Какие действия выполняют эти команды? Для чего служит флаг направления?
Данный флаг служит при указании направления для инструкций работы со
строками (
lods
,
stos
,
movs
и пр.). До сих пор мы перемещали байты только вперед,
например, от 0 до 4000, а не от 4000 до 0 (вспомните вирус, который перемещал
свой код в область видеопамяти). Вот этот флаг отвечает за то, каким образом про-
изводить перемещение, поиск и пр. Иначе говоря, в каком направлении это делать
(отсюда и название флага — флаг направления). Как правило, применяют направ-
ление вперед, и, следовательно, флаг обычно сброшен. Но бывают случаи, когда
необходимо установить флаг, тем самым производя работу "назад". В нашем рези-
денте мы сбрасываем флаг направления для того, чтобы команды
lods
,
stos
и пр.,
используемые в нем, работали "вперед".
Как уже упоминалось, некоторые прерывания (в том числе и
09
) могут быть вы-
званы в любой момент работы какой-нибудь программы (в тот момент, когда поль-
зователь нажмет клавишу). Установлен ли этот флаг или сброшен — нам не из-
вестно. Проще всего сбросить его самим в начале резидентной части, что мы,
собственно, и делаем:
cld ;Направление — вперед!
Обращаем ваше внимание еще раз: как правило, этот флаг сброшен, но лучше не
рисковать и самим сбросить или установить его. Практиковаться с ним мы будем
позже, при написании оболочки.
23.3.3. Изменение параметров резидента "на лету"
Допустим, наш резидент загружен в память и уже успешно работает (т. е.
в LOG-файле фиксирует нажатые пользователем клавиши). А что, если мы хотим
поменять имя LOG-файла в процессе работы резидента? Для этой цели будем ис-
пользовать процедуру обработки прерывания
10h
. Впрочем, не только для этой це-
ли. Она нам необходима еще и для того, чтобы проверять резидент на повторную
загрузку (листинг 23.6).
Листинг 23.6. Процедура обработки прерывания 10h
...
(1) Int_10h_proc proc
(2) cmp ax,0FAAFh ;Проверяем на повторную загрузку?
(3) jne Next_step
(4) xchg ah,al
Часть III. Файловая оболочка, вирус, резидент
236
(5) iret
(6) Next_step:
(7) cmp ax,0FBAFh ;Получаем текущий адрес LOG-файла?
(8) jne Run_int
(9) push cs ;Заносим в es сегмент LOG-файла
(10) pop es
(11) mov di,offset File_name ;Заносим в di смещение LOG-файла
(12) iret
(13) Run_int:
(14) jmp dword ptr cs:[0F8h]
(15) Int_10h_proc endp
...
В строках (2)—(5) мы проверяем, вызывается ли прерывание
10h
с числом
0FAAFh
. Если вызывается, то меняем местами
ah
/
al
, что сигнализирует нашему ре-
зиденту, загружаемому повторно, о том, что он уже в памяти. Подобные вещи рас-
сматривались в предыдущих главах, поэтому подробно останавливаться на этом не
будем.
Нас сейчас больше интересуют строки (6)—(12). Если прерывание
10h
вызыва-
ется с числом
0FBAFh
в
ax
, то это значит, что наш резидент, загружаемый повторно,
просит получить сегмент и смещение имени текущего LOG-файла. Для чего? Как
уже упоминалось, резидент может менять в процессе работы имя своего LOG-
файла. Для этого необходимо запустить его повторно, с указанием имени в ко-
мандной строке. Например, так:
Resid23.com c:\newfile.txt
Резидент, при попытке повторно загрузиться в память, прежде всего проверит
параметры в командной строке. Но как повторно загружаемому резиденту узнать, в
каком сегменте находится его резидентная копия? Для этого мы воспользуемся
созданной нами функцией
0FBAFh
прерывания
10h
, которое резидент перехватыва-
ет. В результате, прерывание
10h
(а точнее, наша процедура обработки прерывания
10h
) вернет в
es
сегмент, а в
di
— смещение имени LOG-файла (листинг 23.7).
Листинг 23.7. Получение сегмента
...
mov ax,0FBAFh ;Получим сегмент и смещение имени LOG-файла
int 10h ;Теперь es — сегмент, а di — смещение LOG-файла в памяти.
...
А теперь посмотрите первые команды нашего обработчика прерывания
10h
, ко-
торый, в случае получения в
ax
числа
0FBAFh
, загружает в
es:di
сегмент и смеще-
ние LOG-файла и немедленно выходит из этого прерывания. Обратите внимание,
Глава 23. Область PSP и DTA. Системные переменные (окружение DOS)
237
что при инициализации резидента мы сперва проверяем, загружен ли он в память
или нет, и если загружен, то получаем адрес LOG-файла. Теперь осталось только
перенести параметры командной строки в полученные сегмент и смещение!
В листинге 23.8 приведен фрагмент нашего обработчика прерывания
10h
(
Int_10h_proc
).
Листинг 23.8. Обработчик прерывания 10h
...
cmp ax,0FBAFh ;Получаем текущий адрес LOG-файла
jne Run_int
push cs ;Заносим в es сегмент LOG-файла
pop es
mov di,offset File_name
;Заносим в di смещение LOG-файла
iret
...
23.4. Задание для закрепления сведений
из данной главы
Обязательно разберитесь с прилагаемым файлом, т. к. информация, приведенная
в нем, очень важна для понимания работы резидентных программ. Описаний
в файле-приложении более чем достаточно.
Глава 24
Резидентный антивирус
В
Н И МА Н И Е
!
Наш антивирус корректно обезвреживает только вирус, код которого приведен в гла-
ве 20. Если вы добавили или убрали хоть один байт в коде вируса, то антивирус не
сможет корректно вылечить зараженный файл!
24.1. Регистры микропроцессоров
80386/80486. Хранение чисел в памяти
Прежде чем приступить к рассмотрению работы нашего антивируса, ознако-
мимся вкратце с некоторыми регистрами процессоров 80386/80486. В табл. 24.1
приведен пример на основе аккумулятора.
Таблица 24.1. Регистры процессоров 386+
Количество разрядов
Регистр
32
eax
16
ax
ax
8
ah
al
ah
al
Как видно из таблицы,
eax
— 32-разрядный регистр. Он может хранить число
65 535 65 535 (т. е. 65 535 в квадрате). До сих пор мы пользовались только 16-
разрядными регистрами (
ax
,
bx
,
cx
и пр.). С данной главы начнем использовать
и 32-разрядные. По большому счету, у нас нет острой необходимости пользоваться
ими. Единственная цель — показать вам возможности 32-разрядных регистров,
а также попробовать использовать их на практике.
В приведенной выше таблице мы рассмотрели только регистр
eax
. По аналогии
с ним, можно добавить и регистры
ebx
,
ecx
,
edx
,
edi
,
esi
,
ebp
.
При использовании 32-разрядных регистров необходимо в ассемблерный лис-
тинг включить одну из следующих директив:
.386
.486