NtModifyBootEntry
Ersetzt einen vorhandenen BOOT_ENTRY in der BCD durch einen neuen Deskriptor, identifiziert über seine ID.
Prototyp
NTSTATUS NtModifyBootEntry( PBOOT_ENTRY BootEntry );
Argumente
| Name | Type | Dir | Description |
|---|---|---|---|
| BootEntry | PBOOT_ENTRY | in | Zeiger auf einen BOOT_ENTRY, dessen `Id`-Feld den zu überschreibenden Eintrag auswählt. Der Rest der Struktur wird zum neuen Inhalt. |
Syscall-IDs pro Windows-Version
| Windows-Version | Syscall-ID | Build |
|---|---|---|
| Win10 1507 | 0x102 | win10-1507 |
| Win10 1607 | 0x107 | win10-1607 |
| Win10 1703 | 0x10B | win10-1703 |
| Win10 1709 | 0x10C | win10-1709 |
| Win10 1803 | 0x10E | win10-1803 |
| Win10 1809 | 0x10F | win10-1809 |
| Win10 1903 | 0x110 | win10-1903 |
| Win10 1909 | 0x110 | win10-1909 |
| Win10 2004 | 0x115 | win10-2004 |
| Win10 20H2 | 0x115 | win10-20h2 |
| Win10 21H1 | 0x115 | win10-21h1 |
| Win10 21H2 | 0x116 | win10-21h2 |
| Win10 22H2 | 0x116 | win10-22h2 |
| Win11 21H2 | 0x11C | win11-21h2 |
| Win11 22H2 | 0x11D | win11-22h2 |
| Win11 23H2 | 0x11D | win11-23h2 |
| Win11 24H2 | 0x11F | win11-24h2 |
| Server 2016 | 0x107 | winserver-2016 |
| Server 2019 | 0x10F | winserver-2019 |
| Server 2022 | 0x11B | winserver-2022 |
| Server 2025 | 0x11F | winserver-2025 |
Kernel-Modul
Verwandte APIs
Syscall-Stub
4C 8B D1 mov r10, rcx B8 1F 01 00 00 mov eax, 0x11F 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
Anders als NtAddBootEntry hat NtModifyBootEntry keinen Ausgabeparameter `Id` — die ID ist der in der eingehenden BOOT_ENTRY eingebettete *Primärschlüssel*. Der Kernel findet den passenden Firmware-Eintrag (`Boot####`-EFI-Variable auf UEFI, Eintrag in der BCD-Hive auf BIOS) und überschreibt ihn atomar. SeSystemEnvironmentPrivilege erforderlich. Dasselbe opake `OsOptionsLength`-Blob wird übernommen, sodass beliebige BCD-Elemente (BcdLibraryDevice_ApplicationDevice, BcdOSLoaderString_KernelPath usw.) in einem Rutsch gepatcht werden können.
Häufige Malware-Nutzung
Die heimlichste BCD-Persistenzvariante: statt einen *verdächtigen neuen* Eintrag hinzuzufügen, den Verteidiger in `bcdedit /enum` sehen würden, **mutiert die Malware den legitimen `{current}`-Windows-Booteintrag**, sodass dessen `path`-Element auf einen bösartigen bootmgr oder ein verkettetes EFI-Binary zeigt, das anschließend zum echten Loader zurückspringt. Der Nutzer sieht keinen zusätzlichen Menüpunkt; das System bootet einfach durch die Stage-0 des Angreifers. Diese Technik wird ESPecter zugeschrieben (modifiziert das vorhandene Windows-Boot-Manager-BCD-Objekt) sowie der `bcdedit /set {bootmgr} path`-Recon von TrickBoot. BlackLotus patcht ebenfalls den vorhandenen Eintrag, um BitLocker-Integritätsprüfungen vor dem Bootkit-Lauf zu deaktivieren.
Erkennungsmöglichkeiten
BCD-Modifikationen erzeugen dieselbe Telemetrie wie Ergänzungen: ETW Microsoft-Windows-Kernel-Boot, Registry-Deltas auf `HKLM\BCD00000000` und Audit-Event 4673 für SeSystemEnvironmentPrivilege. Insbesondere die Elemente `path`, `device` und `nx` der `{current}`- und `{bootmgr}`-Objekte gegen eine Goldbaseline vergleichen — jede Änderung außerhalb des Patch-Tuesday-Fensters ist verdächtig. Windows Defender Application Control (WDAC) kann den Aufruf nicht verhindern, doch die Durchsetzung von **Boot Integrity** über Measured Boot + einen Remote-Attestation-Dienst (Azure Attestation, Intune-Gerätezustand) erkennt Post-Boot-Drift, weil die TPM-Messungen PCR[4]/PCR[7] von der erwarteten Policy abweichen.
Direkte Syscall-Beispiele
asmx64 direct stub (Win11 24H2, SSN 0x11F)
NtModifyBootEntry PROC
mov r10, rcx ; PBOOT_ENTRY (Id baked into the struct)
mov eax, 11Fh ; Win11 24H2
syscall
ret
NtModifyBootEntry ENDPcHijack the existing Windows entry path
// Conceptual: rewrite the {current} Windows entry so its bootmgr path becomes our shim.
// Read the existing entry via NtEnumerateBootEntries, mutate the FilePath, write back.
NTSTATUS hijack_current(ULONG id, const wchar_t* shim_path) {
BYTE buf[1024] = {0};
PBOOT_ENTRY be = (PBOOT_ENTRY)buf;
be->Version = 1;
be->Length = sizeof(buf);
be->Id = id; // ID returned by NtEnumerateBootEntries
be->Attributes = BOOT_ENTRY_ATTRIBUTE_ACTIVE;
be->BootFilePathOffset = FIELD_OFFSET(BOOT_ENTRY, OsOptions);
// Build a FILE_PATH(\EFI\evil\shim.efi) here ...
return NtModifyBootEntry(be);
}rustNaked stub
use std::arch::asm;
#[unsafe(naked)]
unsafe extern "system" fn nt_modify_boot_entry(_entry: *mut u8) -> i32 {
asm!(
"mov r10, rcx",
"mov eax, 0x11F", // Win11 24H2
"syscall",
"ret",
options(noreturn),
);
}MITRE ATT&CK-Mappings
Last verified: 2026-05-20