Вопрос или проблема
Я работаю с образцом драйвера KMDF (режим ядра), который пришел с VS 2022.
Я добавил следующий код для обработки IOCTL в моем Queue.c
:
VOID
TestEvtIoDeviceControl(
_In_ WDFQUEUE Queue,
_In_ WDFREQUEST Request,
_In_ size_t OutputBufferLength,
_In_ size_t InputBufferLength,
_In_ ULONG IoControlCode
)
{
NTSTATUS status = STATUS_SUCCESS;
if(IoControlCode == IOCTL_MY_TEST)
{
REQ_TEST* pReq = NULL;
size_t szcbRead = 0;
status = WdfRequestRetrieveInputBuffer(Request, sizeof(*pReq), &pReq, &szcbRead);
if(NT_SUCCESS(status) &&
szcbRead == sizeof(*pReq))
{
//Обработка данных, полученных в pReq ...
}
}
WdfRequestComplete(Request, status);
}
где:
#define IOCTL_MY_TEST CTL_CODE(0x8000, 0x800, METHOD_BUFFERED, FILE_WRITE_ACCESS)
typedef struct _REQ_TEST
{
ULONG Param1;
int Param2;
}REQ_TEST, *PREQ_TEST;
Вопрос в том, могу ли я узнать, выполняется ли процесс в пользовательском режиме, отправляющий мой IOCTL_MY_TEST
IOCTL, как член встроенной группы администраторов, и если нет, то предотвратить обработку этого запроса IOCTL?
Ответ или решение
Ваша задача заключается в том, чтобы определить, запрашивается ли IOCTL из пользовательского режима, и если это так, проверить, принадлежит ли процесс, который его отправил, к группе администраторов.
Для реализации этого в драйвере KMDF вы можете использовать функцию PsLookupProcessByProcessId
, чтобы получить дескриптор процесса по его идентификатору, а затем проверить его токен для определения принадлежности к группе администраторов.
Вот пример того, как можно реализовать эту логику в функции TestEvtIoDeviceControl
:
#include <ntddk.h> // Включите необходимый заголовочный файл для работы с токенами
VOID
TestEvtIoDeviceControl(
_In_ WDFQUEUE Queue,
_In_ WDFREQUEST Request,
_In_ size_t OutputBufferLength,
_In_ size_t InputBufferLength,
_In_ ULONG IoControlCode
)
{
NTSTATUS status = STATUS_SUCCESS;
if(IoControlCode == IOCTL_MY_TEST)
{
HANDLE processId = PsGetProcessId(WdfRequestGetProcess(Request)); // Получаем ID процесса
PEPROCESS process = NULL;
// Ищем процесс по его ID
status = PsLookupProcessByProcessId(processId, &process);
if (NT_SUCCESS(status) && process != NULL)
{
HANDLE token = NULL;
status = ExOpenProcessToken(process, TOKEN_QUERY, &token);
if (NT_SUCCESS(status) && token != NULL)
{
TOKEN_ELEVATION tokenElevation;
ULONG length;
// Проверяем, является ли процесс администратором
if (GetTokenInformation(token, TokenElevation, &tokenElevation, sizeof(tokenElevation), &length))
{
if (tokenElevation.TokenIsElevated)
{
// Процесс является администратором, продолжаем обработку...
REQ_TEST* pReq = NULL;
size_t szcbRead = 0;
status = WdfRequestRetrieveInputBuffer(Request, sizeof(*pReq), &pReq, &szcbRead);
if (NT_SUCCESS(status) && szcbRead == sizeof(*pReq))
{
// Обработка данных из pReq...
}
}
else
{
// Запретить выполнение, если токен не является администраторским
status = STATUS_ACCESS_DENIED;
}
}
ZwClose(token); // Закрываем дескриптор токена
}
ObDereferenceObject(process); // Освобождаем объект процесса
}
}
WdfRequestComplete(Request, status);
}
Важные моменты:
-
Проверка токена: Мы используем
ExOpenProcessToken
для получения токена процесса иGetTokenInformation
для определения, является ли процесс администратором. -
Обработка ошибок: Убедитесь, что вы обрабатываете все возможные ошибки, которые могут возникнуть при получении объекта процесса и токена.
-
Закрытие дескрипторов: Всегда закрывайте дескрипторы токенов и освобождайте объекты процесса, чтобы избежать утечек памяти.
-
Проверка прав доступа: Если процесс не является администратором, возвращайте код ошибки
STATUS_ACCESS_DENIED
.
С помощью данной реализации ваш драйвер сможет успешно проверять, был ли запрос на IOCTL отправлен из процесса с повышенными привилегиями.