Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
BYOVD-DriverKiller — Driver Reverse & Exploitation | Kitploit
Инструменты/GitHubGitHub/alex3o/byovd-driverkiller
ExploitationReverse EngineeringPost-ExploitationBinary AnalysisLearning & EducationRed Teaming
GitHubalex3o/byovd-driverkiller

BYOVD-DriverKiller

Driver Reverse & Exploitation

Репозиторий
831411 месяцев назадПроверено Kitploit

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

BYOVD-DriverKiller

⚠️ Предупреждение: Этот проект носит строго образовательный и демонстрационный характер. Он не предназначен для использования в вредоносных целях. Цель — изучить методологию reverse engineering и этапы эксплуатации Windows-драйвера.


Здесь я объясняю подход, который я использовал для решения упражнения, предложенного d1rk(SaadAhla) https://github.com/SaadAhla, а именно reverse engineering и эксплуатацию легитимного подписанного драйвера, отсутствующего в блок-листах (HVCI, LOLBIN...). Доступна программа на C, позволяющая завершить любой активный процесс в системе через этот драйвер режима ядра (Kernel-mode Driver); ниже я подробно описываю, как она работает.

POC-BYOD

📃 Использование: DriverKiller.exe <nom_processus.exe> [-d]

Опция -d: позволяет удалить службу и драйвер из системы после эксплуатации.

На целевой машине должен быть включён режим тестовой подписи (testsigning mode), так как сертификат драйвера истёк.


Часть 1 — Reverse engineering:

В упражнении предоставляется файл .sys, названный по его SHA-256 хешу. Первый шаг — открыть этот файл в IDA.
IDA доступна бесплатно. Достаточно зайти на сайт Hex-Rays, чтобы сгенерировать лицензию и скачать программу.

Начнём с просмотра IAT (Import Address Table) драйвера и поищем вызов нужного API: ZwTerminateProcess.

screen1-git

Двойным щелчком по ZwTerminateProcess IDA перенаправляет нас к скомпилированному коду этой функции. Выбрав запись и открыв перекрёстные ссылки (cross-references), мы получаем список функций драйвера, которые её вызывают.

screen2-git

Мы видим, что именно функция sub_12EF4, по смещению 1CE, использует ZwTerminateProcess. После двойного щелчка IDA показывает её скомпилированный код.

screen11-git

Декомпилированный код показывает вызовы ZwOpenProcess (открывает дескриптор целевого процесса) и ZwTerminateProcess (завершает процесс через этот дескриптор).

Согласно документации ZwOpenProcess (https://learn.microsoft.com/fr-fr/windows-hardware/drivers/ddi/ntddk/nf-ntddk-zwopenprocess), параметр ClientID — это указатель, задающий PID целевого процесса.

В строке выше ClientId.UniqueProcess инициализируется переменной v22. Она определена чуть выше:

root@kitploit:~
v22 = (void )((_QWORD *)i + 10);

Чтобы понять это присваивание, нужно определить переменную i и поле +10.

Выше в этой функции виден вызов ZwQuerySystemInformation с параметром SYSTEM_PROCESS_INFORMATION. Также становится понятно, что i — итератор по записям этой структуры вместе с переменной v6.

Согласно документации ZwQuerySystemInformation (https://learn.microsoft.com/en-us/windows/win32/sysinfo/zwquerysysteminformation), эта функция возвращает массив с одной записью на каждый активный процесс в системе.

Структура SYSTEM_PROCESS_INFORMATION описана здесь: https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntquerysysteminformation

root@kitploit:~
typedef struct _SYSTEM_PROCESS_INFORMATION {
    ULONG NextEntryOffset;
    ULONG NumberOfThreads;
    BYTE Reserved1[48];
    UNICODE_STRING ImageName;
    KPRIORITY BasePriority;
    HANDLE UniqueProcessId;
    PVOID Reserved2;
    ULONG HandleCount;
    ULONG SessionId;
    PVOID Reserved3;
    SIZE_T PeakVirtualSize;
    SIZE_T VirtualSize;
    ULONG Reserved4;
    SIZE_T PeakWorkingSetSize;
    SIZE_T WorkingSetSize;
    PVOID Reserved5;
    SIZE_T QuotaPagedPoolUsage;
    PVOID Reserved6;
    SIZE_T QuotaNonPagedPoolUsage;
    SIZE_T PagefileUsage;
    SIZE_T PeakPagefileUsage;
    SIZE_T PrivatePageCount;
    LARGE_INTEGER Reserved7[6];
} SYSTEM_PROCESS_INFORMATION;

Напоминание: размеры некоторых типов в Windows x64

  • ULONG = 4 байта
  • USHORT = 2 байта
  • HANDLE = 8 байт
  • PWSTR = 8 байт
  • KPRIORITY (typedef от LONG) = 4 байта
  • UNICODE_STRING = 16 байт, потому что вот её структура:
root@kitploit:~
  typedef struct _UNICODE_STRING {
    USHORT Length;        -> 2      
    USHORT MaximumLength; -> + 2 = 4
    PWSTR  Buffer;        -> + 8 = 12 (12 n'est pas un multiple de 8 donc padding de 4 ajouté en amont de Buffer) = 16
} UNICODE_STRING;

Расчёт смещения UniqueProcessId:

root@kitploit:~
    ULONG NextEntryOffset;        -> 4
    ULONG NumberOfThreads;        -> + 4 = 8
    BYTE Reserved1[48];           -> + 48 = 56
    UNICODE_STRING ImageName;     -> + 16 = 72
    KPRIORITY BasePriority;       -> + 4 = 76 (76 n'est pas un multiple de 8 donc padding de 4 ajouté) = 80
    HANDLE UniqueProcessId;       -> + 8 = 88

Член UniqueProcessId находится по смещению 0x50 (80 в десятичной системе).

Глядя на присваивание переменной v22, видно, что i приводится к указателю QWORD (8 байт):

root@kitploit:~
v22 = (void )((_QWORD *)i + 10);
Таким образом, v22 соответствует адресу i + 10 * 8 = 80 байт. Эта переменная действительно содержит PID, полученный из структуры SYSTEM_PROCESS_INFORMATION.

Чтобы узнать, какой PID будет передан в ZwTerminateProcess, нужно проанализировать условие, окружающее это присваивание.

screen4-git

Видно, что сначала извлекается имя образа процесса:

root@kitploit:~
v9 = (wchar_t )((_QWORD *)i + 8);
Так как v9 = адрес i + 8 × 8 = 64 байта. Это соответствует полю Buffer члена ImageName, поскольку этот член находится по смещению 56 + 2 (USHORT) + 2 (USHORT) + 4 (padding) = 64.

Судя по операциям и циклам ниже, можно предположить, что выполняется сравнение имени процесса, переданного аргументом (a2), с активными процессами системы v9/String.

root@kitploit:~
sub_1C078(String, v9, (int)v13);
v17 = strupr(a2);
v18 = strupr(String);

Значит, параметр a2 должен содержать имя процесса, который нужно завершить через ZwTerminateProcess. Заметим, что a2 — параметр функции sub_12EF4. Чтобы продвинуться дальше, нужно изучить ссылки на эту функцию (я переименовал её в ZwTerminateProcessCaller для лучшей читаемости).

screen5-git

Видно, что ZwTerminateProcessCaller вызывается функцией sub_13624 по смещению 61A.

screen6-git

Прежде чем анализировать этот декомпилированный код, я найду ссылки на функцию sub_13624 (переименованную в ZwTerminateProcessCallerCaller), чтобы убедиться, что этот код действительно используется после вызова API DeviceIoControl из UserMode.

screen§-git

Видно, что ZwTerminateProcessCallerCaller вызывается функцией sub_14130 (переименованной в ZwTerminateProcessCallerCallerCaller ...к счастью для нас, это последняя перед точкой входа 😅).

screen7-git

Видно, что ZwTerminateProcessCallerCallerCaller вызывается функцией sub_1A4A8 по смещению 306.

screen8-git

Здесь находится присваивание функции ZwTerminateProcessCallerCallerCaller:

root@kitploit:~
memset64(DriverObject->MajorFunction, (unsigned __int64)ZwTerminateProcessCallerCallerCaller, 0x1Cu);
Это означает, что функция назначается всем записям таблицы MajorFunction (0x1B = 27, а всего существует 28 основных IRP).

screen9-git

Прежде чем вернуться к функции sub_13624 (она же ZwTerminateProcessCallerCaller), получаем Symbolic Name и Device Name (здесь они совпадают): Viragtlt.

screen12-git

Возвращаясь к ZwTerminateProcessCallerCaller, замечаем, что её второй параметр (то есть a2) соответствует MasterIrp->AssociatedIrp.SystemBuffer.

screen13-git

Сразу над вызовом ZwTerminateProcessCaller находится IOCTL-код: -2106392528 (в шестнадцатеричном виде: 0x82730030).

Благодаря этой информации можно сделать вывод, что для эксплуатации этого драйвера нужно отправить драйверу вызов API DeviceIoControl с именем завершаемого процесса в SystemBuffer.


🔷 Информация, полученная в ходе reverse engineering:

  • IOCTLCode: 0x82730030
  • Device Name: Viragtlt
  • Symbolic Name: Viragtlt
  • SystemBuffer должен содержать имя целевого процесса

Часть 2 — Эксплуатация

Чтобы эксплуатировать этот драйвер (если он установлен и активен на целевой машине), необходимо открыть к нему дескриптор, а затем выполнить вызов API DeviceIoControl с буфером, содержащим имя процесса, который требуется завершить.
Для этого упражнения я разработал проект на C, который:

  • Проверяет, присутствует ли драйвер в системе и активен ли он (по конкретному имени службы):
    • Если да, программа эксплуатирует драйвер с помощью вызова API DeviceIoControl.
    • Если нет, программа извлекает драйвер из своих ресурсов, разворачивает его на рабочем столе пользователя, создаёт активную службу, а затем эксплуатирует драйвер с помощью вызова API DeviceIoControl. (Требуются права администратора, так как выполняется создание службы.)
  • Если драйвер присутствует в системе, но служба не запущена, программа пытается запустить службу, а затем эксплуатирует её с помощью вызова API DeviceIoControl.

Я также добавил опцию -d, которая позволяет удалить службу и драйвер из системы после эксплуатации.

Вот поведение программы на C в полном цикле выполнения:

git

Обход AV/EDR

В данном случае DriverKiller.exe не обнаруживается Microsoft Defender — ни статически, ни динамически. Обход здесь не имеет особого смысла, потому что эксплуатируемый драйвер имеет истёкший сертификат, поэтому его использование в реальных условиях трудно представить. Но для лучшей скрытности можно было бы реализовать:

  • Маскирование некоторых вызовов API из таблицы IAT с помощью собственных реализаций GetProcAddress и GetModuleHandle
  • Выполнение API-вызовов ближе к ядру (Direct/Indirect Syscalls)
  • Техники Anti-VM / Anti-Debug

Обнаружение драйвера на 29/08/2025 (результат уже существовал, я ничего не отправлял на VirusTotal по очевидным причинам):

image

⚠️ Этот проект создан в учебных целях. Он может содержать неточности или ошибки. Любые предложения, исправления и обсуждения приветствуются! 😃 Спасибо d1rk(SaadAhla): https://github.com/SaadAhla !

Скачать инструмент