> Windows Syscalls
ntoskrnl.exeT1542.003T1542T1106

NtModifyBootEntry

Replaces an existing BOOT_ENTRY in the Boot Configuration Database with a new descriptor, keyed by its ID.

Prototype

NTSTATUS NtModifyBootEntry(
  PBOOT_ENTRY BootEntry
);

Arguments

NameTypeDirDescription
BootEntryPBOOT_ENTRYinPointer to a BOOT_ENTRY whose `Id` field selects the existing entry to overwrite. The remainder of the structure becomes the new contents.

Syscall IDs by Windows version

Windows versionSyscall IDBuild
Win10 15070x102win10-1507
Win10 16070x107win10-1607
Win10 17030x10Bwin10-1703
Win10 17090x10Cwin10-1709
Win10 18030x10Ewin10-1803
Win10 18090x10Fwin10-1809
Win10 19030x110win10-1903
Win10 19090x110win10-1909
Win10 20040x115win10-2004
Win10 20H20x115win10-20h2
Win10 21H10x115win10-21h1
Win10 21H20x116win10-21h2
Win10 22H20x116win10-22h2
Win11 21H20x11Cwin11-21h2
Win11 22H20x11Dwin11-22h2
Win11 23H20x11Dwin11-23h2
Win11 24H20x11Fwin11-24h2
Server 20160x107winserver-2016
Server 20190x10Fwinserver-2019
Server 20220x11Bwinserver-2022
Server 20250x11Fwinserver-2025

Kernel module

ntoskrnl.exeNtModifyBootEntry

Related APIs

BcdSetElementData (bcd.dll)bcdedit.exe /set {bootmgr} pathSetFirmwareEnvironmentVariableWNtAddBootEntryNtDeleteBootEntryNtEnumerateBootEntriesNtSetBootEntryOrder

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

Undocumented notes

Unlike NtAddBootEntry, NtModifyBootEntry takes no `Id` out-parameter — the ID is the *primary key* embedded in the incoming BOOT_ENTRY. The kernel locates the matching firmware-side entry (a `Boot####` EFI variable on UEFI, an entry inside the BCD hive on BIOS) and rewrites it atomically. SeSystemEnvironmentPrivilege is required. The same `OsOptionsLength` opaque blob is honored, allowing arbitrary BCD elements (BcdLibraryDevice_ApplicationDevice, BcdOSLoaderString_KernelPath, etc.) to be patched in one shot.

Common malware usage

The stealthiest BCD-persistence variant: rather than *adding* a suspicious new entry that defenders can spot in `bcdedit /enum`, malware **mutates the legitimate `{current}` Windows boot entry** so that its `path` element points at a malicious bootmgr or a chained EFI binary that pivots back to the real loader. The user sees no extra menu choice; the system simply boots through the attacker's stage 0. This is the technique attributed to ESPecter (modifies the existing Windows Boot Manager BCD object) and to TrickBoot's `bcdedit /set {bootmgr} path` reconnaissance. BlackLotus also patches the existing entry to disable BitLocker integrity checks before its bootkit runs.

Detection opportunities

BCD modifications hit the same telemetry as additions: ETW Microsoft-Windows-Kernel-Boot, registry deltas on `HKLM\BCD00000000`, and audit event 4673 for SeSystemEnvironmentPrivilege. Specifically diff the `path`, `device` and `nx` elements of the `{current}` and `{bootmgr}` objects against a golden baseline — any change to these on a non-patch-Tuesday boundary is suspect. Windows Defender Application Control (WDAC) cannot prevent the call, but enforcing **Boot Integrity** via Measured Boot + a remote attestation service (Azure Attestation, Intune device health) detects post-boot drift because the TPM PCR[4]/PCR[7] measurements will diverge from the expected policy.

Direct syscall examples

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 ENDP

cHijack 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