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

Protected Mode - укрытие для вируса


Персональные компьютеры год от года становятся все сложнее и слож-

нее, используют все более высокие аппаратные и программные техноло-

гии. Компьютерные вирусы тоже не отстают и пытаются приспособиться

к новым условиям обитания. Так, вирусы научились заражать загрузоч-

ные сектора дисков, файлы для операционных систем DOS, Windows,

Windows 95, OS/2, Linux и даже документы Word, Excel, и MS-Office 97.

Скрывая свое присутствие в системе, они стали невидимками, или

стелс-вирусами. Они научились быть полиморфными для того, чтобы

их распознавание стало еще более трудной задачей для разработчиков

антивирусных средств. С появлением процессоров i386 вирусы стали

использовать в своем коде 32-разрядные инструкции. В настоящее вре-

мя полиморфные вирусы используют 32-разрядные расшифровывающие



команды в своем декрипторе.

Одним словом, вирусы хотят выжить и победить. Для этого они исполь-

зуют все новые возможности, как программные, так и аппаратные. Но

защищенный режим работы, появившийся вместе с процессором i286,

до недавнего времени вирусам никак не удавалось "приручить". Вернее,

были "пробы пера", но реального решения этой задачи они не дали.

Загрузочный вирус PMBS, первым пытавшийся освоить защищенный ре-

жим (1994 г.), не мог ужиться ни с одной программой или драйвером

(EMM386, Windows, OS/2,...), которые также использовали в своей рабо-

те защищенный режим. Вирусы Evolution.2761 и Evolution.2770 (тоже

1994 г.) использовали только часть мощного защищенного режима и толь-

ко в то время, когда процессор работал в реальном режиме. Данные виру-

сы заменяли реальную таблицу векторов прерываний на собственную.

Но вот, похоже, проблема близка к разрешению: в России в "диком"

виде обнаружен файловый вирус PM.Wanderer, использующий защи-

щенный режим. Причем он более или менее корректно и стабильно вза-

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

щими защищенный режим.

PM.Wanderer является резидентным полиморфным вирусом, использу-



ющим защищенный режим процессоров i386-Pentium. Для установки

своей резидентной копии в память и переключения в защищенный ре-

жим процессора (Protected Mode) вирусом используется документиро-

ванный интерфейс VCPI (Virtual Control Program Interface) драйвера

расширенной памяти EMS (EMM386).

При старте инфицированной программы вирусный полиморфный дек-

риптор расшифровывает основное тело вируса и передает ему управле-

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

адресах, копирует в него собственный код и передает ему управление.

Затем он восстанавливает код инфицированного файла в программном

сегменте (для ЕХЕ-файлов также производит настройку адресов пере-

мещаемых элементов) и приступает к непосредственному внедрению

в память своей резидентной копии. .

В первую очередь вирус пытается вьыснить, установлен ли в системе драй-

вер EMS. Если этот драйвер не установлен или вирусная резидентная ко-

пия уже находится в памяти, вирус отдает управление программе-вирусо-

носителю, заканчивая тем самым свою "жизнедеятельность" в системе.

Если же "условия среды обитания" благоприятствуют, вирус выполня-

ет ряд подготовительных операций для выделения памяти под свое тело

и производит переключение процессора в защищенный режим работы

с наивысшим уровнем привилегий - режим супервизора.

В защищенном режиме вирус устанавливает две аппаратные контрольные

точки на адреса входа в обработчик прерывания INT 21h (функции DOS)

и перехода на процедуру перезагрузки компьютера. Кроме того, вирус

корректирует дескрипторную таблицу прерываний таким образом, чтобы

на прерывания INT 1 (особый случай отладки) и INT 9 (клавиатура) ус-

тановить собственные дескрипторы обработчиков прерываний.

После этих приготовлений вирус копирует свой код в страницу памяти,

полученную им еще до входа в защищенный режим, и производит пере-

ключение процессора обратно в виртуальный режим работы. Затем он

начинает процедуру освобождения ранее выделенной памяти DOS



в верхних адресах и возвращает управление инфицированной программе.

С этого момента инфицированная программа начинает свою основную

работу, а в защищенном режиме оказываются установленными вирус-

ные обработчики - ловушки на INT 1 и прерывания от клавиатуры на

INT 9. С их помощью вирус контролирует, во-первых, все вызовы фун-

кций DOS, во-вторых, все нажатия клавиш на клавиатуре, и, в-третьих,

попытки мягкой перезагрузки компьютера. В свою очередь, такой конт-

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

интересующих его событий при работе программы, так и постоянно

проверять состояние двух своих контрольных точек и при необходимо-

сти восстанавливать их.

В частности, если вирус обнаруживает, что данный вызов исходит

от его "собрата", он просто возвращает некоторое условное значение,

играющее роль отзыва "я - свой". Таким образом, вирус, пытавшийся

выяснить наличие своей копии в памяти, будет информирован о том,

что память уже инфицирована.

Если вирус обнаруживает попытку получения адреса прерывания INT 6

(обычно такой вызов существует во всех программах, написанных на

языках высокого уровня, например С, Pascal), то он 1"Ъ1тается найти

в адресном пространстве некоторую последовательность байт, очевидно

принадлежащих программе ADinf, но какой-то старой версии. Кстати,

по информации разработчика ADinf Дмитрия Мостового, за последний

год в версиях ADinf не содержится такая последовательность. Если дан-

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

модифицирует найденный код, чтобы управление не попадало на вызов

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

на диске или в файлах изменения.

Если же вирус обнаруживает запрос на запуск программы или открытие

файла (только на чтение), то понимает, что наступило время "большой

охоты". Вирус копирует свой код в старшие адреса виртуального про-

цесса DOS-машины, переключает процессор в виртуальный режим



и отдает управление своему коду (процедуре заражения).

В виртуальном режиме вирус проверяет последние две буквы расшире-

ния имени файла (ОМ или ХЕ), создает свою полиморфную копию

и заражает файлы размером более 4095 байт. Файлы, содержащие

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

тая их уже инфицированными. Корректировку атрибутов файлов вирус

не производит, поэтому все файлы, помеченные как "только для чте-

ния", заражены не будут. Также вирус не заражает программы, имя ко-

торых состоит из 7 букв. Имена данных программ выяснить не удалось,

так как вирус не определяет их имена явно, а подсчитывает CRC име-

ни. Вирус не берет на себя обработку критических ошибок, поэтому при

попытке записи на защищенный диск в процессе заражения появится

стандартный вопрос DOS (...Retry, Ignore, Fail, Abort).

При заражении файлов вирус использует прямой вызов ядра обработчи-

ка DOS INT 21h. Адрес этого ядра он выясняет при трассировке INT 21h

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

СОМ- или в середину ЕХЕ-файла (сразу же после заголовка). Ориги-

нальный программный код запоминается в конце файла. Реальный

рабочий код вируса составляет 3684 байт, но на практике инфицирован-

ные файлы имеют приращение длины более 3940 байт. В теле вируса

содержится текст "WANDERER".

Обнаружить резидентную копию данного вируса, находящегося в нуле-

вом кольце защищенного режима процессора, обычными способами не-

возможно. Для этого необходимо переключаться в защищенный режим

с наивысшими привилегиями и производить его поиск. Но попытаться

обнаружить признаки вируса в системе можно и обычными способами.

После обнаружения вируса рекомендуется, как и всегда в таких случа-

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

мо стерильных условиях. Правда, данный вирус не является Stealth-ви-

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

Теперь немного о результатах тестирования.


При заражении несколь-

ких тысяч файлов- жертв вирус проявил себя как "жилец" - все зара-

женные файлы оказались работоспособными. Здесь надо сделать по-

правку - файлы могут оказаться неработоспособными в том случае,

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

PM.Wanderer при заражении файлов не корректирует значения стар-

товых SS:SP в ЕХЕ-заголовке. Как уже отмечалось выше, он сохраняет

способность к воспроизводству только в том случае, если в системе уста-

новлен драйвер EMS (EMM386). При установленном драйвере EMM386

с ключом NOEMS вирус перезагружает компьютер. Перезагрузка также

возможна, если в системе используется драйвер QEMM386.

Самое интересное, что если в системе находился резидентный вирус,

а потом произошла загрузка Windows 3.1 или Windows 95, то вирус не

сможет размножаться в данных операционных средах, но при выходе

в DOS он опять получает управление и может "трудиться, не покладая

рук". Если же вирус будет запущен в DOS-сессии Windows, то из-за

отсутствия интерфейса VCPI вирус не сможет переключиться в защи-

щенный режим. При отсутствии VCPI под OS/2 вирус также нежизнес-

пособен.

Возможно, в недалеком будущем компьютерный вирус сможет полнос-

тью заменить своим кодом программу-супервизора и сам будет поддер-

живать интерфейсы DPMI, EMS/VCPI, XMS, INT 15h. Кто знает.

Приведенная ниже программа позволяет программисту перевести про-

цессор в защищенный режим. В этом режиме вирус может, например,

расшифровать некоторые данные.

Данная программа делает следующее:

- создает таблицы GDT и LDT, используя текущие значения

CS.DS.SS

- запрещает все прерывания, открывает линию А20

для доступа к RAM>1 Мбайт

- переводит процессор в защищенный режим

- в первый символ строки qw заносит символ L

- выходит в реальный режим

- разрешает прерывания, закрывает А20 -т

- выводит на экран строку qw ("Light General")

- выход в DOS

.286

.model tiny

.code

org 100h

Определения для защищенного режима работы программы



;Структура дескриптора

desc_struc STRUC

limit dw 0

baseJ dw 0

base_h db 0

access db 0

rsrv dw 0

desc_struc ENDS

ACC_PRESENT equ WOOOOOOb

ACC_CSEG equ OOO-MOOOb

ACC_DSEG equ 000-IOOOOb

ACC_EXPDOWN equ 000001 OOb

ACC_CONFORM equ 000001 OOb

ACC_DATAWR equ 0000001 Ob

DATA_ACC=ACC_PRESENT or ACC_DSEG or ACC_DATAWR

; 1001001 Ob

CODE_ACC=ACC_PRESENT or ACC.CSEG or ACC_CONFORM

; 10011100b

STACK_ACC= ACC_PRESENT or ACC_DSEG or ACC_DATAWR or

ACC.EXPDOWN; 1001011 Ob

;Размеры сегментов (реальные размеры на единицу больше)

CSEG SIZE=65535

DSEG_SIZE=65535

STACK_SIZE=65535

[Смещения используемых дескрипторов

CS_DESCR=(gdt_cs-gdt_0)

DS_DESCR=(gdt_ds-gdt_0)

SS_DESCR=(gdt_ss-gdt_0)

;Константы значений портов ?

CMOS_PORT equ 70h

STATUS_PORT equ 64h

SHUTDOWN equ OFEh

A20_PORT equ OD1h

A20_ON equ ODFh

A20_OFF equ ODDh

INT_MASK_PORT equ 21 h

KBD_PORT_A equ 60h

start:

.Инициализируем необходимые данные для перехода

;в защищенный режим

call init_protected_mode

[Переходим в защищенный режим

call set_protected_mode

;Теперь компьютер работает в защищенном режиме!

;Так как таблица прерываний реального режима не может быть

использована в защищенном, прерывания запрещены!

;Именно тут можно вставить инструкции, нужные вирусу

.Возвращаемся в реальный режим

call set_real_mode

[Печатаем сообщение "Light General"

mov ah,09h

lea dx.qw

int 21 h

;Выходим в DOS

mov ax,4COOh

int 21 h

[Макрокоманда для установки адреса для дескриптора

;в глобальной таблице дескрипторов GDT.

;На входе регистры DLAX должны содержать

.абсолютный адрес сегмента

setgdtentry MACRO

mov [desc_struc.base_l][bx],ax

mov [desc_struc.base_h][bx],dl

ENDM

•<

; Процедура инициализации необходимых данных

.для перехода в защищенный режим

init_protected_mode PROC

вычисляем абсолютный адрес для сегмента данных

;в соответствии со значением регистра DS

mov ax.ds

mov dl.ah

shr dl,4

shi ax,4

;Устанавливаем адрес сегмента данных

;в глобальной таблице дескрипторов



mov bx, offset gdt_ds

setgdtentry

; Вычисляем абсолютный адрес для сегмента GDT: прибавляем

;к уже вычисленному абсолютному адресу сегмента данных

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

add ax,offset gdtr

adc dl.0

Останавливаем адрес сегмента GDT

;в глобальной таблице дескрипторов

mov bx.offset gdt_gdt

setgdtentry

;Вычисляем абсолютный адрес для сегмента кода

;в соответствии со значением регистра CS

mov ax,cs

mov dl.ah

shr dl,4

shi ax,4

.Устанавливаем адрес сегмента кода

;в глобальной таблице дескрипторов

mov bx, offset gdt_cs

setgdtentry

[Вычисляем абсолютный адрес для сегмента стека

;в соответствии со значением регистра SS

mov ax.ss

mov dl.ah

shr dl,4

shi ax,4

Останавливаем адрес сегмента стека

;в глобальной таблице дескрипторов

mov bx,offset gdt_ss

setgdtentry

Перехватываем рестарт. Так как процессор i286 (а эта программа

[рассчитана именно на такой процессор) не имеет возможности

;возврата в реальный режим из защищенного, возврат в реальный

режим будем производить следующим образом: перехватим рестарт,

.сгенерируем CPU Reset, после которого получим управление, когда

Процессор будет находится уже в реальном режиме. На процессоре

;i386 возврат в реальный режим происходит

[значительно проще и "естественнее".

push ds

mov ax,40h

mov ds,ax

mov word ptr ds:[0067h], offset shutdown_return

mov word ptr ds:[0069h],cs

pop ds

[Запрещаем маскируемые прерывания

cli

in al,INT_MASK_PORT

or al.OFFh

out INT_MASK_PORT,al

[Запрещаем немаскируемые прерывания. Данная последовательность

;команд не запрещает "незапрещаемые" прерывания в процессоре

[(этого сделать по определению нельзя), а "не пускает" сигнал

[немаскируемого прерывания к процессору

mov al,8Fh

out CMOS_PORT,al

jmp $+2

mov al,5

out CMOS_PORT+1,al

ret

init_protected_mode ENDP

[Подпрограмма, переводящая процессор в защищенный режим

set_protected_mode PROC

.Открываем адресную линию А20 для доступа свыше 1Мбайт.

;При закрытой линии адресное пространство



["зацикливается" в пределах 1Мбайт

call enable_a20

. Сохраняем значение регистра SS для реального режима

mov real_ss,ss

[Переводим компилятор Turbo Assembler в улучшенный режим.

[IDEAL - это не команда и не оператор, это директива, влияющая

[только на интерпретацию дальнейших строк листинга

ideal

р286

[Загружаем регистр глобальной таблицы дескрипторов GDTR

Igdt [QWORD gdt_gdt] ;db OFh,01h,16h dw offset gdt_gdt

[Переводим процессор в защищенный режим

mov ax,0001h

Imsw ax ;db OFh,01h,FOh

[Переводим компилятор Turbo Assembler назад в режим MASM

masm

.286

[Производим длинный переход для того,

.чтобы очистить внутреннюю очередь

.команд процессора

jmp far flush

db OEAh

dw offset flush

dw CS_DESCR

flush:

Останавливаем в регистр SS селектор сегмента стека

mov ax,SS_DESCR

mov ss.ax

;Устанавливаем в регистр DS селектор сегмента данных

mov ax,DS_DESCR

mov ds.ax

.Записываем в строку qw символ "L" и выходим из подпрограммы

mov byte ptr ds: [off set qw+2],"L"

ret

set_protected_mode ENDP

Подпрограмма, возвращающая процессор в реальный режим

set_real_mode PROC

[Сохраняем значение регистра SP для реального режима

mov real_sp,sp

.Выполняем CPU Reset (рестарт процессора)

mov al,SHUT_DOWN

out STATUS_PORT,al

;Ждем, пока процессор перезапустится

wait_reset:

hit

jmp wait_reset

;C этого места программа выполняется после перезапуска процессора

shutdown_return:

;Устанавливаем регистр DS в соответствии с регистром CS

push cs

pop ds

восстанавливаем указатели на стек

;по ранее сохраненным значениям

mov ss,real_ss

mov sp,real_sp

[Закрываем адресную линию А20

call disable_a20

.Разрешаем немаскируемые прерывания

mov ax.OOOdh

out CMOS_PORT,al

[Разрешаем маскируемые прерывания

in al,INT-MASK_PORT

and al,0

out INT_MASK_PORT,al

sti

ret

set_real_mode EN DP

[Процедура, открывающая адресную линию А20. После открытия

[адресной линии программам будет доступна память свыше 1Мбайт

enable_a20 PROC

mov al,A20_PORT



out STATUS_PORT,al

mov al,A20_ON

out KBD_PORT_A.al

ret

enable_a20 ENDP

[Процедура, закрывающая адресную линию А20. После закрытия

[адресной линии программам будет недоступна память свыше 1Мбайт.

[Адресное пространство будет "зацикленным" в пределах 1Мбайт

disable_a20 PROC

mov al.A20_PORT

out STATUS_PORT,al

mov al,A20_OFF

out KBD_PORT_A,al

ret

disable_a20 ENDP

[Здесь сохраняется адрес стека

real_sp dw ?

real_ss dw ?

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

[Символ "?" заменяется на "L" в защищенном режиме

qw db 13,10,"?ight General",13,10,"$"

;Глобальная таблица дескрипторов. Нулевой дескриптор

обязательно должен быть "пустым"

GDT_BEG=$

gdtr label WORD

gdt_0 desc_struc <0,0,0,0,0>

gdt_gdt desc_struc <GDT_SIZE-1„,DATA_ACC,0>

gdt_ds desc_struc <DSEG_SIZE-1,„DATA_ACC,0>

gdt_cs desc_struc <CSEG_SIZE-1„,CODE_ACC,0>

gdt_ss desc_struc <STACK_SIZE-1,„DATA_ACC,0>

GDT_SIZE=($-GDT_BEG)

END start


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