гл.15 В КОТОРОЙ ВЫ УЗНАЕТЕ О ПРОКЛЯТИИ MSDOS -- БУТОВЫХ ВИРУСАХ
(совершенно новая тема)
============================================================================
СРАЗУ ЖЕ ПРЕДУПРЕДИМ ВАС, что работа в данной области сопряжена с повы-
шенной опасностью. => Вы должны, если решитесь что-либо предпринять, прояв-
лять крайнюю осторожность.
Вот какие минимальные правила техники безопасности мы бы Вам рекомендо-
вали: при помощи программы diskeditor из нортоновских утилит перепишите на
специальную дискету (в виде файлов) такие объекты ЖЕСТКОГО ДИСКА как Boot
Record и Partition Table (они придставлены в меню diskeditor-а). Если Вы слу-
чайно повредите эти объекты во время своего эксперимента, при помощи того же
diskeditor-а (предварительно загрузившись с системной дискеты) Вы можете их
восстановить (записать соответствующие файлы в область Boot Record или MBR).
Более того, когда Вы вольно работаете с прерыванием 13h, иногда полезно быва-
ет сохранять подобным образом даже FAT.
Расскажем, не вдаваясь в излишние подробности о логической структуре
жесткого диска (HDD). HDD разбит на разделы, называемые логическими дисками.
На каждом из разделов в принципе может обитать своя операционная система.
Каждый такой раздел имеет специальный загрузочный сектор, который, в случае
если раздел имеет свою систему, хранит программу ее загрузки. Кроме разделов
HDD имеет специальный трэк (дорожку), не доступный для пользователя MS-DOS;
т.н. скрытый трэк.
А как PC узнает, на каком из разделов находится система и как он ее заг-
рузит? Дело в том, что на скрытом трэке, в самом его начале (цилиндр 0, сто-
рона 0, сектор 1) находится специальная крохотная программа-загрузчик (Master
Boot-Record (MBR)), которая анализирует, - какой из разделов имеет систему
(является активным) и передает управление загрузчику этой системы.
Теперь по-подробнее, -- как происходит процесс загрузки PC.
1) Вы включили электропитание;
2) Специальные подпрограммы BIOS-а, сидящие в ПЗУ, тестируют память
и прочее железо;
3) Специальная подпрограмма BIOS-а считала с HDD самый первый сектор
скрытого трэка (MBR) и передела ей управление. (MBR была считана
по адресу 0000:7C00h);
4) MBR хранит в себе специальную таблицу (Partition Table), в которой
говорится, на каком из разделов HDD сидит система;
MBR анализирует эту таблицу, определяет активный раздел, после чего
5) MBR считывает в память (по адресу 0000:7C00h) загрузчик системы,
(он находится на диске в начале соответствующего раздела) и передает
ему управление;
6) Загрузчик системы (Boot Record (BR)) загружает в память системные
файлы и передает им управление;
7) далее инициализируются драйверы из config.sys; запускается
COMMAND.COM и стартует autoexec.bat;
Достаточно долгий и нудный процесс. Но бутовые вирусы себя особо не ут-
руждают. Когда бутовый вирус заражает компьютер, он переписывает либо MBR,
либо -- BR в какое-либо другое место (как правило -- в пределах скрытого трэ-
ка), а сам -- садится на их место. Когда в следующий раз включат зараженный
PC, при выполнении пункта 3 (или 5) вместо MBR (или BR) в память по адресу
0000:7C00h будет считан и получит управление вирус. Он по специальному меха-
низму посадит резидент и после этого загрузит по адресу 0000:7C00h MBR (или
BR) и передаст ей управление. Вирус как бы вклинился в процесс загрузки; стал
в нем посредником.
Чаще вирусы нападают на BR, нежели на MBR. Это связано с рядом причин.
Во-первых в процессе загрузки системы к MBR обращаются не единожды (читаются
данные из Partition Table); т.о. вирус, либо должен оставить в неприкосновен-
ности Partition Table, либо -- включить в свою резидентную процедуру
СТЭЛС-блок, каждый раз, когда идет запрос на чтение сектора 001, подсовыва-
ющий сохраненную где-то истинную MBR. Во-вторых даже при визуальном контроле
(если вы загрузитесь с системной дискеты и посмотрите на сектор 001) в MBR
легче обнаружить присутствие вируса, т.к. "здоровая" MBR занимает лишь около
1/3 сектора, остальное -- пустота.
Встает вопрос: каким образом бутовые вирусы заражают PC? Есть 2 способа.
Во-первых вирус может быть не чисто бутовым, а бутово-файловым; т.е. заражать
как MBR (BR), так и EXE- и COM-файлы. С компьютера на компьютер он переносит-
ся в файле. Во-первых вирус может внедряться в Boot Record-ы гибких дисков.
Пользователь нередко забывает извлечь дискету из дисковода перед перезагруз-
кой PC. Если это случится, PC пробует загрузить систему с дискеты. Тут-то и
вылезает вирус.
Теперь опишем механизм посадки резидента (он отличается от всех рассмот-
ренных нами ранее).
Мы уже пользовались областью данных BIOS. В ячейке с адресом 0040:0134h
мы хранили флажок наличия резидентной копии вируса в памяти. Но помимо пустых
ячеек, которые мы можем использовать в своих целях, область данных BIOS со-
держит ячейки, хранящие очень важную информацию. В наших изысканиях нас будет
интересовать ячейка с адресом 0000:0413h. Здесь хранится величина свободной
памяти PC (одно слово). Выражается эта величина в килобайтах. В момент, когда
файлы MS-DOS загружаются в память, загрузка эта выполняется с учетом величины
свободной памяти. Если перед началом загрузки DOS уменьшить слово по адресу
0000:0413h, то после загрузки память будет распределена так, что появится
свободная область, потерянная для DOS. Ее размер = величине, на которую мы
уменьшили слово по адресу 0000:0413h (в килобайтах). В эту область мы и можем
посадить наш резидент. Весь фрагмент посадки резидента будет выглядеть так:
XOR AX,AX ;¬
MOV DS,AX ;¦DS=0
MOV AX,word ptr DS:[0413h] ;¦уменьшаем количество свободной
DEC AX ;¦памяти на 1 Kб
MOV word ptr DS:[0413h],AX ;-
;
MOV CL,06 ;¬вычисляем сегментный адрес
SHL AX,CL ;+свободного участка памяти
MOV ES,AX ;-
;
MOV AX,rezident_segment ;¬
MOV DS,AX ;¦пересылаем в захваченную
MOV SI,rezident_offset ;¦нами область код резидента
XOR DI,DI ;¦ (здесь это - 1 Кб)
MOV CX,0100h ;¦
CLD ;¦
REPNE MOVSW ;-
Ниже мы приводим программу, которая является, по-сути, фильтром предох-
раняющим компьютер от бутовых вирусов. Этот фильтр, подобно бутовому вирусу,
записывается (но только не сам по себе, а -- программистом) в сектор 0 0 1
(MBR при этом заблаговременно перемещается нами в сектор 0 0 7). В момент
загрузки фильтр сажает резидент на прерывание 13h. Как только бутовый вирус
попытается заразить PC (будет дано прерывание 13h -- запись в сектор 0 0 1
или 0 1 1) -- фильтр приостановит работу PC и выдаст предупреждение. После
этого PC будет автоматически перезагружен при помощи команды
JMP__far_0FFFF0000h (по этому адресу находится подпрограмма BIOS, осуществля-
ющая перезагрузку). Фильтр реализует стэлс-механизм сектора 0 0 1 (при попыт-
ке считать оттуда информацию мы получаем истинную MBR).
Вот блок/схема программы:
--инициализационная часть-¬ _/блок обработки прерывания 13h\_
-------------------------------------¬ -------------------------------------¬
¦ установка стека: SS=0, SP=7C00h ¦ ¦ читаеся сектор 0 0 1 HDD? если да -¦
¦(сам код начинается по 0000:7C00h) ¦ ¦подсовываем вместо него сектор 0 0 7¦
L-----------------T------------------- ¦(истинную MBR,загодя там сохраненную)
¦ L-----------------T-------------------
------------------+------------------¬ ¦
¦ уменьшаем слово по адресу 0:413h ¦ ------------------+------------------¬
L-----------------T------------------- ¦кто-то пытается что-то записать в ¦
¦ ¦сектор 0 0 1? да -- идем на объявле-¦
------------------+------------------¬ ¦ние тревоги >>-----------------------¬
¦ пересылаем резидент в освободив- ¦ L-----------------T-------------------¦
¦ шуюся область ¦ ¦ ¦
L-----------------T------------------- ------------------+------------------¬¦
¦ ¦кто-то пытается что-то записать в ¦¦
------------------+------------------¬ ¦сектор 0 1 1? нет - идем на IRET >>--¦¬
¦ делаем JMP far на продолжение кода ¦ L-----------------T-------------------¦¦
¦ уже в резиденте ¦ ¦<-------------------¦
L-----------------T------------------- ------------------+------------------¬ ¦
¦ ¦ объявление тревоги и перезагрузка ¦ ¦
------------------+------------------¬ ¦ PC (JMP far FFFF0000h) ¦ ¦
¦ перехватываем вектор прерывания ¦ L------------------------------------- ¦
¦ 13h ¦ -----------¬<--------------
L-----------------T------------------- ¦ IRET ¦
¦ L-----------
------------------+------------------¬
¦ считываем по адресу 0000:7C00h ¦
¦ истинную MBR (она была записана ¦
¦ в сектор 0 0 7) ¦
L-----------------T-------------------
¦
------------------+------------------¬
¦ делаем JMP far на 0000:7C00h ¦
¦ (отдаем управл-е истинной MBR) ¦
L-------------------------------------
Довольно-таки простая конструкция.
А вот и сама программа:
-----------------------------------------------------------¬
¦ пример 22 ¦:
L-----------------------------------------------------------
TITLE Это - COM. программа N23 -- примитивный антивирусный фильтр
ASSUME CS:CodeSegment
;-------------------------------------------------------------------------
CodeSegment SEGMENT PARA
ORG(100h)
Start:
MainProcedure PROC NEAR
;
; ;внимание! -- при имплан-
; ; тации в область MBR
; ; сектор должен заканчиваться
; ; сигнатурой 55AAh
; ;
Code_begining:CLI ;¬ установка стека:
XOR AX,AX ;+SS:SP = 0000:7C00
MOV SS,AX ;¦
MOV SP,7C00h ;-
MOV SI,SP ;SI = 7C00
MOV DS,AX ;DS = 0
STI
;
MOV AX,word ptr DS:[0413h] ;¬уменьшаем количество сво-
DEC AX ;¦ бодной памяти на 1 Kб
MOV word ptr DS:[0413h],AX ;-
MOV CL,06 ;¬вычисляем сегментный адрес
SHL AX,CL ;¦свободного участка памяти
MOV ES,AX ;-
XOR DI,DI ;DI = 0
MOV CX,0100h ;¬пересылаем в захваченную
CLD ;+нами область код резидента
REPNE MOVSW ;- (здесь это - 1 Кб)
;
PUSH ES ;¬
MOV AX,Continue_work-Code_begining;+JMP Far на продолжение
PUSH AX ;¦ кода уже в резиденте
RETF ;-
;
;-------перехват вектора прерывания 13h----------------------¬
Continue_work:MOV AX,word ptr DS:[4Ch] ¦
MOV word ptr ES:[jmp_old_int13-Code_begining+1],AX ¦
MOV AX,word ptr DS:[4Eh] ¦
MOV word ptr ES:[jmp_old_int13-Code_begining+3],AX ¦
CLI ¦
MOV word ptr DS:[4Ch],Resident13_begining-Code_begining ¦
MOV word ptr DS:[4Eh],ES ¦
STI ¦
;-------------------------------------------------------------
;
;-----загрузка истин. MBR и передача управления ей-----------¬
MOV DX,0080h ;¬ side 0 disk 1 ¦
MOV CX,0007h ;¦ cyl 0 sect 7 ¦
MOV BX,7C00h ;¦ ¦
XOR AX,AX ;¦ ¦
MOV ES,AX ;+загружаем MBR по адресу¦
MOV AX,0201h ;¦ 0000:7C00h ¦
INT 13h ;- ¦
DB 0EAh,00,7Ch,00,00 ;JMP far 0000:7C00h ¦
;-------------------------------------------------------------
;
;-----процедура обработки прерывания 13h---------------------¬
Resident13_begining: ¦
CMP CX,0001h ;¬ ¦
JNE jmp_old_int13 ;¦ ¦
CMP DX,0080h ;¦реализация стэлс-меха- ¦
JNE may_by_boot ;¦низма: читающий сектор ¦
CMP AH,02 ;¦0 0 1, получает истин. ¦
JNE may_by_write ;¦MBR ¦
MOV CX,0007h ;- ¦
JMP Short jmp_old_int13 ; ¦
; ¦
may_by_boot: CMP DX,0180h ;¬ ¦
JNE jmp_old_int13 ;¦ ¦
may_by_write: CMP AH,03 ;¦отслеживание попытки ¦
JNE jmp_old_int13 ;¦записать что-то в ¦
MOV AX,3 ;¦сектор 0 0 1 -- MBR ¦
INT 10h ;¦или -- 0 1 1 -- BR ¦
PUSH CS ;- ¦
POP DS ;¬ ¦
MOV AH,9 ;¦печать предупруждения ¦
MOV DX,admonition - Code_begining ;¦о попытки записи ¦
INT 21h ;- ¦
XOR AX,AX ;¬ожидание нажатия клавиши
INT 16h ;- ¦
DB 0EAh,00,00,0FFh,0FFh ;JMP far FFFF:0000h ¦
jmp_old_int13: ;¬здесь будет адрес старого
; ;¦ обработчика INT 13h ¦
DB 0EAh,00,00,00,00 ;-JMP far ????:????h ¦
; ¦
; ¦
admonition: DB 'System area writing attempt !!!',0Dh,0Ah ¦
DB 'Remove floppy disks & press any key...$' ¦
Resident_ending:------------------------------------------------------------
;
;
;
MainProcedure ENDP
;
CodeSegment ENDS
END Start
Что здесь новенького? Новое прерывание. Прерывание BIOS INT 16h (функция
0) -- ввод с клавиатуры. Когда дается это прерывание, PC замирает и ждет на-
жатия клавиши. После нажатия клавиши соответствующий ASCII символ помещается
в AL, а в AH устанавливается скэн-код. В этом примере прерывание 16 использу-
ется просто для создания паузы -- ожидание нажатия любой клавиши. Еще здесь
показана функция 9 прерывания 21h -- печать строки символов. С этой функцией
мы уже встречались (см. пример 10). Напомним лишь кратко, что печатаемая
строка символов обязательно должна заканчиваться символом "$". Ее адрес дол-
жен быть загружен в пару регистров DS:DX.
Удивительно, с какой легкостью показанный выше антивирус может превра-
титься в полноценный (правда, - довольно примитивный) бутовый вирус. Изменить
надо лишь чуть-чуть. Вот блок/схема; сравните:
--инициализационная часть-¬ _/резидентная часть\_
------------------------------------¬ -------------------------------------¬
¦ установка стека: SS=0, SP=7C00h ¦ ¦ читаеся сектор 0 0 1 HDD? если да -¦
¦(сам код начинается по 0000:7C00h) ¦ ¦подсовываем вместо него сектор 0 0 7¦
L-----------------T------------------ ¦(истинную MBR,загодя там сохраненную)
¦ L-----------------T-------------------
------------------+-----------------¬ ¦
¦ уменьшаем слово по адресу 0:413h ¦ ------------------+------------------¬
L-----------------T------------------ ¦читаееся сектор 0 0 1 дискеты? нет, ¦
¦ ¦уходим на IRET >>--------------------¬
------------------+-----------------¬ L-----------------T-------------------¦
¦ пересылаем резидент в освободив- ¦ ¦ ¦
¦ шуюся область ¦ ------------------+------------------¬¦
L-----------------T------------------ ¦включен ли мотор дисковода? да, -- ¦¦
¦ ¦уходим на IRET >>-------------------->
------------------+-----------------¬ L-----------------T-------------------¦
¦ делаем JMP far на продолжение кода¦ ¦ ¦
¦ уже в резиденте ¦ ------------------+------------------¬¦
L-----------------T------------------ ¦записываем код вируса в сектор 0 0 1¦¦
¦ ¦дискеты ¦¦
------------------+-----------------¬ L-----------------T-------------------¦
¦ считываем по адресу 0000:7C00h ¦ ---+--¬ ¦
¦ истинную MBR (она была записана ¦ ¦ IRET¦<----------------
¦ в сектор 0 0 7) ¦ L------
L-----------------T------------------
¦
------------------+-----------------¬
¦ перехватываем вектор прерывания ¦
¦ 13h ¦
L-----------------T------------------
¦
------------------+-----------------¬
¦проверяем, есть ли в считанной MBR ¦
¦сигнатура вируса; если да - обходим¦
¦блок заражения >>--------------------¬
L-----------------T------------------ ¦
¦ ¦
------------------+-----------------¬ ¦
¦переписываем MBR в сектор 0 0 7 ¦ ¦
+-----------------------------------+ ¦
¦записываем код вируса в сектор 001 ¦ ¦
L-----------------T------------------ ¦
¦ ¦
------------------+-----------------¬<-
¦ делаем JMP far на 0000:7C00h ¦
¦ (отдаем управл-е истинной MBR) ¦
L------------------------------------
Далее
|