Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых
[Назад]

Восстановление данных в разделах NTFS

В статье, посвященной сохранности и восстановлению данных, мы расскажем о файловой системе NTFS, получающей все большее распространение вместе с операционными системами Microsoft Windows NT/2000. Мы расскажем об использовании некоторых утилит восстановления данных в разделах NTFS, а также приведем форматы наиболее важных внутренних структур этой файловой системы.

Файловая система нового поколения для Microsoft Windows NT/2000

Название файловой системы NTFS расшифровывается как New Technology File System, т.е. файловая система, созданная с применением новой технологии. И как Вы увидите далее, это название себя полностью оправдывает. Действительно, файловая система NTFS лишена многих недостатков своих предшественниц - FAT и FAT-32. Она обладает повышенной надежностью, способностью восстановления после сбоев, допускает использование символов национальных алфавитов для имен файлов и каталогов, позволяет упаковывать и шифровать файлы, содержит мощные средства разграничения доступа и т.д. Мы могли бы продолжить этот список еще дальше.

Тем не менее, дисковые разделы NTFS также подвержены разрушениям в результате аппаратных и программных сбоев, вирусного воздействия, ошибок операторов и т.п. Однако благодаря более совершенным принципам, использованным при ее проектировании, вероятность успеха восстановительных работ в разделах NTFS обычно намного выше, чем в разделах FAT и FAT-32.

Объем настоящей статьи не позволяет нам детально рассмотреть все особенности NTFS, поэтому мы ограничимся лишь теми сведениями, которые имеют непосредственное отношение к проведению восстановительных работ.

Заметим также, что все сведения о внутренних недокументированных структурах NTFS, приведенные в этой статье, не претендуют на полноту и точность. Они получены из различных источников, найденных в Интернете, в частности, из документации к драйверу NTFS операционной системы Linux, а также "добыты" в результате собственных исследований дампов системных структур NTFS, проведенных авторами при помощи редактора Microsoft DiskProbe и Microsoft DISKEDIT.

Поиск основных внутренних структур NTFS

Если попытки восстановления данных из разрушенного раздела NTFS при помощи автоматизированных утилит, таких как EraseUndo, CrashUndo или EasyRecovery не привели к успеху, можно попытаться извлечь нужные файлы вручную. В общем случае это довольно нетривиальная работа, однако иногда только этот способ может дать какие-то результаты.

Исследование внутренних структур файловой системы NTFS можно выполнять программой Microsoft DiskProbe из комплекта Windows NT Resource Kit или редактором диска Norton DISKEDIT из комплекта утилит Norton Utilities. Об этих средствах мы уже рассказывали в предыдущей статье нашей серии. Напомним, что Microsoft DiskProbe работает только в среде операционной системы Microsoft Windows NT/2000, а Norton DISKEDIT - в среде MS-DOS.

Определенный интерес в плане изучения внутренних структур NTFS может представлять собой программа Microsoft DISKEDIT, расположенная в пакете обновления операционной системы Microsoft Windows NT Srvice Pack 4, 5 или 6. Не путайте ее с одноименной программой из пакета Norton Utilities - это совершенно разные средства, предназначенные для решения различных задач.

К сожалению, ни один из существующих редакторов диска (кроме, разве лишь, только что упомянутой программы Microsoft DISKEDIT) не окажет Вам существенной помощи при исследовании таких важнейших структур NTFS, как записи главной таблица файлов MFT или записи каталогов. Поэтому при проведении восстановительных работ Вам придется иметь дело главным образом с шестнадцатеричным дампом секторов раздела.

Загрузочный сектор раздела NTFS

В предыдущей статье этой серии мы рассказывали о содержимом главной загрузочной записи MBR, в которой имеется код начальной загрузки и таблица разделов. Там же мы говорили о том, что в начале каждого раздела имеется загрузочная запись Boot Record, содержащая таблицу параметров BIOS Parameter Block (BPB).

Разделы файловой системы NTFS также начинаются с загрузочного сектора. Ниже мы привели формат начальной области загрузочного сектора:

Смещение, байтРазмер, байтОписание
03Команда JMP xxxx (переход на программу начальной загрузки)
38Название фирмы-изготовителя операционной системы и версия
0xB2Размер сектора в байтах
0xD1Количество секторов в одном кластере
0xE7Зарезервировано
0x15 1Тип носителя данных
0x16 2Зарезервировано
0x182Количество секторов на дорожке
0x1A2Количество магнитных головок
0x1C8Зарезервировано
0x242Содержит число 0x80
0x262Содержит число 0x80
0x284Младшее слово общего количества секторов в разделе
0x2C4Старшее слово общего количества секторов в разделе
0x304Младшее слово номера кластера, в котором начинается таблица MFT
0x344Старшее слово номера кластера, в котором начинается таблица MFT
0x384Младшее слово номера кластера, в котором начинается копия таблицы MFT
0x3C4Старшее слово номера кластера, в котором начинается копия таблицы MFT
0x404Размер записи MFT в кластерах
0x444Размер буфера индексов в кластерах
0x484Младшее слово серийного номера диска
0x4C4Старшее слово серийного номера диска

Если Вы создаете собственные программы для работы с разделами NTFS на низком уровне, то Вам пригодится следующее определение типа BOOT_NTFS, составленное с использованием только что приведенного формата загрузочного сектора:

typedef struct _BOOT_NTFS 
{
    BYTE    jump[3];
    BYTE    name[8];
    UINT16  sec_size; 
    BYTE    secs_cluster; 
    BYTE    reserved_0[7]; 
    BYTE    media_desc; 
    UINT16  reserved_2; 
    UINT16  secs_track; 
    UINT16  num_heads; 
    BYTE    reserved_3[8]; 
    UINT16  reserved_4; 
    UINT16  reserved_5; 
    UINT32  num_secs_lo; 
    UINT32  num_secs_hi; 
    UINT32  mft_clus_lo; 
    UINT32  mft_clus_hi; 
    UINT32  mft2_clus_lo; 
    UINT32  mft2_clus_hi; 
    UINT32  mft_rec_size; 
    UINT32  buf_size; 
    UINT32  volume_id_lo; 
    UINT32  volume_id_hi; 
} BOOT_NTFS;

Это определение мы взяли из исходных текстов программы CrashUndo 2000, предназначенной для автоматического восстановления разрушенных томов NTFS.

На рис. 1 мы показали содержимое загрузочного сектора раздела NTFS в виде дампа, полученного с помощью программы Microsoft DiskProbe.

Рис. 1. Дамп загрузочного сектора раздела NTFS

Просматривая дамп визуально, можно зафиксировать признаки, характерные для загрузочной записи NTFS. Это строка "NTFS" в начале сектора, а также текстовые сообщения в его конце. Кроме того, как и всякий служебный сектор, отвечающий за формирование структуры разделов, последние два байта загрузочного сектора NTFS содержат байты 55AA.

Для форматированного просмотра содержимого полей данного сектора выберите из меню View программы Microsoft DiskProbe строку NTFS BootSector. После этого Вы сможете просматривать и редактировать отдельные поля загрузочной записи в диалоговом окне, показанном на рис. 2.

Рис. 2. Просмотр содержимого загрузочного сектора раздела NTFS в форматированном виде

Загрузочный сектор содержит критически важную информацию, при разрушении которой операционная система не сможет смонтировать раздел NTFS. Если это случилось, Вы можете попытаться найти копию загрузочного сектора. В зависимости от размера раздела NTFS и версии операционной системы, в которой он был отформатирован, создается копия загрузочного сектора либо в середине, либо в конце раздела.

Обратите внимание на кнопки Volume End и Volume Middle, расположенные в правой части окна, показанного на рис. 2. С помощью этих кнопок можно перейти к просмотру одной из копий загрузочного сектора.

Если оказалось, что оригинальная загрузочная запись разрушена, можно попытаться записать на ее место копию. Во многих случаях этого оказывается достаточно для того, чтобы смонтировать раздел и скопировать из него необходимые файлы.

Просмотреть содержимое загрузочного сектора раздела NTFS в форматированном виде можно и при помощи программы Microsoft DISKEDIT. Чтобы запустить ее, скопируйте в отдельный каталог из распакованного архива пакета обновления Microsoft Windows NT Service Pack 6 следующие файлы:

  • diskedit.exe;
  • ifsutil.dll;
  • ufat.dll;
  • ulib.dll;
  • untfs.dll

Далее запустите программу diskedit.exe и выберите из меню File строку Open. Введите в поле Volume Name имя диска, снабдив его двоеточием (рис. 3), а затем щелкните кнопку OK.

Рис. 3. Открытие диска d:

Сразу обращаем Ваше внимание на то, что программа Microsoft DISKEDIT может открыть только такой раздел, который уже был смонтирован операционной системой. Именно поэтому сама по себе программа Microsoft DISKEDIT едва ли может рассматриваться как инструмент восстановления данных. Однако с ее помощью можно многое понять в недокументированных структурах NTFS.

Если раздел поврежден настолько, что смонтировать его не удается, анализ повреждений возможен только при помощи программы Microsoft DiskProbe. Эта программа может открывать не только логические, но и физические диски.

Итак, полагаем, что Вы открыли диск. Теперь, чтобы просмотреть загрузочный сектор, выберите из меню Read строку Sectors. На экране появится диалоговое окно с полями Starting Sector и Run Length. В первом поле нужно ввести номер сектора, который должна прочитать программа (загрузочная запись располагается в секторе с номером 0), а во втором - количество секторов (нам нужен только один сектор, поэтому ведите здесь значение 1). Далее щелкните кнопку OK. В окне программы Microsoft DISKEDIT появится шестнадцатеричный дамп первого сектора, аналогичный дампу, показанному на рис. 1.

Теперь, чтобы перейти в режим форматного просмотра загрузочного сектора, выберите из меню View строку NTFS Boot Sector. Результат этой операции показан на рис. 4.

Рис. 4. Форматный просмотр загрузочной записи NTFS программой Microsoft DISKEDIT

Как видите, все значения здесь отображаются в шестнадцатеричном виде. К сожалению, их нельзя редактировать.

Определение геометрии раздела NTFS

Для успешного проведения восстановительных работ в разделе NTFS необходимо определить его геометрию. Под геометрией раздела мы понимаем набор следующих параметров:

  • размер сектора в байтах (поле Bytes per Sector на рис. 2, смещение 0xB от начала сектора);
  • размер кластера в секторах (поле Sectors per Cluster, смещение 0xD от начала сектора);
  • номер начального кластера главной таблицы файлов MFT и ее копии (поля Clusters to MFT и Clusters to MFT mirr, смещение 0x30 и 0x38 от начала сектора, соответственно);
  • размер записи таблицы MFT в кластерах (поле Clusters per FRS, смещение 0x40 от начала сектора)

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

Размер сектора

Что касается размера сектора Bytes per Sector, то для жестких дисков он обычно равен 512 байт. Другие носители данных (компакт-диски и магнитооптические диски могут использовать иные размеры сектора, такие как 1024 или 2048 байт).

Размер кластера

Важная составляющая геометрии NTFS -размер кластера Sectors per Cluster. Этот размер устанавливается при форматировании раздела и зависит от его объема.

В тех случаях, когда содержимое загрузочного сектора NTFS утеряно, можно воспользоваться следующей таблицей зависимости размера кластера от объема раздела NTFS:

Объем раздела NTFS, ГбайтРазмер кластера, секторы по 512 байт
до 0.51
от 0.5 до 12
от 1 до 24
свыше 28

Эта таблица справедлива для операционной системы Microsoft Windows NT версии 3.51, 4.0 и Microsoft Windows 2000. Что же касается более старых версий Microsoft Windows NT, то в них применялись кластеры и таких размеров:

Объем раздела NTFS, ГбайтРазмер кластера, секторы по 512 байт
от 4 до 816
от 8 до 1632
от 16 до 3264
свыше 32128

Заметим, что при форматировании разделов NTFS можно указать размер кластера явным образом, поэтому приведенные в данной таблице значения следует использовать только в качестве ориентировочных.

Начало таблицы MFT и копии ее первых записей

Теперь о полях Clusters to MFT и Clusters to MFT mirr.

Поле Clusters to MFT содержит номер первого кластера, распределенного главной таблице файлов MFT. Эта таблица содержит ключевую информацию об именах и расположении всех файлов и каталогов, необходимую для проведения восстановительных работ. Заметим, что MFT сама по себе также является файлом с именем $MFT и тоже описана в MFT. Таким образом, файл $MFT ссылается сам на себя.

Обращаем Ваше внимание, что в файловой системе NTFS помимо обычных имеются так называемые системные файлы, имена которых начинаются с символа $. Такие файлы нельзя читать или копировать обычными средствами. Наша утилита восстановления данных CrashUndo for NTFS выполняет эту операцию, читая непосредственно секторы диска, распределенные системным файлам.

При объемах разделов порядка нескольких Гбайт размеры файла $MFT могут достигать десятков Мбайт, особенно если в разделе находится много файлов. По мере того как раздел NTFS живет своей жизнью, на нем появляются и исчезают файлы и каталоги. В результате файл $MFT растет и становится фрагментированным, что замедляет работу файловой системы.

По названию поля Clusters to MFT mirr можно сделать ошибочный вывод о существовании полноценной копии файла $MFT. К сожалению, это не так. Вероятно, из-за больших размеров файла $MFT копируются только его несколько первых записей, в том числе (что важно), запись, описывающая расположение самого файла $MFT.

Размер записи таблицы MFT

Большое значение имеет правильное определение размера записи главной таблицы файлов MFT, записанное в поле Clusters per FRS. Это значение следует рассматривать как целое со знаком. Если содержимое поля положительно, то оно означает количество кластеров, занимаемое одной записью таблицы MFT. Если же оно отрицательное, то для определения размера записи MFT нужно использовать формулу:

MFT_Record_Bytes = 2(-Clusters_Per_FRS)

Здесь Clusters_Per_FRS - значение из поля Clusters per FRS, а MFT_Record_Bytes - количество байт, занимаемых записью MFT.

Поясним эту формулу на примере. В поле Clusters per FRS часто встречается значение 0xF6, которое означает ни что иное, как -10. Если возвести 2 в степень 10, получим значение 1024. Таким образом, размер записи MFT составляет 210=1024 байт. Аналогично, значение 0xF5, равное -11, соответствует размеру записи MFT, равному 211=2048 байт.

Поиск главной таблицы файлов MFT

Что делать, если в результате сбоя полей Clusters to MFT и Clusters to MFT mirr оказалось утерянным?

Вы можете попытаться найти первый сектор кластера, распределенного файлу $MFT при помощи утилиты Microsoft DiskProbe. Для этого откройте восстанавливаемый диск и выберите из меню Tools строку Search Sectors. На экране появится одноименное окно, показанное на рис. 5.

Рис. 5. Поиск записи в таблице MFT для файла $MFT

Установите отметку флажков, как показано на этом рисунке. При этом программа Microsoft DiskProbe будет искать в секторах, интервал номеров которых задан в полях First sector to search и Last sector to search, строку символов "$MFT" в кодировке UNICODE. Именно эта кодировка применяется в NTFS для хранения имен файлов и каталогов.

Флажок Search at offset позволяет выполнять поиск по фиксированному смещению относительно начала сектора. Хотя такой поиск выполняется быстрее, чем поиск по всему сектору (выполняется при отмеченном флажке Exhaustive search), в нашем случае он не приведет к успеху. Дело в том, что расположение имени файла изменяется от одной записи MFT к другой.

Для того чтобы выполнять поиск без учета строчных и прописных букв, мы отметили флажок Ignore case. И, наконец, для поиска строки в кодировке UNICODE мы отметили флажок Unicode characters.

Установив флажки, введите имя файла $MFT в поле Enter characters to search for и щелкните кнопку Search. После этого начнется процесс поиска. Если будет обнаружен подходящий сектор, Вы увидите диалоговое окно, показанное на рис. 6.

Рис. 6. Найден сектор, соответствующий заданным критериям поиска

Щелкните кнопку No, чтобы отказаться от дальнейшего поиска. На экране появится дамп найденного сектора (рис. 7).

Рис. 7. Дамп сектора записи таблицы MFT для файла $MFT

Здесь со смещением 0x00EA располагается имя файла $MFT. Обратите также внимание, что первые 4 байта сектора содержат строку "FILE". Так отмечается начало первого сектора каждой записи MFT.

Структура файла $MFT

Как мы уже говорили, файл $MFT содержит всю информацию о расположении всех файлов раздела, в том числе и самого файла $MFT. Этот файл состоит из записей фиксированной длины, размер которых можно узнать, анализируя загрузочную запись раздела NTFS.

Несколько первых записей файла $MFT описывают системные файлы, перечисленные ниже:

Номер записиИмя системного файлаОписание
0x0$MFTГлавная таблица файлов MFT
0x1$MFTMirrКопия первых 4 записей таблицы MFT
0x2$LogFileЖурнал транзакций. Используется для отката транзакций в случае аварийного завершения операций над файловой системой
0x3$VolumeИнформация о разделе, например, имя соответствующего логического тома и версия файловой системы NTFS
0x4$AttrDefСписок атрибутов, используемых в файловой системе
0x5.Корневой каталог файловой системы
0x6$BitmapБитовый массив, в котором отмечены все использованные кластеры
0x7$BootЗагрузочный сектор раздела NTFS
0x8$BadClusСписок всех плохих кластеров данного раздела. Кластер считается плохим, если в нем есть один плохой сектор
0x9$SecureБаза данных атрибутов безопасности. Применяется только в NTFS версии 5.0 в среде Microsoft Windows 2000
0xA$UpCaseСписок всех прописных символов Unicode. Используется для перекодировки строчных символов в прописные и обратно в процессе сравнения имен файлов и каталогов
0xB$ExtendФайл хранит расширенную информацию файловой системы NTFS версии 5.0, применяемой в среде Microsoft Windows 2000, такую как дисковые квоты, точки монтирования и т.д.
0xC Зарезервировано
0xD Зарезервировано
0xE Зарезервировано
0xF Зарезервировано

Далее в файле $MFT следуют записи с информацией обо всех остальных файлах и каталогах. Именно эти записи будут Вам нужны для извлечения файлов из разрушенного раздела NTFS.

Для каждого файла и каталога в файле $MFT создается одна запись, называемая базовой, и, возможно, несколько расширенных записей. Расширенные записи создаются в том случае, если вся информация о файле или каталоге не помещается в базовой записи (напомним, что размер записи файла $MFT ограничен и обычно составляет 1 Кбайт). Обычно такое происходит, если файлы увеличивают свой размер, по мере того как с ними работают пользователи. Это могут быть файлы баз данных, файлы офисных документов и т.д.

На рис. 8 мы показали структуру файла $MFT. В начале файла мы показали область записей, описывающих системные файлы, а в конце - записи остальных файлов и каталогов.

Рис. 8. Структура файла $MFT

Здесь для файлов MyLetter.doc, Readme.txt, game.exe и каталога AllLettersFolder создано по одной базовой записи, а для файла MyDatabase.mdb - одна базовая и две расширенные записи. Базовая запись и расширенные записи связаны в список.

Как найти запись MFT для произвольного файла по его имени?

Это можно сделать при помощи программы Microsoft DiskProbe. Здесь необходимо использовать описанную ранее процедуру поиска файла $MFT, но в поле Enter characters to search for диалогового окна Search Sectors (рис. 5) Вы должны указать имя нужного файла.

Структура записей файла $MFT

Итак, теперь Вы знаете, что ключевая информация о файлах и каталогах, необходимая для извлечения файлов из поврежденных разделов раздела NTFS, находится в файле $MFT в виде базовых и расширенных записей. Начало файла $MFT нетрудно найти, анализируя загрузочный сектор раздела NTFS. Там же хранится и размер отдельных записей таблицы MFT. Теперь нашей задачей будет изучение структуры этих записей.

Если рассматривать запись MFT в целом, то она содержит список областей переменной длины, называемых атрибутами файлов (File Attribut). Размер этого списка и состав хранящихся в нем атрибутов также может изменяться от записи к записи.

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

Короче говоря, для каждого файла или каталога в файле $MFT хранится список областей данных (атрибутов файла). Этот список может занимать одну или несколько записей MFT. Базовая запись MFT и все расширенные записи одного и того же файла или каталога связаны в список.

Атрибуты файла

Нам известно о существовании 14 атрибутов файла различного типа. Типы атрибута обозначается числами. Ниже мы перечислили атрибуты известных нам типов с кратким описанием хранящейся в них информации.

Тип Имя Описание
0x10$STANDARD_INFORMATIONСтандартный атрибут. Здесь хранится дата и время создания и последнего изменения файла, дата и время последнего доступа к файлу, флаги доступа к файлу, а также дата и время изменения записи MFT, соответствующей данному файлу
0x20$ATTRIBUTE_LISTСписок атрибутов. Если помимо базовой записи MFT для файла создаются расширенные записи, в этом атрибуте перечисляются все атрибуты файла. Кроме того, здесь хранится информация о распределении этих атрибутов по записям MFT (по базовой записи и по расширенным записям данного файла).
0x30$FILE_NAMEИмя файла или каталога. В этом атрибуте хранится имя файла или каталога, набор флагов доступа, размер файла, а также ссылка на запись MFT каталога, в котором хранится данный файл или каталог.
0x40$VOLUME_VERSIONВерсия NTFS для данного раздела.
0x50$SECURITY_DESCRIPTORДескриптор разграничения доступа.
0x60$VOLUME_NAMEИмя тома. Это имя задается при форматировании раздела и может быть изменено пользователем.
0x70$VOLUME_INFORMATIONСостояние тома. Здесь хранится версия драйвера, с помощью которого был создан данный раздел, а также флаг программы CHKDSK. Если этот флаг установлен, то при очередной перезагрузке операционной системы программа CHKDSK выполнит проверку данного раздела.
0x80$DATAАтрибут данных. Этот атрибут может содержать либо данные файла (если размеры файла не превышают размеры записи MFT), либо список номеров кластеров, в которых располагается файл (список экстентов файла).
0x90$INDEX_ROOTКорневая вершина дерева типа B+, с применением которого в NTFS реализована система каталогов.
0xA0$INDEX_ALLOCATIONУзлы ветвей дерева типа B+, с применением которого в NTFS реализована система каталогов.
0xB0$BITMAPНабор бит, описывающих использование отдельных записей MFT или узлов дерева каталогов.
0xC0$SYMBOLIC_LINKИнформация Reparse Point, используется в Microsoft Windows 2000
0xD0$EA_INFORMATIONИнформация о расширенных атрибутах файловой системы HPFS. Используется для обеспечения совместимости NTFS с файловой системой HPFS, применяемой в IBM OS/2.
0xE0$EAДанные расширенных атрибутов файловой системы HPFS.

Для восстановления файлов из разрушенных разделов NTFS наибольший интерес представляют собой атрибуты $STANDARD_INFORMATION, $ATTRIBUTE_LIST, $FILE_NAME и $DATA.

Вначале с помощью Microsoft DiskProbe нужно найти запись MFT файла по имени, которое хранится в атрибуте $FILE_NAME.

Далее, анализируя информацию из атрибута $STANDARD_INFORMATION, можно определить дату создания или изменения файла. На основании этой информации можно сделать вывод о том, нужно ли восстанавливать данный файл или следует поискать другую, более свежую версию этого же файла.

Атрибуты $STANDARD_INFORMATION и $FILE_NAME всегда размещаются в базовой записи MFT, но другие атрибуты этого же файла или каталога могут находиться в расширенных записях. Кроме того, для одного файла может быть создано несколько атрибутов $FILE_NAME, в которых хранится несколько имен одного и того же файла в разных форматах (об этом мы расскажем чуть позже). Поэтому дополнительно может возникнуть необходимость анализа атрибута $ATTRIBUTE_LIST, хранящего полный список атрибутов восстанавливаемого файла.

И, наконец, атрибут $DATA хранит или описывает расположение данных файла, которые, собственно, и требуется восстановить. Там же находится информация о размере файла.

Поиск атрибутов в записях MFT

Прежде чем рассказывать о том, как искать нужные Вам атрибуты в записи MFT, рассмотрим ее структуру в целом.

Как мы уже говорили, размер записи MFT хранится в загрузочном секторе раздела NTFS. Чаще всего записи MFT занимают 2 или 4 сектора, хотя встречаются записи и другого размера.

Каждая запись MFT состоит из заголовка фиксированного формата, вслед за которым идет список атрибутов переменной длины. Приступая к исследованию записи MFT, сначала нужно проанализировать ее заголовок.

Ниже мы представили формат заголовка записи MFT:

Смещение, байтДлина, байтОписание
0x004Текстовая строка "FILE" - признак записи MFT
0x042Смещение массива корректировки записи Update Sequence
0x062Размер массива корректировки записей Update Sequence
0x102Последовательный номер сектора в записи MFT
0x122Счетчик ссылок
0x142Смещение начала списка атрибутов
0x162Флажки, отмечающее состояние записи MFT
0x184Реальный размер записи MFT
0x1C4Размер памяти, занимаемый записью MFT
0x208Файловый номер (File Reference) базовой записи MFT
0x282Максимальное значение идентификатора атрибута, увеличенное на единицу
0x2A2Массив корректировки записи MFT размером 2*(N-1) байт, где N - значение размера массива корректировки записи из поля со смещением 0x06

Изучать заголовок записи MFT лучше всего на конкретном примере. На рис. 9 мы показали дамп первого сектора записи MFT, созданной для файла DataRecovery3.doc (это файл с текстом статьи, которую Вы сейчас читаете). Область заголовка записи MFT здесь выделена линией красного цвета. Дамп второго сектора записи MFT Вы найдете на рис. 10.

Рис. 9. Заголовок записи MFT

Массив корректировки секторов записи MFT

Прежде всего, обратите внимание на поле со смещением 0x04, в котором находится смещение так называемого массива корректировки записей MFT. На рис. 9 это поле выделено черной рамкой и хранит значение 0x002A (напомним, что в компьютерах с процессорами Intel используется такая система хранения данных, при которой наименее значимые байты слова записываются по младшим адресам).

Размер массива корректировки записи MFT находится в поле со смещением 0x06. В нашем случае его значение равно 3.

Исследуя дамп, показанный на рис 9, мы обнаруживаем, что в массиве корректировки хранятся три числа: 0x0002, 0x700C и 0x0000. Первое из этих чисел служит в качестве шаблона корректировки, а два других - корректировочные значения, соответственно, для первого и второго сектора записи MFT.

В ходе корректировки записи MFT, необходимой для ее дальнейшего анализа, необходимо заменить в первом секторе (рис. 9) значение 0x0002 в слове со смещением 0x01FE на значение 0x700C, а во втором секторе (рис. 10) - значение 0x0002 в слове со смещением 0x01FE на значение 0x0000.

Таким образом, массив корректировки содержит значения, которые необходимо записать в конец каждого сектора записи MFT перед ее использованием.

Рис. 10. Второй сектор записи MFT, показанной на рис. 9

Зачем был придуман такой странный механизм корректировки секторов записи MFT?

Этот механизм предназначен для контроля целостности многосекторных записей MFT. Дело в том, что при возникновении сбоев может случиться так, что не все секторы записи MFT будут успешно сохранены на диске. Обнаружив такую дефектную запись, операционная система, возможно, сумеет отменить связанную с ней транзакцию, не допустив катастрофического разрушения файловой системы.

Конечно, для контроля целостности секторов записи можно было бы применить хорошо проверенный метод подсчета контрольных сумм, однако вычисление таких сумм отнимает немало процессорного времени и может неблагоприятно сказаться на производительности файловой системы.

Вместо этого перед сохранением записи MFT операционная система заменяет последние два байта каждого сектора специальным значением - шаблоном корректировки, которое должно быть одинаковым для всех секторов одной записи MFT, но разным для разных записей MFT. Оригинальное содержимое последних байт секторов записи MFT сохраняется во второй и последующих ячейках массива корректировки. В первую ячейку этого массива при этом записывается значение шаблона корректировки.

В нашем примере оригинальные значения последних двух байт в первом и втором секторе, равные, соответственно, 0x700C и 0x0000, были заменены шаблоном корректировки 0x0002. Перед этим операционная система записала числа 0x700C и 0x0000 во второй и третий элемент массива корректировки, соответственно. В первый элемент массива корректировки было записано значение шаблона корректировки 0x0002.

Прослеживание списка атрибутов

Точное смещение начала списка атрибутов хранится в слове заголовка записи MFT со смещением 0x14. Таким образом, в записи, показанной на рис. 9, список атрибутов начинается со смещением 0x0030.

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

Четырехбайтовое слово со смещением 0x0030 в нашем дампе хранит значение 0x00000010. Это стандартный атрибут $STANDARD_INFORMATION. Размер атрибута записан в слове со смещением 0x0034 и равен 0x00000060. Область данных стандартного атрибута выделена на рис. 9 рамкой фиолетового цвета.

Продолжим исследования дампа, представленного на рис. 9.

Прибавив к смещению 0x0030 размер стандартного атрибута $STANDARD_INFORMATION, равный 0x00000060 байт, получим смещение следующего атрибута. Это атрибут имени файла $FILE_NAME с типом 0x00000030 и длиной 0x00000060 байт (выделен на рисунке рамкой синего цвета). Обратите внимание на правую символьную часть дампа, соответствующую этому атрибуту. Нетрудно заметить, что в области данного атрибута хранится строка "DATAREC~1.DOC". Это имя файла DataRecovery3.doc, созданное операционной системой для старых программ DOS, не "умеющих" распознавать длинные имена. Оно хранится здесь в кодировке UNICODE.

Следующий атрибут, расположенный со смещением 0x0108, - это тоже атрибут имени с типом 0x00000030 (выделен рамкой зеленого цвета). Размер памяти, занимаемой данным атрибутом, составляет 0x00000080 байт. Здесь хранится полное имя файла DataRecovery3.doc (также в кодировке UNICODE).

Прослеживая далее список атрибутов, мы можем обнаружить атрибуты $VOLUME_VERSION, не представляющий для нас особого интереса, а также атрибут $DATA.

Атрибут данных $DATA начинается в первом секторе записи MFT со смещением 0x01B0 и заканчивается во втором секторе этой же записи, показанном на рис. 10. Размер атрибута $DATA составляет 0x00000060 байт.

Обратите внимание, что последние два байта первого сектора записи MFT, измененные шаблоном корректировки, приходятся как раз на середину атрибута данных. Если не восстановить в этом месте правильное значение, равное 0x700C, Вы будете неправильно интерпретировать содержимое атрибута данных, что приведет к невозможности восстановления файла.

Формат атрибутов файла

Итак, Вы научились прослеживать списки атрибутов файла в записи MFT. Теперь мы расскажем о внутренней структуре атрибутов.

Атрибуты файлов любого типа состоят из заголовка фиксированного формата и области данных (Data Stream). Заголовок описывает атрибут в целом, а область данных хранит информацию, представленную атрибутом.

Отметим, что атрибуты можно разделить на резидентные и нерезидентные атрибуты.

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

Например, все атрибуты в записи, показанной на рис. 9 и 10, кроме атрибута данных $DATA являются резидентными. Что же касается атрибута данных $DATA, то его размер, составляющий 0x00000060 байт, явно недостаточен для хранения файла DataRecovery3.doc этой статьи (размер файла составляет несколько сотен Кбайт). И в самом деле, как Вы скоро увидите, атрибут $DATA хранит только номера кластеров, выделенных в разделе NTFS для хранения файла.

Заголовок атрибута файла

Как Вы уже знаете, в заголовке атрибута файлов хранится тип атрибута и размер выделенной для его хранения памяти. Вот полный список полей заголовка атрибута:

Смещение, байтРазмер, байтОписание
0x004Тип атрибута
0x044Размер области памяти, занимаемой атрибутом
0x081Флаг нерезидентного атрибута
0x091Длина имени атрибута
0x0A2Смещение области данных атрибута
0x0C2Флаг упакованного атрибута
0x0E2Идентификатор атрибута

Изучая содержимое поля флага нерезидентного атрибута (смещение 0x08 от начала атрибута) в дампе, показанном на рис. 9, можно заметить, что оно равно нулю для всех атрибутов, кроме атрибута $DATA. Таким образом, только этот атрибут является нерезидентным.

Поле со смещением 0x0C содержит флаг упакованного атрибута. Если этот флаг установлен, данные атрибута хранятся в упакованном или зашифрованном виде. Операционная система Microsoft Windows NT умела только упаковывать файлы. Что же касается Microsoft Windows 2000, то она дополнительно может шифровать файлы, причем данная операция выполняется совершенно прозрачно для пользователя.

В то время как извлечение упакованных файлов в процессе восстановления данных представляется нам вполне разрешимой задачей (с ней легко справляются наши утилиты EraseUndo for NTFS и CrashUndo 2000), восстановление зашифрованных файлов возможно только средствами самой операционной системы Microsoft Windows 2000. Но если разрушенный раздел невозможно смонтировать, то тогда проведение восстановительных работ становится проблематичным. Во всяком случае, нам ничего не известно о существовании каких-либо программ, способных это сделать.

Итак, первые 0x10 байт атрибута файла хранят заголовок фиксированного формата. Далее со смещением 0x10 начинается область данных атрибута, формат который различен для резидентных и нерезидентных атрибутов.

Область данных атрибута $STANDARD_INFORMATION

Атрибут $STANDARD_INFORMATION всегда резидентный. Как мы уже говорили, в нем записана дата и время создания и изменения файла, а также флаги доступа.

Ниже мы привели формат области данных атрибута $STANDARD_INFORMATION:

Смещение, байтРазмер, байтОписание
0x188Дата и время создания файла
0x208Дата и время последнего изменения файла
0x288Дата и время последнего изменения записи MFT данного файла
0x308Дата и время последнего доступа к файлу
0x384Флаги доступа
0x3С12Зарезервировано, содержит нулевые байты

Дата и время хранится как количество интервалов времени длительностью 100 нс, прошедших с 1 января 1601 года, причем здесь используется универсальное время UTC.

Для отбора нужных файлов в процессе восстановления данных Вы можете анализировать поля даты, однако для этого, скорее всего, придется написать небольшую программу. В этом Вам поможет следующий фрагмент кода, выполняющий преобразование даты NTFS в локальную системную дату и в текстовую строку (для сокращения листинга мы убрали обработку ошибок):

FILETIME ftLocalTime;
UINT64 qwTime;
SYSTEMTIME stSystemTime;
string sTime;
void FILE_TIME::ConvertToLocalSystemTime()
{
// Дата по Гринвичу. Конвертируем в местное время
FileTimeToLocalFileTime((CONST FILETIME *)&qwTime, &ftLocalTime);

// Конвертируем в системное время
FileTimeToSystemTime(&ftLocalTime, &stSystemTime);

// Конвертируем в текстовую строку
BYTE szDate[80];
wsprintf((char *)szDate, "%02d.%02d.%02d %02d:%02d", 
  stSystemTime.wMonth, stSystemTime.wDay, 
  stSystemTime.wYear, stSystemTime.wHour, stSystemTime.wMinute);
sTime = (char*)szDate;
}

Исходное значение находится в переменной qwTime. Данный метод применяется в программе автоматического восстановления данных CrashUndo 2000 и в программе восстановления стертых файлов EraseUndo for NTFS, созданных авторами этой статьи.

Что же касается флагов доступа, то они представляют собой набор отдельных битов, комбинируемых при помощи логической операции ИЛИ:

БитОписание
0x0001Для файла или каталога разрешено только чтение
0x0002Скрытый файл или каталог
0x0004Системный файл или каталог
0x0020Было выполнено архивирование файла
0x0400Символическая ссылка (Symbolic Link)
0x0800Упакованный файл или каталог

Первые четыре бита, приведенные выше, соответствуют обычным флагам, применявшимся в MS-DOS для управления доступом к файлам и каталогам. Что же касается символической ссылки и флага упаковки, то они специфичны для NTFS.

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

Область данных атрибута $FILE_NAME

Этот атрибут, так же как и только что рассмотренный атрибут $STANDARD_INFORMATION, всегда резидентный. Для каждого файла или каталога может быть создано несколько таких атрибутов, содержащих имена файла в разных пространствах имен (Filename spaces).

Здесь имеется в виду следующие пространства имен:

  • имена в стандарте POSIX;
  • имена в стандарте операционной системы Microsoft Windows;
  • имена в стандарте "8.3" операционной системы MS-DOS

В первом случае имена могут содержать любые символы кроме 0 и "/", в втором на эти символы накладываются дополнительные ограничения операционной системы Windows, а в третьем - ограничения MS-DOS.

Восстанавливая файл, Вы можете искать его в любом из перечисленных пространств имен.

Ниже мы привели формат области данных атрибута $FILE_NAME:

Смещение, байтРазмер, байтОписание
0x188Номер записи MFT для каталога, содержащего данный файл
0x208Дата и время создания файла
0x288Дата и время последнего изменения файла
0x308Дата и время последнего изменения записи MFT данного файла
0x388Дата и время последнего доступа к файлу
0x408Размер дискового пространства, использованного для хранения файла
0x488Реальная длина файла
0x508Флаги доступа
0x581Длина имени файла N
0x591Код пространства имени файла
0x5A2*NИмя файла. Это поле имеет длину 2*N, где N - длина имени файла из поля со смещением 0x50

Обратите внимание, что здесь дублируется информация о дате и времени и флаги доступа. Эти сведения присутствуют также и в стандартном атрибуте $STANDARD_INFORMATION. Если флаг доступа имеет значение 0x1000000, то данное имя - это имя каталога, а не файла.

В качестве примера определим расположение имени файла из атрибута $FILE_NAME, расположенного в записи MFT со смещением 0x0108 (рис. 9).

Исходя из только что приведенного формата атрибута $FILE_NAME, длина имени файла хранится в поле со смещением 0x0108+0x58=0x0160 и составляет 11 байт.

Код пространства имени расположен по адресу 0x0108+0x59=0x0161 и равен 1 (это пространство имен Microsoft Windows).

Что же касается самого имени файла, то оно располагается, начиная с адреса 0x0108+0x5A=0x0162, и занимает 0x11 двухбайтовых символов UNICODE до адреса 0x0162+(0x11*2)-1=0x183 включительно. В этом нетрудно убедиться, взглянув на рис. 9.

Вы можете самостоятельно проделать эти вычисления и для другого атрибута имени файла $FILE_NAME нашей записи MFT, расположенного со смещением 0x0090. Это имя принадлежит к пространству имен операционной системы MS-DOS.

Область данных атрибута $DATA

Теперь мы расскажем о том, как извлечь данные файла, расположение которых описано в атрибуте $DATA.

В зависимости от размера файла, он может быть расположен либо полностью внутри записи MFT (если файл небольшой), либо в кластерах раздела NTFS, выделенных для хранения файла. В первом случае атрибут данных $DATA и файл называются резидентными, а во втором - нерезидентными.

Резидентный атрибут $DATA

Формат области данных резидентного атрибута приведен ниже:

Смещение, байтРазмер, байтОписание
0x104Размер блока данных в байтах
0x142Смещение блока данных
0x162Флаг индексированного атрибута

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

На рис. 11 мы показали запись MFT для небольшого текстового файла, содержащего единственную строку "Small resident file". Имя файла - Samll28.txt.

Рис. 11. Файл, расположенный резидентно в записи MFT

Исследуя запись MFT, показанную на рис. 11, можно заметить, что она использовалась несколько раз. Действительно, вначале мы создали этот файл с именем New Text Document.txt, а затем переименовали его в Samll28.txt. В результате первый сектор записи MFT содержит следы старой информации. Эти старые данные не помешают нам извлечь файл, так как для доступа к нему мы будем прослеживать актуальную цепочку атрибутов. Расположение атрибута $DATA мы выделили на рис. 11 рамкой красного цвета.

Согласно приведенному выше формату резидентного атрибута $DATA, размер блока данных, выделенного для хранения файла, находится в поле с адресом 0x128+0x10=0x0138 и равен 0x13 байт. Это поле выделено на нашем рисунке рамкой зеленого цвета.

Аналогично, смещение блока данных хранится в слове со смещением 0x128+0x14=0x013C и равно 0x18. Соответствующее поле выделено на рис. 11 рамкой синего цвета. Таким образом, данные резидентного файла располагаются со смещением 0x128+0x18=0x0140.

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

Нерезидентный атрибут $DATA

Хранение данных резидентных файлов непосредственно в записях MFT увеличивает скорость доступа, однако, очевидно, для файлов большого размера этот способ хранения не подходит. Такие файлы хранятся на диске в отдельных кластерах, причем список кластеров, выделенных файлу, записывается в специальном формате в нерезидентный атрибут $DATA.

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

Процесс этот далеко не всегда прост, так как файл может храниться в упакованном или зашифрованном виде. Кроме того, у одного файла может быть несколько атрибутов $DATA. Эти атрибуты могут располагаться в главной записи MFT и в расширенных записях MFT одновременно.

В наших программах CrashUndo 2000 и EraseUndo for NTFS реализован весьма нетривиальный алгоритм извлечения нерезидентных файлов, работающий во всех возможных случаях (исключая зашифрованные файлы). Его детальное описание выходит за рамки данной статьи. Мы ограничимся только исследованием нерезидентного атрибута $DATA, полностью размещенного в главной записи MFT и созданного для неупакованных файлов.

Ниже мы привели формат области данных нерезидентного атрибута $DATA:

Смещение, байтРазмер, байтОписание
0x108Начальный номер VCN
0x188Конечный номер VCN
0x202Смещение списка экстентов Runlist
0x222Код метода упаковки атрибута
0x288Размер области данных, занимаемой файлом на диске
0x308Реальная длина файла
0x388Размер инициализированной области дисковой памяти, выделенной для хранения файла

Здесь нам интересны, прежде всего, поля смещения списка экстентов Runlist, метода упаковки атрибута, размеры областей данных, заказанной для атрибута и реально занимаемой атрибутом.

Список экстентов Runlist необходим нам для получения номеров кластеров раздела NTFS, выделенных для хранения восстанавливаемого файла. Каждый элемент данного списка описывает размер и расположение одного экстента (непрерывного фрагмента) файла.

Анализируя код метода упаковки файла, можно определить, является ли данный файл упакованным или нет. Если код равен 4, то файл может быть упакован или зашифрован (в случае Microsoft Windows 2000), а если он равен 0, то упаковка и шифрование не используется.

Реальная длина файла может быть получена из поля со смещением 0x30.

Рассмотрим практический пример. На рис. 12 мы показали дамп атрибута $DATA, взятого из записи MFT, показанной на рис. 9. Здесь мы применили корректировку, заменив значение шаблона корректировки 0x0002 в слове со смещением 0x01FE на исходное значение 0x700C (в соответствии с содержимым массива корректировки).

Рис. 12. Нерезидентный атрибут $DATA

Поле смещения списка Runlist выделено рамкой синего цвета и расположено в записи MFT со смещением 0x1B0+0x20=0x1D0. Там хранится значение 0x40 - смещение списка Runlist относительно начала атрибута $DATA.

Таким образом, список Runlist начинается с байта, имеющего смещение 0x1B0+0x40=0x1F0. Этот список выделен рамкой фиолетового цвета (о том, как определить конец списка Runlist, мы расскажем чуть позже).

Код метода упаковки находится в байте со смещением 0x1B0+0x22=0x1D2 и равен 0. Соответствующее поле выделено рамкой красного цвета. Таким образом, наш файл не упакован.

Реальный размер файла хранится в поле длинной 8 байт, которое расположено в записи MFT со смещением 0x1B0+0x30=0x1E0. Он равен 0x3EC00 байт в шестнадцатеричной или 257024 байт в десятичной системе счисления.

[Назад]