NtCreateMutant
Crea o abre un objeto mutant (mutex) con o sin nombre y opcionalmente toma la propiedad inicial.
Prototipo
NTSTATUS NtCreateMutant( PHANDLE MutantHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, BOOLEAN InitialOwner );
Argumentos
| Name | Type | Dir | Description |
|---|---|---|---|
| MutantHandle | PHANDLE | out | Recibe el handle al nuevo mutant si tiene éxito. |
| DesiredAccess | ACCESS_MASK | in | Máscara de acceso, típicamente MUTANT_ALL_ACCESS o MUTANT_QUERY_STATE | SYNCHRONIZE. |
| ObjectAttributes | POBJECT_ATTRIBUTES | in | Atributos de objeto opcionales; NULL para anónimo, proporcionar nombre bajo \BaseNamedObjects para IPC entre procesos. |
| InitialOwner | BOOLEAN | in | TRUE convierte al hilo llamante en propietario inicial (cuenta de recursión = 1, no señalado). |
IDs de syscalls por versión de Windows
| Versión de Windows | ID de syscall | Build |
|---|---|---|
| Win10 1507 | 0xA7 | win10-1507 |
| Win10 1607 | 0xA9 | win10-1607 |
| Win10 1703 | 0xAC | win10-1703 |
| Win10 1709 | 0xAD | win10-1709 |
| Win10 1803 | 0xAE | win10-1803 |
| Win10 1809 | 0xAE | win10-1809 |
| Win10 1903 | 0xAF | win10-1903 |
| Win10 1909 | 0xAF | win10-1909 |
| Win10 2004 | 0xB3 | win10-2004 |
| Win10 20H2 | 0xB3 | win10-20h2 |
| Win10 21H1 | 0xB3 | win10-21h1 |
| Win10 21H2 | 0xB4 | win10-21h2 |
| Win10 22H2 | 0xB4 | win10-22h2 |
| Win11 21H2 | 0xB7 | win11-21h2 |
| Win11 22H2 | 0xB8 | win11-22h2 |
| Win11 23H2 | 0xB8 | win11-23h2 |
| Win11 24H2 | 0xBA | win11-24h2 |
| Server 2016 | 0xA9 | winserver-2016 |
| Server 2019 | 0xAE | winserver-2019 |
| Server 2022 | 0xB6 | winserver-2022 |
| Server 2025 | 0xBA | winserver-2025 |
Módulo del kernel
APIs relacionadas
Stub del syscall
4C 8B D1 mov r10, rcx B8 BA 00 00 00 mov eax, 0xBA 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
Respaldado por `KeInitializeMutant` dentro de ntoskrnl.exe. A diferencia de los eventos, la SSN *deriva* entre builds (`0xA7` en 1507 hasta `0xBA` en Win11 24H2 / Server 2025), por lo que cualquier implementación con syscalls directos requiere resolución dinámica. Un mutant es propiedad de exactamente un hilo a la vez y soporta adquisición recursiva; queda abandonado (retorno `STATUS_ABANDONED_WAIT_0`) si el hilo propietario sale sin liberarlo — propiedad IPC resistente a crashes. La familia Win32 `CreateMutex` llama finalmente a esta rutina.
Uso común por malware
El enforcement de single-instance es el uso canónico: al arrancar, el implante llama a `NtCreateMutant` con un nombre codificado o derivado por hash; si `GetLastError == ERROR_ALREADY_EXISTS` (o en términos NT `STATUS_OBJECT_NAME_COLLISION`), una instancia existente está corriendo y la nueva sale. Los catálogos públicos de IOCs (Emotet, TrickBot, Qakbot, IcedID, NotPetya, Ryuk, Conti) listan cientos de nombres de mutex específicos por familia justamente por esto. Uso secundario: primitiva de bloqueo intra-proceso entre módulos worker, y sonda anti-sandbox (algunas sandboxes pre-crean nombres conocidos para provocar salida temprana).
Oportunidades de detección
Sysmon Event ID 1 / 11 no capturan directamente la creación de mutex; las configuraciones Sysmon pueden incluir matches `<RuleGroup>` sobre `OriginalFileName` más correlación vía ETW. La telemetría de alto valor es ETW `Microsoft-Windows-Kernel-Object` con el keyword `Mutant`, o el parsing `EvtxEcmd` de auditorías de handle del Object Manager cuando se colocan SACLs sobre `\BaseNamedObjects\<nombre-familia>`. Los IOCs de nombres de mutex siguen siendo una de las vías de detección más baratas y duraderas para malware commodity — las reglas Yara sobre memoria o strings aún capturan la mayoría de los droppers.
Ejemplos de syscalls directos
asmx64 direct stub (Win11 24H2)
; Direct syscall stub for NtCreateMutant (SSN 0xBA on Win11 24H2 / Server 2025)
NtCreateMutant PROC
mov r10, rcx ; syscall convention
mov eax, 0BAh ; SSN (24H2 — resolve dynamically for portability)
syscall
ret
NtCreateMutant ENDPcSingle-instance check
// Refuse to run a second copy. Family-specific mutex name kept in cleartext for clarity.
UNICODE_STRING name;
RtlInitUnicodeString(&name, L"\\BaseNamedObjects\\Global\\{8B4E4-implant-singleton}");
OBJECT_ATTRIBUTES oa;
InitializeObjectAttributes(&oa, &name, OBJ_CASE_INSENSITIVE, NULL, NULL);
HANDLE h = NULL;
NTSTATUS st = NtCreateMutant(&h, MUTANT_ALL_ACCESS, &oa, FALSE);
if (st == STATUS_OBJECT_NAME_COLLISION) { ExitProcess(0); } // already running
rustwindows-sys CreateMutexW wrapper
// Cargo: windows-sys = "0.59" (Win32_System_Threading)
use windows_sys::Win32::System::Threading::CreateMutexW;
use windows_sys::Win32::Foundation::{GetLastError, ERROR_ALREADY_EXISTS};
use windows_sys::core::w;
use std::ptr::null;
unsafe fn singleton() -> bool {
let h = CreateMutexW(null(), 0, w!("Global\\{my-implant-singleton}"));
!h.is_null() && GetLastError() != ERROR_ALREADY_EXISTS
}Mapeos MITRE ATT&CK
Last verified: 2026-05-20