NtUnloadDriver
Décharge un driver mode noyau précédemment chargé — la primitive de nettoyage BYOVD.
Prototype
NTSTATUS NtUnloadDriver( PUNICODE_STRING DriverServiceName );
Arguments
| Name | Type | Dir | Description |
|---|---|---|---|
| DriverServiceName | PUNICODE_STRING | in | Chemin NT vers la clé service sous \Registry\Machine\System\CurrentControlSet\Services\<Name>. L'appelant doit détenir SeLoadDriverPrivilege. |
IDs de syscalls par version de Windows
| Version de Windows | ID de syscall | Build |
|---|---|---|
| Win10 1507 | 0x1A9 | win10-1507 |
| Win10 1607 | 0x1B2 | win10-1607 |
| Win10 1703 | 0x1B8 | win10-1703 |
| Win10 1709 | 0x1BC | win10-1709 |
| Win10 1803 | 0x1BE | win10-1803 |
| Win10 1809 | 0x1BF | win10-1809 |
| Win10 1903 | 0x1C0 | win10-1903 |
| Win10 1909 | 0x1C0 | win10-1909 |
| Win10 2004 | 0x1C6 | win10-2004 |
| Win10 20H2 | 0x1C6 | win10-20h2 |
| Win10 21H1 | 0x1C6 | win10-21h1 |
| Win10 21H2 | 0x1C8 | win10-21h2 |
| Win10 22H2 | 0x1C8 | win10-22h2 |
| Win11 21H2 | 0x1D2 | win11-21h2 |
| Win11 22H2 | 0x1D6 | win11-22h2 |
| Win11 23H2 | 0x1D6 | win11-23h2 |
| Win11 24H2 | 0x1D9 | win11-24h2 |
| Server 2016 | 0x1B2 | winserver-2016 |
| Server 2019 | 0x1BF | winserver-2019 |
| Server 2022 | 0x1CE | winserver-2022 |
| Server 2025 | 0x1D9 | winserver-2025 |
Module noyau
APIs liées
Stub du syscall
4C 8B D1 mov r10, rcx B8 D9 01 00 00 mov eax, 0x1D9 F6 04 25 08 03 FE 7F 01 test byte ptr [0x7FFE0308], 1 75 03 jne short +3 0F 05 syscall C3 ret CD 2E int 2Eh C3 ret
Notes non documentées
NtUnloadDriver est l'homologue de NtLoadDriver. Étant donné un chemin NT vers une clé de service, il demande à l'I/O manager d'appeler la routine `DriverUnload` du driver et de retirer son `DRIVER_OBJECT` de `\Driver`. L'image driver est démappée de l'espace adressable noyau et l'emplacement `MmUnloadedDrivers` correspondant est rempli (le noyau garde un petit ring buffer des ~50 derniers noms de drivers déchargés — `!drvobj /unloaded` dans WinDbg). NtUnloadDriver exige que le token appelant détienne `SeLoadDriverPrivilege`, que les Administrateurs ont par défaut mais que les comptes de service ont rarement.
Usage courant par les malwares
L'appel signature du **nettoyage BYOVD (Bring Your Own Vulnerable Driver)**. Le kill chain classique : 1) déposer un driver signé-mais-vulnérable depuis une liste codée (RTCore64, gdrv, mhyprot2, kArmor, etc.) ; 2) NtLoadDriver pour créer le service et charger ; 3) IOCTL dans le driver pour désactiver les callbacks EDR, terminer des processus protégés, écrire dans des MSR ou de la mémoire noyau arbitraire ; 4) NtUnloadDriver pour retirer le driver du système et réduire l'empreinte forensique. Familles : EDRKillShifter (outillage affilié RansomHub), Terminator de Spyboy, module BYOVD d'AvosLocker, variantes KillAV, abus de RTCore64 par BlackByte, loader FudModule de Lazarus. L'unload est *nécessaire* — laisser le driver vulnérable chargé est un signal de détection bruyant pour l'énumération d'images noyau.
Opportunités de détection
Critique : la majeure partie de la télémétrie BYOVD publique se concentre sur le *load* (`Microsoft-Windows-Kernel-PnP` event 400, Sysmon Event ID 6) — le *unload* est historiquement peu instrumenté. La détection repose sur la corrélation : Sysmon Event 6 a loggé le chargement initial, puis l'absence de l'image driver dans les énumérations `Get-WindowsDriver` / `driverquery` / callbacks noyau suivantes est l'unique delta. `Microsoft-Windows-Kernel-PnP` event 410 se déclenche à l'arrêt du service. La blocklist drivers vulnérables de Microsoft Defender (`DriverSiPolicy.p7b`) empêche entièrement le load sur les systèmes activés — quand présente, le chemin BYOVD échoue à NtLoadDriver et NtUnloadDriver n'est jamais atteint. ELAM et HVCI mordent aussi sur le load, pas l'unload.
Exemples de syscalls directs
asmx64 direct stub
; Direct syscall stub for NtUnloadDriver (SSN 0x1D9 on Win11 24H2)
NtUnloadDriver PROC
mov r10, rcx ; DriverServiceName
mov eax, 1D9h ; SSN — verify per-build
syscall
ret
NtUnloadDriver ENDPcBYOVD cleanup after exploitation
// Final stage of a BYOVD chain: tear down the vulnerable driver and its service key.
#include <windows.h>
#include <winternl.h>
typedef NTSTATUS (NTAPI *pNtUnloadDriver)(PUNICODE_STRING);
BOOL BYOVDCleanup(PCWSTR ntServicePath /* L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Vuln" */) {
UNICODE_STRING us;
RtlInitUnicodeString(&us, ntServicePath);
pNtUnloadDriver fn = (pNtUnloadDriver)GetProcAddress(
GetModuleHandleA("ntdll.dll"), "NtUnloadDriver");
NTSTATUS s = fn(&us);
// Best practice: also delete the service-key and the .sys on disk to slim forensics.
// (omitted) RegDeleteTreeW + DeleteFileW
return s >= 0;
}rustEDR-kill teardown
// Cargo: ntapi = "0.4", widestring = "1"
use ntapi::ntioapi::NtUnloadDriver;
use ntapi::ntrtl::RtlInitUnicodeString;
use winapi::shared::ntdef::UNICODE_STRING;
use widestring::U16CString;
unsafe fn unload(svc_nt_path: &str) -> i32 {
let w = U16CString::from_str(svc_nt_path).unwrap();
let mut us: UNICODE_STRING = std::mem::zeroed();
RtlInitUnicodeString(&mut us, w.as_ptr());
NtUnloadDriver(&mut us)
}Mappings MITRE ATT&CK
Last verified: 2026-05-20