Иллюстрированный самоучитель по Pogramming Sistem Security


Потоки как диспетчерские объекты


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

NTSTATUS DriverEntry( .... )

status = PsCreateSystemThread(&thread_handle,

0,

NULL,

0,

NULL,

thread_func,

pDevExt~>thread_context) ; if (status != STATUS_SUCCESS)

{

//обработка ошибки } else

{

status = ObReferenceobjectByHandle (thread_handle, THREAD_ALL_ACCESS, NULL,

KernelMode,

(PVOID*) &pDevExt->pThreadObject, NULL) ; if (status != STATUS_SUCCESS)

{ ' ' ': ' " ' ' ' ' '

//обработка ошибки

Функция потока:

VOID thread_func(PVOID Context)

{ ' ' ' '; , ' -

//Рабочий код потока

//Завершение потока PsTerminateSystemThread'(STATUS_SUCCESS) ;

Функция, ожидающая завершение работы потока: .... SomeFunc( .... )

status = KeWaitForSingleObject (pDevExt->pThreadObject,

Executive,

KernelMode,

FALSE ,

NULL) ; ObDereferenceObject (pDevExt->pThreadObject) ;

Прокомментируем этот пример. При создании потока с помощью функции PsCreateSystemThread() возвращается описатель потока в контексте процесса, в котором поток был создан. Важно понимать, что это может быть совершенно не тот процесс, в контексте которого была вызвана функция PsCreateSystem Thread(). В этом случае мы не можем напрямую воспользоваться функцией ObReference ObjectByHandle() для получения указателя на объект-поток по его описателю.

Существует простейший способ решения этой проблемы, основанный на том факте, что функция - точка входа в драйвер DriverEntry, всегда вызывается в контексте потока System. Вызов функции PsCreateSystemThread() следует производить из DriverEntry, и при этом указывать создавать поток в контексте процесса System. Получив описатель созданного потока, можно получить указатель на объект-поток с помощью ObReferenceObjectByHandle(), и в дальнейшем пользоваться этим указателем в контексте любого процесса и потока. При завершении использования объекта-потока надо обязательно освободить его с помощью вызова ObDereferenceObject(). Все вышесказанное иллюстрируется рис. 13.

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

Вышесказанное относилось только к ОС Windows NT 4.0. В ОС Win2000 появилась специальная таблица описателей, называемая таблицей описателей ядра (kernel handle table), которая может быть доступна с помощью экспортируемого имени ObpKernelHandleTable. Таблица доступна только из режима ядра, при этом у всех описателей старший бит установлен в 1, так что значения всех описателей превышают 0x80000000. Как быть с уникальностью описателей для каждого процесса, на момент написания данной книги неясно и нуждается в исследовании.

Рис. 13




- Начало -  - Назад -  - Вперед -



Книжный магазин