KnigaRead.com/

Игорь Гульев - Создаем вирус и антивирус

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Игорь Гульев, "Создаем вирус и антивирус" бесплатно, без регистрации.
Перейти на страницу:

Возможно, в недалеком будущем компьютерный вирус сможет полностью заменить своим кодом программу-супервизора и сам будет поддерживать интерфейсы DPMI, EMS/VCPI, XMS, INT 15h. Кто знает.

Приведенная ниже программа позволяет программисту перевести процессор в защищенный режим. В этом режиме вирус может, например, расшифровать некоторые данные.

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

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

; CS,DS,SS

; – запрещает все прерывания, открывает линию A20

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

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

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

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

; – разрешает прерывания, закрывает A20

; – выводит на экран строку qw (”Light General”)

; – выход в DOS

.286

.model tiny

.code

org 100h

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

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

desc_struc STRUC

limit dw 0

base_l dw 0

base_h db 0

access db 0

rsrv dw 0

desc_struc ENDS

ACC_PRESENT equ 10000000b

ACC_CSEG equ 00011000b

ACC_DSEG equ 00010000b

ACC_EXPDOWN equ 00000100b

ACC_CONFORM equ 00000100b

ACC_DATAWR equ 00000010b

DATA_ACC=ACC_PRESENT or ACC_DSEG or ACC_DATAWR

; 10010010b

CODE_ACC=ACC_PRESENT or ACC_CSEG or ACC_CONFORM

; 10011100b

STACK_ACC=ACC_PRESENT or ACC_DSEG or ACC_DATAWR or ACC_

EXPDOWN; 10010110b

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

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

SHUT_DOWN equ 0FEh

A20_PORT equ 0D1h

A20_ON equ 0DFh

A20_OFF equ 0DDh

INT_MASK_PORT equ 21h

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 21h

;Выходим в DOS

mov ax,4C00h

int 21h

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

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

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

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

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

shl 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

shl ax,4

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

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

mov bx,offset gdt_cs

setgdtentry

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

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

mov ax,ss

mov dl,ah

shr dl,4

shl 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,0FFh

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

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

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

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

call enable_a20

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

mov real_ss,ss

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

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

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

ideal

p286

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

lgdt [QWORD gdt_gdt] ;db 0Fh,01h,16h dw offset gdt_gdt

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

mov ax,0001h

lmsw ax ;db 0Fh,01h,F0h

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

masm

.286

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

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

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

jmp far flush

db 0EAh

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:[offset 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:

hlt

jmp wait_reset

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

shutdown_return:

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

push cs

pop ds

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

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

mov ss,real_ss

mov sp,real_sp

;Закрываем адресную линию A20

call disable_a20

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

mov ax,000dh

out CMOS_PORT,al

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

in al,INT_MASK_PORT

and al,0

out INT_MASK_PORT,al

sti

ret

set_real_mode ENDP

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

;адресной линии программам будет доступна память свыше 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

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

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

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

Обход резидентных антивирусных мониторов

Обычно все программы используют сервис DOS так:

mov ah,... int 21h

По команде INT управление передается в точку, адрес которой определяется двумя словами, находящимися в таблице векторов прерываний по адресу 0000h:0084h. С этого момента начинается исполнение команд многочисленных обработчиков прерывания INT 21h и не менее многочисленных резидентных программ до тех пор, пока управление, наконец, не получит оригинальный обработчик операционной системы (рис. 5.1):

Рис. 5.1

Разумеется, среди этих многочисленных обработчиков может «затесаться» обработчик, принадлежащий антивирусному монитору, который не дает спокойно работать не только вирусам, но и обычным программам. Поэтому серьезные вирусы и некоторые хорошо написанные программы пытаются определить адрес оригинального обработчика и обратиться к нему напрямую, в обход остальных обработчиков:

mov ah,...

pushf

call dword ptr O21...

O21 dw ?

S21 dw ?

Но антивирусные мониторы учитывают эту возможность и принимают свои меры.

Определение адреса оригинального обработчика DOS

Для того чтобы обратиться к DOS напрямую, нужно знать адрес оригинального обработчика. Получить этот адрес не так просто.

Метод трассировки Чаще всего используется метод трассировки при помощи отладочного прерывания INT 1. Суть метода заключается в том, что вирус трассирует прерывание INT 21h (включает флаг трассировки, при этом после каждой команды происходит прерывание INT 1) и проверяет значение сегмента, в котором идет обработка прерывания. Если значение сегмента меньше 0300h, то это обработчик DOS. Например, так поступал много лет назад вирус Yankee 2C (M2C, Музыкальный). Вот листинг соответствующего фрагмента с комментариями:
Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*