Часть 2
Крис Касперски
В продолжение знакомства с файловой системой NTFS сегодня мы
сосредоточимся на строении атрибутов, исследовав их заголовок и механизмы
хранения нерезидентного тела на диске, а также покажем, как рассмотренные нами
структуры данных выглядят вживую в дисковом редакторе типа Disk Probe
или Sector Inspector.
Атрибуты
Структурно всякий атрибут состоит из заголовка (attribute header) и тела (attribute
body). Заголовок атрибута всегда хранится в файловой записи, расположенной
внутри MFT (см. первую часть статьи, «Файловые записи»). Тела резидентных
атрибутов хранятся там же. Нерезидентные атрибуты хранят свое тело вне MFT, в
одном или нескольких кластерах, перечисленных в заголовке данного атрибута в специальном
списке (см. «Списки отрезков»). Если 8-разрядное поле, расположенное по
смещению 08h байт от начала атрибутного заголовка, равно нулю, атрибут
считается резидентным, а если единице – то нет. Любые другие значения
недопустимы.
Первые четыре байта атрибутного заголовка
определяют его тип. Тип атрибута в свою очередь определяет формат представления
тела атрибута. В частности, тело атрибута данных (тип: 80h – $DATA)
представляет собой «сырую» последовательность байт. Тело атрибута стандартной
информации (тип: 10h – $STANDARD_INFORMATION) описывает время его
создания, права доступа и т. д. Подробнее см. «Типы атрибутов».
Следующие четыре байта заголовка содержат длину
атрибута, выражаемую в байтах. Длина нерезидентного атрибута равна сумме длин
его тела и заголовка, а длина резидентного атрибута равна длине его заголовка.
Короче говоря, если к смещению атрибута добавить его длину, мы получим
указатель на следующий атрибут (или маркер конца, если текущий атрибут –
последний в цепочке).
Длина тела резидентных атрибутов, выраженная в
байтах, хранится в 32-разрядном поле, расположенном по смещению 10h байт от
начала атрибутного заголовка. 16-разрядное поле, следующее за его концом,
хранит смещение резидентного тела, отсчитываемое от начала атрибутного заголовка.
С нерезидентными атрибутами в этом плане все
намного сложнее и для хранения длины их тела используется множество полей.
Реальный размер тела атрибута (real size of attribute), выраженный в байтах,
хранится в 64-разрядном (!) поле, находящемся по смещению 30h байт от
начала атрибутного заголовка. Следующее за ним 64-разрядное поле хранит
инициализированный размер потока (initialized data size of the stream),
выраженный в байтах и, судя по всему, всегда равный реальному размеру тела
атрибута. 64-разрядное поле, расположенное по смещению 28h байт от начала
атрибутного заголовка, хранит выделенный размер (allocated size of attribute),
выраженный в байтах и равный реальному размеру тела атрибута, округленному до
размера кластера (в большую сторону).
Два 64-разрядных поля, расположенные по смещению
10h и 18h байт от начала атрибутного заголовка, задают первый (starting VCN) и
последний (last VCN) номер виртуального кластера, принадлежащего телу
нерезидентного атрибута. Виртуальные кластеры представляют собой логические
номера кластеров, не зависящие от своего физического расположения на диске. В
подавляющем большинстве случав номер первого кластера тела нерезидентного
атрибута равен нулю, а последний – количеству кластеров, занятых телом
атрибута, уменьшенном на единицу. 16-разрядное поле, расположенное по смещению
20h от начала атрибутного заголовка, содержит указатель на массив Data Runs,
расположенный внутри этого заголовка и описывающий логический порядок
размещения нерезидентного тела атрибута на диске (подробнее см. «Списки
отрезков»).
Каждый атрибут имеет свой собственный
идентификатор (attribute ID), уникальный для данной файловой записи и
хранящийся в 16-разрядном поле, расположенном по смещению 0Eh от начала
атрибутного заголовка.
Если атрибут имеет имя (attribute Name), то
16-разрядное поле, расположенное по смещению 0Ah байт от атрибутного заголовка,
содержит указатель на него. Для безымянных атрибутов оно равно нулю (а
большинство атрибутов безымянны!). Имя атрибута хранится в атрибутном заголовке
в формате UNICODE, а его длина определяется 8-разрядным полем, расположенным по
смещению 09h байт от начала атрибутного заголовка.
Если тело атрибута сжато, зашифровано или
разряжено, 16-разрядное поле флагов, расположенное по смещению 0Ch байт от
начала атрибутного заголовка, не равно нулю.
Остальные поля не играют сколь-нибудь
существенной роли и потому здесь не рассматриваются.
Таблица 1. Структура
резидентного атрибута
|
Смещение
|
Размер
|
Значение
|
Описание
|
|
00h
|
4
|
|
Тип (type) атрибута (например, 0x10, 0x60, 0xB0)
|
|
04h
|
4
|
|
Длина атрибута,
включая этот заголовок
|
|
08h
|
1
|
00h
|
Нерезидентный флаг
(non-resident flag)
|
|
09h
|
1
|
N
|
Длина имени
атрибута (ноль, если атрибут безымянный)
|
|
0Ah
|
2
|
18h
|
Смещение имени (ноль,
если атрибут безымянный)
|
|
0Ch
|
2
|
00h
|
Флаги
|
|
Значение
|
Описание
|
|
0001h
|
Сжатый атрибут (compressed)
|
|
4000h
|
Зашифрованный
атрибут (encrypted)
|
|
8000h
|
Разряженный атрибут
(sparse)
|
|
0Eh
|
2
|
|
Идентификатор
атрибута (attribute ID)
|
|
10h
|
4
|
L
|
Длина тела
атрибута, без заголовка
|
|
14h
|
2
|
2N+18h
|
Смещение тела
атрибута
|
|
16h
|
1
|
|
Индексный флаг
|
|
17h
|
1
|
00h
|
Для выравнивания
|
|
18h
|
2N
|
UNICODE
|
Имя атрибута (если
есть)
|
|
2N+18h
|
L
|
|
Тело атрибута
|
Таблица 2. Структура
нерезидентного атрибута
|
Смещение
|
Размер
|
Значение
|
Описание
|
|
00h
|
4
|
|
Тип (type) атрибута
(например, 0x20, 0x80)
|
|
04h
|
4
|
|
Длина атрибута,
включая этот заголовок
|
|
08h
|
1
|
01h
|
Нерезидентный флаг
(non-resident flag)
|
|
09h
|
1
|
N
|
Длина имени
атрибута (ноль, если атрибут безымянный)
|
|
0Ah
|
2
|
40h
|
Смещение имени (ноль,
если атрибут безымянный)
|
|
0Ch
|
2
|
|
Флаги
|
|
Значение
|
Описание
|
|
0001h
|
Сжатый атрибут (compressed)
|
|
4000h
|
Зашифрованный
атрибут (encrypted)
|
|
8000h
|
Разряженный атрибут
(sparse)
|
|
0Eh
|
2
|
|
Идентификатор
атрибута (attribute ID)
|
|
10h
|
8
|
|
Начальный
виртуальный кластер (starting VCN)
|
|
18h
|
8
|
|
Конечный
виртуальный кластер (last VCN)
|
|
20h
|
2
|
2N+40h
|
Смещение списка
отрезков (data runs)
|
|
22h
|
2
|
|
Размер блока сжатия
(compression unit size), округленный до 4 байт вверх
|
|
24h
|
4
|
00h
|
Для выравнивания
|
|
28h
|
8
|
|
Выделенный размер (allocated
size), округленный до размера кластера
|
|
30h
|
8
|
|
Реальный размер (real
size)
|
|
38h
|
8
|
|
Инициализированный размер
потока (initialized data size of the stream)
|
|
40h
|
2N
|
UNICODE
|
имя атрибута если
есть
|
|
2N+40h
|
..
|
|
Список отрезков (data
runs)
|
Типы атрибутов
NTFS поддерживает большее количество предопределенных типов атрибутов,
перечисленных в таблице 3. Как уже говорилось выше, тип атрибута
определяет его назначение и формат представления тела. Полное описание всех
атрибутов заняло бы очень много места и поэтому здесь приводятся лишь наиболее
«ходовые» из них, а за информацией об остальных обращайтесь к Linux-NTFS Project.
Таблица 3. Основные
типы атрибутов
|
Значение
|
ОС
|
Условное
обозначение
|
Описание
|
|
010h
|
любая
|
$STANDARD_INFORMATION
|
Стандартная
информация о файле (время, права доступа)
|
|
020h
|
любая
|
$ATTRIBUTE_LIST
|
Список атрибутов
|
|
030h
|
любая
|
$FILE_NAME
|
Полное имя файла
|
|
040h
|
NT
|
$VOLUME_VERSION
|
Версия тома
|
|
040h
|
2K
|
$OBJECT_ID
|
Уникальный GUID и прочие ID
|
|
050h
|
любая
|
$SECURITY_DESCRIPTOR
|
Дескриптор
безопасности и списки прав доступа (ACL)
|
|
060h
|
любая
|
$VOLUME_NAME
|
Имя тома
|
|
070h
|
любая
|
$VOLUME_INFORMATION
|
Информация о томе
|
|
080h
|
любая
|
$DATA
|
Основные данные
файла
|
|
090h
|
любая
|
$INDEX_ROOT
|
Корень индексов
|
|
0A0h
|
любая
|
$INDEX_ALLOCATION
|
Ветви (sub-nodes) индекса
|
|
0B0h
|
любая
|
$BITMAP
|
Карта свободного
пространства
|
|
0C0h
|
NT
|
$SYMBOLIC_LINK
|
Символическая связь
|
|
0C0h
|
2K
|
$REPARSE_POINT
|
Для сторонних
производителей
|
|
0D0h
|
любая
|
$EA_INFORMATION
|
Расширенные
атрибуты для HPFS
|
|
0E0 h
|
любая
|
$EA
|
Расширенные
атрибуты
для HPFS
|
|
0F0h
|
NT
|
$PROPERTY_SET
|
Устарело и ныне не
используется
|
|
100h
|
2K
|
$LOGGED_UTILITY_STREAM
|
Используется
шифрованной файловой системой (EFS)
|
Атрибут стандартной информации
$STANDARD_INFORMATION
Атрибут стандартной информации описывает время создания/изменения/последнего
доступа к файлу и права доступа, а также некоторую другую вспомогательную
информацию (например, квоты):
Таблица 4. Структура
атрибута $STANDARD_INFORMATION
|
Смещение
|
Размер
|
ОС
|
Описание
|
|
~ ~
|
|
любая
|
Стандартный
атрибутный заголовок (standard attribute header)
|
|
|