Восстановление данных в разделах 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 также начинаются с загрузочного сектора. Ниже мы привели формат начальной области загрузочного сектора:
Если Вы создаете собственные программы для работы с разделами 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 и выберите из меню 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, то для жестких дисков он обычно равен 512 байт. Другие носители данных (компакт-диски и магнитооптические диски могут использовать иные размеры сектора, такие как 1024 или 2048 байт). Размер кластераВажная составляющая геометрии NTFS -размер кластера Sectors per Cluster. Этот размер устанавливается при форматировании раздела и зависит от его объема. В тех случаях, когда содержимое загрузочного сектора NTFS утеряно, можно воспользоваться следующей таблицей зависимости размера кластера от объема раздела NTFS:
Эта таблица справедлива для операционной системы Microsoft Windows NT версии 3.51, 4.0 и Microsoft Windows 2000. Что же касается более старых версий Microsoft Windows NT, то в них применялись кластеры и таких размеров:
Заметим, что при форматировании разделов 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 описывают системные файлы, перечисленные ниже:
Далее в файле $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 атрибутов файла различного типа. Типы атрибута обозначается числами. Ниже мы перечислили атрибуты известных нам типов с кратким описанием хранящейся в них информации.
Для восстановления файлов из разрушенных разделов 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:
Изучать заголовок записи 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 для хранения файла. Заголовок атрибута файлаКак Вы уже знаете, в заголовке атрибута файлов хранится тип атрибута и размер выделенной для его хранения памяти. Вот полный список полей заголовка атрибута:
Изучая содержимое поля флага нерезидентного атрибута (смещение 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:
Дата и время хранится как количество интервалов времени длительностью 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, созданных авторами этой статьи. Что же касается флагов доступа, то они представляют собой набор отдельных битов, комбинируемых при помощи логической операции ИЛИ:
Первые четыре бита, приведенные выше, соответствуют обычным флагам, применявшимся в MS-DOS для управления доступом к файлам и каталогам. Что же касается символической ссылки и флага упаковки, то они специфичны для NTFS. Анализируя эти флаги в процессе восстановления данных, Вы можете пропускать скрытые или системные файлы, не представляющие в большинстве случаев особого интереса. Область данных атрибута $FILE_NAMEЭтот атрибут, так же как и только что рассмотренный атрибут $STANDARD_INFORMATION, всегда резидентный. Для каждого файла или каталога может быть создано несколько таких атрибутов, содержащих имена файла в разных пространствах имен (Filename spaces). Здесь имеется в виду следующие пространства имен:
В первом случае имена могут содержать любые символы кроме 0 и "/", в втором на эти символы накладываются дополнительные ограничения операционной системы Windows, а в третьем - ограничения MS-DOS. Восстанавливая файл, Вы можете искать его в любом из перечисленных пространств имен. Ниже мы привели формат области данных атрибута $FILE_NAME:
Обратите внимание, что здесь дублируется информация о дате и времени и флаги доступа. Эти сведения присутствуют также и в стандартном атрибуте $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Формат области данных резидентного атрибута приведен ниже:
Здесь наиболее интересны поля размера блока данных и смещения блока данных, так как именно они позволяют извлечь данные резидентного атрибута. На рис. 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:
Здесь нам интересны, прежде всего, поля смещения списка экстентов 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 байт в десятичной системе счисления. |