NtFindAtom
Busca un átomo global existente por nombre y devuelve su ID de 16 bits sin incrementar el refcount.
Prototipo
NTSTATUS NtFindAtom( PWSTR AtomName, ULONG Length, PRTL_ATOM Atom );
Argumentos
| Name | Type | Dir | Description |
|---|---|---|---|
| AtomName | PWSTR | in | Buffer UTF-16 cuyos bytes el kernel comparará con las entradas de átomos existentes. |
| Length | ULONG | in | Tamaño del buffer en bytes. |
| Atom | PRTL_ATOM | out | Recibe el ID de átomo de 16 bits si se encuentra. Opcional — pasar NULL solo para probar existencia. |
IDs de syscalls por versión de Windows
| Versión de Windows | ID de syscall | Build |
|---|---|---|
| Win10 1507 | 0x14 | win10-1507 |
| Win10 1607 | 0x14 | win10-1607 |
| Win10 1703 | 0x14 | win10-1703 |
| Win10 1709 | 0x14 | win10-1709 |
| Win10 1803 | 0x14 | win10-1803 |
| Win10 1809 | 0x14 | win10-1809 |
| Win10 1903 | 0x14 | win10-1903 |
| Win10 1909 | 0x14 | win10-1909 |
| Win10 2004 | 0x14 | win10-2004 |
| Win10 20H2 | 0x14 | win10-20h2 |
| Win10 21H1 | 0x14 | win10-21h1 |
| Win10 21H2 | 0x14 | win10-21h2 |
| Win10 22H2 | 0x14 | win10-22h2 |
| Win11 21H2 | 0x14 | win11-21h2 |
| Win11 22H2 | 0x14 | win11-22h2 |
| Win11 23H2 | 0x14 | win11-23h2 |
| Win11 24H2 | 0x14 | win11-24h2 |
| Server 2016 | 0x14 | winserver-2016 |
| Server 2019 | 0x14 | winserver-2019 |
| Server 2022 | 0x14 | winserver-2022 |
| Server 2025 | 0x14 | winserver-2025 |
Módulo del kernel
APIs relacionadas
Stub del syscall
4C 8B D1 mov r10, rcx B8 14 00 00 00 mov eax, 0x14 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
El SSN `0x14` es estable de 1507 a 24H2 — las interfaces de tabla de átomos simplemente no se mueven. NtFindAtom es el hermano de solo lectura de NtAddAtom: recorre la tabla hash global, compara byte a byte el input Length-bytes contra cada entrada y devuelve el ID existente sin tocar el refcount. A diferencia de NtAddAtom, NtFindAtom devuelve STATUS_OBJECT_NAME_NOT_FOUND si el nombre no existe (NtAddAtom lo crearía). Wrappers Win32: `GlobalFindAtomA/W`.
Uso común por malware
**Rendezvous Atom Bombing** — el segundo implante (o un hilo hermano) llama a NtFindAtom sobre una cadena marcador pactada para descubrir si el shellcode stage-1 ya está en la tabla y conocer su ID antes de encolar el APC que dispara `GlobalGetAtomNameA` en el objetivo. También para **coordinación IPC entre implantes** donde la tabla de átomos hace de almacén clave/valor compartido encubierto: los implantes publican identificadores de sesión, IDs de beacon o hashes de URL de callback como nombres de átomos, y los pares los `NtFindAtom` para descubrirse sin tocar disco, registro o sockets. **Detección de sandbox** — consultar la tabla por átomos dejados por harnesses de sandbox (Triage y Joe Sandbox registran cada uno un pequeño conjunto de átomos reconocibles en el arranque); presencia = entorno de análisis. Barato, sin imports más allá de ntdll, indetectable por EDRs centrados en fichero/registro.
Oportunidades de detección
Volumen aún más bajo que NtAddAtom en telemetría de alertas — la mayoría de productos tratan la tabla de átomos como caja negra. Caza útil: **NtFindAtom llamado por un proceso que nunca llama a NtAddAtom**, con un Length que sugiere búsqueda de marcador en vez de nombre de clase de ventana (típicamente 8-64 bytes), correlacionado con un NtQueueApcThread posterior hacia un proceso remoto — signo fuerte de rendezvous Atom Bombing. ETW Microsoft-Windows-Kernel-Audit-API-Calls expone el syscall. WinDbg `!atom` muestra la tabla global actual y es la verdad en IR. El motor conductual de Defender añadió (~2018) una detección específica de Atom Bomb que dispara sobre la cadena completa GlobalAddAtomA + GlobalGetAtomNameA-vía-APC, pero NtFindAtom solo normalmente no la dispara.
Ejemplos de syscalls directos
asmx64 direct stub
; Direct syscall stub for NtFindAtom (SSN 0x14, all builds)
NtFindAtom PROC
mov r10, rcx ; syscall convention
mov eax, 14h ; SSN
syscall
ret
NtFindAtom ENDPcRendezvous marker lookup (Atom Bombing stage-2 helper)
// Stage-2 implant looks up the agreed marker atom to find the stage-1
// shellcode payload uploaded via NtAddAtom by a sibling. Returns the
// atom ID, ready to feed to GlobalGetAtomNameA via an APC in the target.
#include <windows.h>
#include <winternl.h>
typedef NTSTATUS (NTAPI *pNtFindAtom)(PWSTR, ULONG, PUSHORT);
USHORT FindRendezvousAtom(PCWSTR marker) {
pNtFindAtom NtFindAtom = (pNtFindAtom)GetProcAddress(
GetModuleHandleA("ntdll.dll"), "NtFindAtom");
USHORT id = 0;
ULONG bytes = (ULONG)(wcslen(marker) * sizeof(WCHAR));
NTSTATUS s = NtFindAtom((PWSTR)marker, bytes, &id);
return NT_SUCCESS(s) ? id : 0;
}rustSandbox marker probe
// Cargo: ntapi = "0.4", widestring = "1"
// Probe the global atom table for known sandbox-harness markers. Presence
// of any of these signals an analysis environment.
use ntapi::ntexapi::NtFindAtom;
use widestring::U16CString;
const MARKERS: &[&str] = &[
"TriageHostMarker_v3",
"JoeSandboxAgent_active",
"AnyRun_Probe",
];
pub unsafe fn looks_like_sandbox() -> bool {
for &m in MARKERS {
let w = U16CString::from_str(m).unwrap();
let mut id: u16 = 0;
let s = NtFindAtom(w.as_ptr() as _, (w.len() * 2) as u32, &mut id);
if s >= 0 && id != 0 { return true; }
}
false
}Mapeos MITRE ATT&CK
Last verified: 2026-05-20