NtQueryBootOptions
Lee el blob de opciones de arranque BCD del sistema — flags debug, opciones de carga del SO, hypervisor, test signing.
Prototipo
NTSTATUS NtQueryBootOptions( PBOOT_OPTIONS BootOptions, PULONG BootOptionsLength );
Argumentos
| Name | Type | Dir | Description |
|---|---|---|---|
| BootOptions | PBOOT_OPTIONS | out | Estructura BOOT_OPTIONS asignada por el llamador (longitud variable) que recibe las opciones de arranque actuales. |
| BootOptionsLength | PULONG | in/out | En entrada: capacidad en bytes. En salida: bytes escritos; STATUS_BUFFER_TOO_SMALL devuelve el tamaño requerido. |
IDs de syscalls por versión de Windows
| Versión de Windows | ID de syscall | Build |
|---|---|---|
| Win10 1507 | 0x129 | win10-1507 |
| Win10 1607 | 0x12F | win10-1607 |
| Win10 1703 | 0x134 | win10-1703 |
| Win10 1709 | 0x136 | win10-1709 |
| Win10 1803 | 0x138 | win10-1803 |
| Win10 1809 | 0x139 | win10-1809 |
| Win10 1903 | 0x13A | win10-1903 |
| Win10 1909 | 0x13A | win10-1909 |
| Win10 2004 | 0x140 | win10-2004 |
| Win10 20H2 | 0x140 | win10-20h2 |
| Win10 21H1 | 0x140 | win10-21h1 |
| Win10 21H2 | 0x141 | win10-21h2 |
| Win10 22H2 | 0x141 | win10-22h2 |
| Win11 21H2 | 0x147 | win11-21h2 |
| Win11 22H2 | 0x149 | win11-22h2 |
| Win11 23H2 | 0x149 | win11-23h2 |
| Win11 24H2 | 0x14B | win11-24h2 |
| Server 2016 | 0x12F | winserver-2016 |
| Server 2019 | 0x139 | winserver-2019 |
| Server 2022 | 0x146 | winserver-2022 |
| Server 2025 | 0x14B | winserver-2025 |
Módulo del kernel
APIs relacionadas
Stub del syscall
4C 8B D1 mov r10, rcx B8 4B 01 00 00 mov eax, 0x14B 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
Devuelve el blob BOOT_OPTIONS capturado por el cargador de SO y expuesto al kernel en ejecución. La estructura incluye Version, Length, Timeout, CurrentBootEntryId, NextBootEntryId y un HeaderId seguido de la región de cadenas de opciones. Ejemplos de cadenas presentes: `DEBUG`, `TESTSIGNING`, `HYPERVISORLAUNCHTYPE=AUTO`, `BOOTLOG`, `WINPE`, `NOEXECUTE=OPTIN`. Requiere SeSystemEnvironmentPrivilege. Mayormente usada por herramientas de recovery / setup y por algunos productos defensivos que quieren detectar si el host corre en modo arranque amigable al desarrollador.
Uso común por malware
Señal ofensiva baja. Algunos malwares (notablemente rutinas anti-análisis en loaders commodity) llaman a esto para detectar estados de arranque amistosos al debugger (`DEBUG`, `TESTSIGNING`, `BOOTLOG`) y abortar o modificar comportamiento para evadir entornos sandbox / lab. Ese es el patrón de abuso dominante — environmental keying en lugar de compromiso directo. Leer opciones de arranque no escala privilegios por sí mismo ni persiste.
Oportunidades de detección
El volumen de llamadas legítimas es moderado (herramientas de recovery, agentes de diagnóstico OEM, algunos productos de protección endpoint). ETW Microsoft-Windows-Kernel-General registra el acceso. La señal interesante es la *correlación*: un binario que acaba de elevar, habilitar SeSystemEnvironmentPrivilege y luego leyó BootOptions justo antes de decidir desplegar más payload es la forma anti-análisis de libro de texto. Los proveedores de sandbox normalmente responden falsificando el blob devuelto para hacer `DEBUG`/`TESTSIGNING` invisibles.
Ejemplos de syscalls directos
asmx64 direct stub (Win11 24H2)
; Direct syscall stub for NtQueryBootOptions (SSN 0x14B, Win11 24H2)
NtQueryBootOptions PROC
mov r10, rcx
mov eax, 14Bh
syscall
ret
NtQueryBootOptions ENDPcAnti-analysis: refuse to run under DEBUG/TESTSIGNING boot
// Demonstrative environmental-keying check used by commodity loaders.
// In production the loader fingerprints additional artefacts before deciding.
#pragma pack(push,4)
typedef struct _BOOT_OPTIONS {
ULONG Version;
ULONG Length;
ULONG Timeout;
ULONG CurrentBootEntryId;
ULONG NextBootEntryId;
WCHAR HeaderId[1]; // variable
} BOOT_OPTIONS, *PBOOT_OPTIONS;
#pragma pack(pop)
BOOLEAN was;
RtlAdjustPrivilege(SE_SYSTEM_ENVIRONMENT_PRIVILEGE, TRUE, FALSE, &was);
UCHAR buf[1024];
ULONG len = sizeof(buf);
NTSTATUS s = NtQueryBootOptions((PBOOT_OPTIONS)buf, &len);
if (NT_SUCCESS(s)) {
// Naive substring scan of the trailing options region.
PCWSTR opts = (PCWSTR)(buf + sizeof(BOOT_OPTIONS));
if (wcsstr(opts, L"DEBUG") || wcsstr(opts, L"TESTSIGNING")) {
ExitProcess(0); // bail — looks like an analyst's machine
}
}Mapeos MITRE ATT&CK
Last verified: 2026-05-20