NtEnumerateDriverEntries
Liefert eine gepackte Liste aller registrierten EFI_DRIVER_ENTRYs — die UEFI-Driver####-Variablen, die vor dem Boot-Manager dispatcht werden.
Prototyp
NTSTATUS NtEnumerateDriverEntries( PVOID Buffer, PULONG BufferLength );
Argumente
| Name | Type | Dir | Description |
|---|---|---|---|
| Buffer | PVOID | out | Vom Aufrufer allokierter Puffer, der eine gepackte Folge von EFI_DRIVER_ENTRY_LIST-Datensätzen empfängt (NextEntryOffset + eingebetteter EFI_DRIVER_ENTRY). Darf NULL sein, um die benötigte Größe abzufragen. |
| BufferLength | PULONG | in/out | Eingabe: Größe von Buffer in Byte. Ausgabe: geschriebene Byte oder benötigte Größe, wenn STATUS_BUFFER_TOO_SMALL zurückgegeben wird. |
Syscall-IDs pro Windows-Version
| Windows-Version | Syscall-ID | Build |
|---|---|---|
| Win10 1507 | 0xD0 | win10-1507 |
| Win10 1607 | 0xD3 | win10-1607 |
| Win10 1703 | 0xD6 | win10-1703 |
| Win10 1709 | 0xD7 | win10-1709 |
| Win10 1803 | 0xD8 | win10-1803 |
| Win10 1809 | 0xD9 | win10-1809 |
| Win10 1903 | 0xDA | win10-1903 |
| Win10 1909 | 0xDA | win10-1909 |
| Win10 2004 | 0xDF | win10-2004 |
| Win10 20H2 | 0xDF | win10-20h2 |
| Win10 21H1 | 0xDF | win10-21h1 |
| Win10 21H2 | 0xE0 | win10-21h2 |
| Win10 22H2 | 0xE0 | win10-22h2 |
| Win11 21H2 | 0xE5 | win11-21h2 |
| Win11 22H2 | 0xE6 | win11-22h2 |
| Win11 23H2 | 0xE6 | win11-23h2 |
| Win11 24H2 | 0xE8 | win11-24h2 |
| Server 2016 | 0xD3 | winserver-2016 |
| Server 2019 | 0xD9 | winserver-2019 |
| Server 2022 | 0xE4 | winserver-2022 |
| Server 2025 | 0xE8 | winserver-2025 |
Kernel-Modul
Verwandte APIs
Syscall-Stub
4C 8B D1 mov r10, rcx B8 E8 00 00 00 mov eax, 0xE8 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
Undokumentierte Hinweise
Gleiches Zwei-Aufruf-Schema wie NtEnumerateBootEntries — einmal mit `Buffer = NULL` aufrufen, um die benötigte Größe zu erfahren, dann mit der Allokation erneut. Durchläuft die verkettete Liste über `EFI_DRIVER_ENTRY_LIST.NextEntryOffset`. SeSystemEnvironmentPrivilege ist auch zum Lesen erforderlich. Auf UEFI liest es indirekt die globale `DriverOrder`-Variable sowie jede referenzierte `Driver####`.
Häufige Malware-Nutzung
Sowohl offensiv als auch defensiv genutzt. Offensiv: APT-Recon zum Fingerprinten der Firmware, bevor entschieden wird, welcher DRIVER_ENTRY-Hijack tragfähig ist — der MosaicRegressor-Installer enumeriert DriverOrder, um einen stabilen Slot eines verwundbaren OEM-Treibers zum Patchen zu finden. Defensiv: Incident-Response und proaktive Forensik rufen ihn (oder `bcdedit /enum FIRMWARE`) auf, um die aktuelle Treiberliste zu dumpen und gegen eine Cleanroom-Baseline desselben Hardwaremodells zu vergleichen — die zuverlässigste einfache Methode zur Erkennung von LoJax-/MosaicRegressor-artigen Implants ohne vollständigen SPI-Dump.
Erkennungsmöglichkeiten
Enumeration allein ist gutartig — Verteidiger führen sie ständig aus. Interessantes Signal ist die **Enumeration durch einen unerwarteten Prozess**: ein Nicht-OEM-, Nicht-Microsoft-, Nicht-EDR-Userland-Prozess, der ein Token mit SeSystemEnvironmentPrivilege öffnet und die Treiberliste liest, ist ein starker Staging-Indikator. Den Aufrufer (Event ID 4673) mit der Prozess-Kommandozeile via Sysmon Event ID 1 paaren. Verlässlichste Verteidigung bleibt Secure Boot mit aktueller DBX sowie Measured Boot + Remote Attestation, die PCR[2] bei jedem dispatchten DXE-Treiber erweitern.
Direkte Syscall-Beispiele
asmx64 direct stub (Win11 24H2, SSN 0xE8)
NtEnumerateDriverEntries PROC
mov r10, rcx ; PVOID Buffer
mov eax, 0E8h ; Win11 24H2
syscall
ret
NtEnumerateDriverEntries ENDPcDefensive: dump every DXE entry path + hash
// Walk DriverOrder, print FriendlyName + DriverFilePath of each registered DXE entry.
extern NTSTATUS NTAPI NtEnumerateDriverEntries(PVOID, PULONG);
void dump_drivers(void) {
ULONG size = 0;
NtEnumerateDriverEntries(NULL, &size);
if (!size) return;
PBYTE buf = (PBYTE)HeapAlloc(GetProcessHeap(), 0, size);
if (NT_SUCCESS(NtEnumerateDriverEntries(buf, &size))) {
PBYTE p = buf;
while (p < buf + size) {
PEFI_DRIVER_ENTRY_LIST list = (PEFI_DRIVER_ENTRY_LIST)p;
PEFI_DRIVER_ENTRY de = &list->DriverEntry;
wprintf(L"id=%08X name=%s\n", de->Id,
(LPCWSTR)((PBYTE)de + de->FriendlyNameOffset));
if (!list->NextEntryOffset) break;
p += list->NextEntryOffset;
}
}
HeapFree(GetProcessHeap(), 0, buf);
}rustNaked stub
use std::arch::asm;
#[unsafe(naked)]
unsafe extern "system" fn nt_enumerate_driver_entries(_buf: *mut u8, _len: *mut u32) -> i32 {
asm!(
"mov r10, rcx",
"mov eax, 0xE8", // Win11 24H2
"syscall",
"ret",
options(noreturn),
);
}MITRE ATT&CK-Mappings
Last verified: 2026-05-20