Иллюстрированный самоучитель по программированию систем защиты

Рабочие потоки

Создание потоков драйвером

В случае, когда использование системных рабочих потоков невозможно, драйвер должен создать свой собственный поток. Для создания нового потока используется функция PsCreateSystemThread(). В качестве одного из параметров функция имеет описатель процесса, в контексте которого нужно создать поток. Чтобы правильно использовать описатель, код драйвера должен выполняться в контексте процесса, таблица описателей которого содержит описатель процесса, в контексте которого мы хотим создать поток. Если описатель процесса не указан (значение NULL), новый поток будет создан в контексте процесса System.

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

Вновь созданный поток будет работать на уровне IRQL PASSIVE_LEVEL и иметь базовое значение приоритета планирования равным 8 (динамический диапазон приоритетов, базовое значение для класса NORMAL). После создания код потока может изменить базовое значение приоритета планирования на любое значение в диапазоне динамических приоритетов либо приоритетов реального времени. Это делается с помощью функции KeSetPriorityThread(). Отметим, что это не повышение уровня приоритета планирования, после которого уровень приоритета постепенно снизится до базового значения, а именно установка нового базового значения приоритета.

Код потока может не только изменить значение приоритета планирования при уровне IRQL PASSIVE_LEVEL, но и повысить уровень IRQL. Для этого служит функция KeRaiselrql(). Работа потока на повышенном уровне IRQL должна быть завершена как можно скорее, после чего должно быть восстановлено первоначальное значение IRQL с помощью функции KeLowerlrql(). Использование функции KeRaiselrql() для понижения IRQL и функции KeLowerlrql() для повышения IRQL не допускается, так как это приведет к возникновению синего экрана.

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

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

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);
Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.