Объекты типа
Заголовки объектов содержат данные, общие для всех объектов, которые могут принимать различные значения для каждого экземпляра объекта. Например, у каждого объекта есть уникальное имя и может быть уникальный дескриптор безопасности.
Но объекты также содержат некоторые данные, которые остаются постоянными для всех объектов конкретного типа. Например, при открытии дескриптора объекта определенного типа можно выбрать права доступа из набора, присущего этому типу объектов. Исполняющая система предоставляет для объектов типа поток кроме всех прочих доступ к завершению и приостановке, а для объектов типа файл доступ для чтения, записи, добавления и удаления.
Еще одним примером атрибута, присущего определенному типу объектов, является синхронизация, которая вскоре будет рассмотрена.
Для экономии памяти диспетчер объектов сохраняет эти статические атрибуты, присущие объектам определенного типа, единожды при создании нового объекта типа. Для записи этих данных он использует свой собственный объект, так называемый объект типа. Как показано на рисунке, если установлен флаг отладки для отслеживания объектов (рассматриваемый далее в разделе «Глобальные флаги Windows»), объект типа также связывает вместе все объекты одного и того же типа (в данном случае типа процесс), позволяя диспетчеру объектов находить эти объекты и вести их подсчет, если это необходимо. Эта функция использует возможность ранее рассмотренного подзаголовка с информацией о создателе.
Из пользовательского режима работать с объектами типа нельзя, поскольку диспетчер объектов не предоставляет для них никаких служб. Тем не менее некоторые, определяемые ими атрибуты, видимы с помощью некоторых собственных служб операционной системы и процедур Windows API. Информация, хранящаяся в инициализаторах типа, описана в таблице.
Поля инициализаторов типа.
Атрибут | Назначение |
---|---|
Type name (Имя типа) | Имя объектов данного типа («процесс», «событие», «порт» и т. д.) |
Pool type (Тип пула) | Показывает, может ли объектам данного типа выделяться выгружаемая или невыгружаемая память |
Default quota charges (Квота по умолчанию) | Значения пулов выгружаемой и невыгружаемой памяти, составляющие по умолчанию квоту процесса. |
Valid access mask (Действующая маска доступа) | Виды доступа, которые поток может запросить при открытии дескриптора объекта данного типа («чтение», «запись», «завершение», «приостановка» и т. д.) |
Generic access rights mapping (Отображение общих прав доступа) | Отображение четырех общих прав доступа (для чтения, записи, выполнения и всех прав) на права доступа, присущие конкретному типу |
Flags (Флаги) | Указывают на то, что объекты не должны иметь имен (например, в случае с объектами типа «процесс»), что в их именах учитывается регистр символов, что они требуют наличие дескриптора безопасности, что они поддерживают обратные вызовы, фильтруемые объектами, и должна ли поддерживаться база данных дескрипторов (подзаголовок информации о дескрипторах) и (или) взаимозависимость списка типов (подзаголовок информации о создателе). Флаг use default object также определяет поведение показанного далее в этой таблице поля default object |
Object type code (Код объекта типа) | Используется для описания того, что из себя представляет тип объекта (в отличие от сравнения с известным значением имени). Для файловых объектов значение этого поля устанавливается в 1, для объектов синхронизации — в 2 и для объектов потоков — в 4. Это поле также используется ALPC для хранения информации об атрибуте дескриптора, связанной с сообщением |
Invalid attributes (Недопустимые атрибуты) | Задает флаги атрибутов объекта, недопустимые для этого типа объекта |
Default object (Объект по умолчанию) | Определяет внутреннее событие диспетчера объектов, которое должно использоваться при ожидании данного объекта, если этого требует создатель объекта типа. Следует учесть, что такие объекты, как File и ALPC-порт, уже содержат свой встроенный диспетчер объектов; в таком случае это поле является смещением в теле объекта. Например, событие внутри структуры FILE_OBJECT встроено в поле под названием Event |
Methods (Методы) | Одна или несколько процедур, вызываемых диспетчером объектов автоматически в определенные моменты жизни объекта |
Просмотр заголовков объектов и объектов типа.
Структуру данных объекта типа «процесс» можно увидеть в отладчике ядра, предварительно идентифицировав этот объект с помощью команды !process:
lkd> !process 0 0
**** NT ACTIVE PROCESS DUMP ****
PROCESS fffffa800279cae0
SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000
DirBase: 00187000 ObjectTable: fffff8a000001920 HandleCount: 541.
Image: System
Выполните команду !object с адресом объекта «процесс» в качестве аргумента:
lkd> !object fffffa800279cae0
Object: fffffa800279cae0 Type: (fffffa8002755b60) Process
ObjectHeader: fffffa800279cab0 (new version)
HandleCount: 3 PointerCount: 172 3172
Учтите, что на 32-разрядной версии Windows заголовок объекта начинается с 0x18 (24 в десятичном формате) байт, предшествующих телу объекта, а на 64-разрядной версии Windows он начинается с 0x30 (48 в десятичном формате) байт, предшествующих телу, то есть с размера самого заголовка объекта. Просмотреть заголовок объекта можно с помощью следующей команды:
lkd> dt nt!_OBJECT_HEADER fffffa800279cab0
+0x000 PointerCount : 172
+0x008 HandleCount : 33
+0x008 NextToFree : 0x000000000x00000000'00000003
+0x010 Lock : _EX_PUSH_LOCK
+0x018 TypeIndex : 0x7 ''
+0x019 TraceFlags : 0 ''
+0x01a InfoMask : 0 ''
+0x01b Flags : 0x2 ''
+0x020 ObjectCreateInfo : 0xfffff800'01c53a80 _OBJECT_CREATE_INFORMATION
+0x020 QuotaBlockCharged : 0xfffff800'01c53a80
+0x028 SecurityDescriptor: 0xfffff8a0'00004b29
+0x030 Body : _QUAD
Теперь посмотрим на структуру данных объекта типа, получив его адрес из таблицы ObTypeIndexTable, указанный в записи, связанной с полем TypeIndex структуры данных заголовка объекта:
lkd> ?? ((nt!_OBJECT_TYPE**)@@(nt!ObTypeIndexTable))[((nt!_OBJECT_
HEADER*)0xfffffa800279cab0)->TypeIndex]
struct _OBJECT_TYPE * 0xfffffa80'02755b60
+0x000 TypeList : _LIST_ENTRY [ 0xfffffa80'02755b60 - 0xfffffa80'02755b60
]
+0x010 Name : _UNICODE_STRING "Process"
+0x020 DefaultObject : (null)
+0x028 Index : 0x70x7 ''
+0x02c TotalNumberOfObjects : 0x380x38
+0x030 TotalNumberOfHandles : 0x1320x132
+0x034 HighWaterNumberOfObjects : 0x3d
+0x038 HighWaterNumberOfHandles : 0x13c
+0x040 TypeInfo : _OBJECT_TYPE_INITIALIZER
+0x0b0 TypeLock : _EX_PUSH_LOCK
+0x0b8 Key : 0x636f7250
+0x0c0 CallbackList : _LIST_ENTRY [ 0xfffffa80'02755c20 - 0xfffffa80'02755c20 ]
В выведенной информации показано, что структура объекта типа включает имя объекта типа, в ней отслеживается общее количество активных объектов этого типа и пиковое количество дескрипторов и объектов данного типа. В поле CallbackList также отслеживается фильтрация обратных вызовов диспетчера объектов, связанная с этим объектом типа.
В поле TypeInfo хранится указатель на структуру данных, в которой хранятся общие для всех объектов этого типа атрибуты, а также указатели на методы объекта типа:
lkd> ?? ((nt!_OBJECT_TYPE*)0xfffffa8002755b60)->TypeInfo*)0xfffffa8002755b60)->TypeInfo
+0x000 Length : 0x70
+0x002 ObjectTypeFlags : 0x4a 'J'
+0x002 CaseInsensitive : 0y0
+0x002 UnnamedObjectsOnly : 0y1
+0x002 UseDefaultObject : 0y0
+0x002 SecurityRequired : 0y1
+0x002 MaintainHandleCount : 0y0
+0x002 MaintainTypeList : 0y0
+0x002 SupportsObjectCallbacks : 0y1
+0x004 ObjectTypeCode : 0
+0x008 InvalidAttributes : 0xb0
+0x00c GenericMapping : _GENERIC_MAPPING
+0x01c ValidAccessMask : 0x1fffff
+0x020 RetainAccess : 0x101000
+0x024 PoolType : 0 ( NonPagedPool )
+0x028 DefaultPagedPoolCharge : 0x1000
+0x02c DefaultNonPagedPoolCharge : 0x528
+0x030 DumpProcedure : (null)
+0x038 OpenProcedure : 0xfffff800'01d98d58 long nt!PspProcessOpen+0
+0x040 CloseProcedure : 0xfffff800'01d833c4 void nt!PspProcessClose+0
+0x048 DeleteProcedure : 0xfffff800'01d83090 void nt!PspProcessDelete+0
+0x050 ParseProcedure : (null)
+0x058 SecurityProcedure : 0xfffff800'01d8bb50 long nt!SeDefaultObjectMethod+0
+0x060 QueryNameProcedure : (null)
+0x068 OkayToCloseProcedure : (null)
Синхронизация, являющаяся одним из атрибутов, видимых приложениями Windows, относится к способности потоков синхронизировать их выполнение путем ожидания перехода объекта из одного состояния в другое. Поток может синхронизироваться с объектами выполняемого задания, процесса, потока, файла, семафора, мьютекса и таймера. Все остальные объекты исполняющей системы синхронизацию не поддерживают. Способность объекта поддерживать синхронизацию основана на трех возможностях:
- Объект исполняющей системы является оболочкой для объекта-диспетчера и содержит заголовок диспетчера.
- Создатель объекта типа требует объект по умолчанию, и диспетчер объектов предоставляет такой объект.
- Объект исполняющей системы имеет встроенный диспетчер объектов, такой как событие, где-нибудь внутри тела объекта, и владелец объекта предоставляет смещение на него диспетчеру объектов при регистрации объекта типа.