Может ли драйвер KMDF проверить, пришел ли IOCTL из процесса пользовательского режима с правами администратора?

Вопрос или проблема

Я работаю с образцом драйвера 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);
}

Важные моменты:

  1. Проверка токена: Мы используем ExOpenProcessToken для получения токена процесса и GetTokenInformation для определения, является ли процесс администратором.

  2. Обработка ошибок: Убедитесь, что вы обрабатываете все возможные ошибки, которые могут возникнуть при получении объекта процесса и токена.

  3. Закрытие дескрипторов: Всегда закрывайте дескрипторы токенов и освобождайте объекты процесса, чтобы избежать утечек памяти.

  4. Проверка прав доступа: Если процесс не является администратором, возвращайте код ошибки STATUS_ACCESS_DENIED.

С помощью данной реализации ваш драйвер сможет успешно проверять, был ли запрос на IOCTL отправлен из процесса с повышенными привилегиями.

Оцените материал
Добавить комментарий

Капча загружается...