Восстановление данных. Практическое руководство
Обнаружив загрузочный раздел (а обнаружить это можно по флагу
, находящемуся по нулевому смещению от начала раздела), загрузчик должен считать первый сектор этого раздела, поместив его в памяти по адресу80h
, то есть в точности поверх своего собственного тела. А вот это уже нехорошо! И чтобы не вызвать крах системы, загрузчик должен заблаговременно перенести свое тело по другому адресу, что обычно осуществляется командой0000:7C00h
. Копироваться можно по любому из адресов памяти — отMOVSB
до0080:0067h
. Память, расположенную ниже9FE00h
, лучше не трогать, так как здесь находятся вектора прерываний и системные переменные BIOS, а от0080:0067h
и выше начинается область отображения ПЗУ, так что предельно доступный адрес равенA000h
.A000h - 200h (размер сектора) == 9FE00h
Не забывайте, что трогать регистр
ни в коем случае нельзя, поскольку в нем передается номер загрузочного привода. Некоторые загрузчики содержат ошибку, всегда загружаясь с первого жесткого диска, и это в то время, как BIOS уже больше 10 лет как позволяют менять порядок загрузки, и потому загрузочным может быть любой привод.DL
По правде говоря, FASM — это единственный известный мне ассемблер, "переваривающий" команду дальнего вызова
напрямую. Все остальные ассемблеры заставляют извращаться приблизительно так:JMP 0000:7C00h
. Здесь мы заталкиваем в стек сегмент и смещение целевого адреса и выполняем дальнийPUSH offset_of_target/PUSH segment_of_target/RETF
, переносящий нас на нужное место. Еще можно воспользоваться самомодифицирующимся кодом, собрав командуRETF
"вручную", или просто расположить целевой адрес в одном сегменте с исходным адресом (например,JMP FAR
→0000:7C00h
). Однако эти подходы муторны и утомительны.0000:7E00h
В общем, скелет нашего загрузчика будет выглядеть так, как показано в листинге 5.8.
Листинг 5.8. Скелет простейшего загрузчика, написанный на FASM
use16
ORG 7C00h
CLD ; Копируем слева направо
; (в сторону увеличения адресов)
MOV SI,7C00h ; Откуда копировать
MOV DI,7E00h ; Куда копировать
MOV CX,200h ; Длина сектора
REP MOVSB ; Копируем
; // Выбираем раздел, который мы хотим загрузить,
; // считываем его в память по адресу 0000:7C00h
; // (см. листинги 5.7 и 5.6)
JMP 0000:7C00h ; Передаём управление на загрузочный сектор
Записываем загрузчик в главную загрузочную записьПод старушкой MS-DOS записать свой загрузчик в MBR было просто. Для этого достаточно дернуть прерывание
, функцияINT 13h
(запись сектора). Но под Windows NT этот прием уже не работает, и приходится прибегать к услугам функции03h
. Если вместо имени открываемого файла указать название устройства, например,CreateFile
(первый физический диск), мы сможем свободно читать и записывать его сектора вызовами\\.\PHYSICALDRIVE0
иReadFile
соответственно. При этом флагWriteFile
должен быть установлен на значениеdwCreationDisposition
, а флагOPEN_EXISTING
— на значениеdwShareMode
. Еще потребуются права системного администратора, иначе ничего не получится.FILE_SHARE_WRITE
Законченный пример вызова
выглядит, как показано в листинге 5.9.CreateFile
Листинг 5.9. Открытие непосредственного доступа к жесткому диску под Windows NT
XOR EAX,EAX
PUSH EAX ; hTemplateFile
PUSH dword FILE_ATTRIBUTE_NORMAL ; dwFlagsAndAttributes
PUSH dword OPEN_EXISTING ; dwCreationDisposition
PUSH EAX ; lpSecurityAttributes
PUSH dword FILE_SHARE_WRITE ; dwShareMode
PUSH dword (GENERIC_WRITE OR GENERIC_READ) ; dwDesiredAccess
PUSH DEVICE_NAME ; Имя устройства
CALL CreateFile ; Открываем устройство
INC EAX
TEST EAX,EAX
JZ error
DEC EAX
...
DEVICE_NAME db "\\.\PHYSICALDRIVE0",0
BUF RB 512 ; Буфер
Открыв физический диск и убедившись в успешности этой операции, мы должны прочитать оригинальный MBR-сектор в буфер, перезаписать первые
байт, ни в коем случае не трогая таблицу разделов и сигнатуру1BBh
(мы ведь не хотим, чтобы диск перестал загружаться, верно?). Теперь остается записать обновленный код MBR на место и закрыть дескриптор устройства. После перезагрузки все изменения вступят в силу.55h AAh
ПримечаниеПравда, вполне возможно, что внесенные вами изменения и не подумают вступать в силу. Загрузчик жестоко мстит за малейшие ошибки проектирования. Поэтому, чтобы не потерять содержимое своих разделов, для начала лучше попрактиковаться на VMWare или любом другом эмуляторе PC.
Под Windows 9x, разумеется, трюк с
не работает. Но там можно воспользоваться симуляцией прерываний из DMPI или обратиться к драйверу ASPI. Оба способа были подробно описаны в моей книге "Техника защиты компакт-дисков от копирования". Однако, хотя в ней речь идет о CD, а не о HDD, жесткие диски программируются аналогично.CreateFile
Прежде чем писать собственный загрузчик, рекомендуется изучить существующие нестандартные загрузчики. Все перечисленные ниже загрузчики распространяются по лицензии GPL или BSD, то есть без ограничений.
□ Ge2000.asm — тщательно прокомментированный Stealth-вирус, подменяющий системный загрузчик своим собственным. Хоть это и вирус, но он не опасен и может быть использован в учебных целях.