NtQuerySystemEnvironmentValueEx
Liest eine UEFI-Variable, identifiziert durch (Name, Hersteller-GUID), und liefert Daten plus Attribute zurück.
Prototyp
NTSTATUS NtQuerySystemEnvironmentValueEx( PUNICODE_STRING VariableName, LPGUID VendorGuid, PVOID Value, PULONG ValueLength, PULONG Attributes );
Argumente
| Name | Type | Dir | Description |
|---|---|---|---|
| VariableName | PUNICODE_STRING | in | UEFI-Variablenname, z. B. L"BootOrder", L"dbx", L"PK", L"SecureBoot". |
| VendorGuid | LPGUID | in | Hersteller-GUID-Namensraum. EFI_GLOBAL_VARIABLE für Boot-Konfiguration, EFI_IMAGE_SECURITY_DATABASE_GUID für Secure-Boot-Schlüssel. |
| Value | PVOID | out | Vom Aufrufer bereitgestellter Puffer für die rohen Variablendaten (binär). |
| ValueLength | PULONG | in/out | Eingang: Pufferkapazität. Ausgang: tatsächlich zurückgegebene Bytes. |
| Attributes | PULONG | out | Empfängt EFI-Variablen-Attribut-Flags (NON_VOLATILE, BOOTSERVICE_ACCESS, RUNTIME_ACCESS, AUTHENTICATED_WRITE_ACCESS, ...). |
Syscall-IDs pro Windows-Version
| Windows-Version | Syscall-ID | Build |
|---|---|---|
| Win10 1507 | 0x146 | win10-1507 |
| Win10 1607 | 0x14D | win10-1607 |
| Win10 1703 | 0x153 | win10-1703 |
| Win10 1709 | 0x156 | win10-1709 |
| Win10 1803 | 0x158 | win10-1803 |
| Win10 1809 | 0x159 | win10-1809 |
| Win10 1903 | 0x15A | win10-1903 |
| Win10 1909 | 0x15A | win10-1909 |
| Win10 2004 | 0x160 | win10-2004 |
| Win10 20H2 | 0x160 | win10-20h2 |
| Win10 21H1 | 0x160 | win10-21h1 |
| Win10 21H2 | 0x161 | win10-21h2 |
| Win10 22H2 | 0x161 | win10-22h2 |
| Win11 21H2 | 0x168 | win11-21h2 |
| Win11 22H2 | 0x16B | win11-22h2 |
| Win11 23H2 | 0x16B | win11-23h2 |
| Win11 24H2 | 0x16D | win11-24h2 |
| Server 2016 | 0x14D | winserver-2016 |
| Server 2019 | 0x159 | winserver-2019 |
| Server 2022 | 0x166 | winserver-2022 |
| Server 2025 | 0x16D | winserver-2025 |
Kernel-Modul
Verwandte APIs
Syscall-Stub
4C 8B D1 mov r10, rcx B8 6D 01 00 00 mov eax, 0x16D 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
Die moderne UEFI-Variablen-Leseschnittstelle. Identifiziert eine Variable per (Name, Hersteller-GUID) — der Name allein ist mehrdeutig, da Secure Boot, BCD, Hersteller-Firmware-Tools und OEM-Management gemeinsame Kurznamen unter unterschiedlichen GUID-Namensräumen wiederverwenden. Liefert die rohen Bytes plus EFI-Attributmaske zurück, sodass Aufrufer erkennen, ob die Variable nichtflüchtig, zur Laufzeit zugänglich oder authentifiziert-schreibbar ist. Erfordert SeSystemEnvironmentPrivilege. Win32-Oberfläche ist GetFirmwareEnvironmentVariableExW.
Häufige Malware-Nutzung
Primärer Reconnaissance-Aufruf für firmware-bewusste Angreifer. `SecureBoot`, `SetupMode`, `PK`, `KEK`, `db`, `dbx` und `BootOrder` zu lesen offenbart, ob Secure Boot erzwungen wird, welche Schlüssel eingespielt sind und welcher Loader zuerst läuft. TrickBoot (das UEFI-Modul von TrickBot) nutzte den Win32-Wrapper, um verwundbare Firmware zu fingerprinten. APT41s MoonBounce und Sednit/APT28s LoJax untersuchten UEFI-Zustände beide auf diesem Weg, bevor sie über den Ex-*Setter* persistieren wollten. Lesen allein ist wirkungsarm; der Wert liegt in der Opferauswahl und der Vermeidung signierter Firmware-Maschinen.
Erkennungsmöglichkeiten
Microsoft-Windows-Kernel-General ETW gibt Firmware-Leseereignisse inkl. Variablenname und GUID aus. Verteidiger sollten Baseline-Prozesse erfassen, die legitim Secure-Boot-Zustand lesen (System, mountvol, manage-bde, Hersteller-Agenten), und jeden anderen Leser — besonders Usermode-Malware, die gerade SeSystemEnvironmentPrivilege erhöht und aktiviert hat — als hochpräzises verdächtiges Signal behandeln. CrowdStrike und Microsoft Defender for Endpoint exponieren direkte Aufrufe über ihren EDR-Sensor; die Win32-Wrapper werden ebenfalls regelmäßig gehakt.
Direkte Syscall-Beispiele
asmx64 direct stub (Win11 24H2)
; Direct syscall stub for NtQuerySystemEnvironmentValueEx (SSN 0x16D, Win11 24H2)
NtQuerySystemEnvironmentValueEx PROC
mov r10, rcx
mov eax, 16Dh
syscall
ret
NtQuerySystemEnvironmentValueEx ENDPcRead SecureBoot state via Win32
// GUID for EFI_GLOBAL_VARIABLE: {8BE4DF61-93CA-11D2-AA0D-00E098032B8C}
// Win32 string-form is required by GetFirmwareEnvironmentVariableExW.
static const wchar_t* kGlobal = L"{8BE4DF61-93CA-11D2-AA0D-00E098032B8C}";
BOOLEAN was;
RtlAdjustPrivilege(SE_SYSTEM_ENVIRONMENT_PRIVILEGE, TRUE, FALSE, &was);
BYTE secureBoot = 0;
DWORD attrs = 0;
DWORD n = GetFirmwareEnvironmentVariableExW(
L"SecureBoot", kGlobal, &secureBoot, sizeof(secureBoot), &attrs);
if (n == 1 && secureBoot == 1) {
// Secure Boot is active. Variable attribute mask is in `attrs`.
}rustDirect syscall query of BootOrder
// windows-sys = "0.59" — naked stub omitted for brevity (see x64 stub above).
// Demonstrates the call shape — privilege gating must be performed beforehand.
#[repr(C)]
struct UnicodeString { length: u16, max: u16, buf: *const u16 }
extern "system" {
fn NtQuerySystemEnvironmentValueEx(
name: *const UnicodeString,
guid: *const windows_sys::core::GUID,
value: *mut u8,
value_len: *mut u32,
attributes: *mut u32,
) -> i32;
}
const EFI_GLOBAL_VARIABLE: windows_sys::core::GUID = windows_sys::core::GUID {
data1: 0x8BE4DF61, data2: 0x93CA, data3: 0x11D2,
data4: [0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C],
};MITRE ATT&CK-Mappings
Last verified: 2026-05-20