NtQueryInformationAtom
Devuelve metadatos sobre un átomo individual o sobre toda la tabla global de átomos — nombre, refcount, pin count, contadores de uso.
Prototipo
NTSTATUS NtQueryInformationAtom( RTL_ATOM Atom, ATOM_INFORMATION_CLASS InformationClass, PVOID AtomInformation, ULONG AtomInformationLength, PULONG ReturnLength );
Argumentos
| Name | Type | Dir | Description |
|---|---|---|---|
| Atom | RTL_ATOM | in | ID de átomo a consultar. Ignorado cuando InformationClass = AtomTableInformation (volcado completo). |
| InformationClass | ATOM_INFORMATION_CLASS | in | AtomBasicInformation (por átomo: nombre + refcount + pin) o AtomTableInformation (conteo + lista de IDs). |
| AtomInformation | PVOID | out | Buffer del llamador que recibe una estructura ATOM_BASIC_INFORMATION o ATOM_TABLE_INFORMATION. |
| AtomInformationLength | ULONG | in | Tamaño de AtomInformation en bytes. |
| ReturnLength | PULONG | out | Recibe el número de bytes realmente escritos. Sirve para dimensionar una llamada subsiguiente si se devuelve STATUS_BUFFER_TOO_SMALL. |
IDs de syscalls por versión de Windows
| Versión de Windows | ID de syscall | Build |
|---|---|---|
| Win10 1507 | 0x12F | win10-1507 |
| Win10 1607 | 0x135 | win10-1607 |
| Win10 1703 | 0x13A | win10-1703 |
| Win10 1709 | 0x13D | win10-1709 |
| Win10 1803 | 0x13F | win10-1803 |
| Win10 1809 | 0x140 | win10-1809 |
| Win10 1903 | 0x141 | win10-1903 |
| Win10 1909 | 0x141 | win10-1909 |
| Win10 2004 | 0x147 | win10-2004 |
| Win10 20H2 | 0x147 | win10-20h2 |
| Win10 21H1 | 0x147 | win10-21h1 |
| Win10 21H2 | 0x148 | win10-21h2 |
| Win10 22H2 | 0x148 | win10-22h2 |
| Win11 21H2 | 0x14E | win11-21h2 |
| Win11 22H2 | 0x150 | win11-22h2 |
| Win11 23H2 | 0x150 | win11-23h2 |
| Win11 24H2 | 0x152 | win11-24h2 |
| Server 2016 | 0x135 | winserver-2016 |
| Server 2019 | 0x140 | winserver-2019 |
| Server 2022 | 0x14D | winserver-2022 |
| Server 2025 | 0x152 | winserver-2025 |
Módulo del kernel
APIs relacionadas
Stub del syscall
4C 8B D1 mov r10, rcx B8 52 01 00 00 mov eax, 0x152 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
La contraparte de lectura de NtAddAtom. La clase `AtomBasicInformation` devuelve una `ATOM_BASIC_INFORMATION` con el UsageCount (refcount), los Flags (pineado vs ordinario), el NameLength (en bytes) y los bytes de nombre — y al igual que con NtAddAtom, el kernel entrega los bytes crudos almacenados, independientemente de la validez UTF-16. La clase `AtomTableInformation` devuelve el conteo de átomos seguido de un array con todos los RTL_ATOM IDs — una primitiva de enumeración completa. Los wrappers Win32 `GlobalGetAtomNameW` y `GetAtomNameW` son la vía más común; herramientas sigilosas y la extensión WinDbg !atom usan el syscall en crudo.
Uso común por malware
**Atom Bombing etapa 2**: este syscall es el que realiza la escritura cross-process — el malware encola una APC en la víctima que llama a `GlobalGetAtomNameA`, que internamente invoca NtQueryInformationAtom; el propio kernel escribe los bytes de 'nombre' del átomo (el shellcode contrabandeado) en el buffer del espacio de direcciones de la víctima. Como la escritura la hace el kernel en nombre de la víctima, los hooks NtWriteVirtualMemory usermode no ven nada. **Inspección sigilosa de IPC**: herramientas red-team y de monitorización de persistencia llaman AtomTableInformation para volcar toda la tabla global y buscar residuos binarios, entradas sobredimensionadas o nombres conocidos malos — la misma primitiva que defensivamente detecta residuales de Atom Bomb puede usarse ofensivamente para leer el estado IPC en vivo de apps legítimas (topics DDE de Office, estado IME, nombres de clase de Explorer).
Oportunidades de detección
Las llamadas AtomBasicInformation ocurren constantemente vía GlobalGetAtomName — cada drag-and-drop, cada ronda de marshalling COM, cada conversación DDE. La detección debe centrarse en el contexto: AtomBasicInformation invocado desde un hilo recién reanudado vía NtTestAlert / KiUserApcDispatcher hacia un buffer recién asignado es el indicador canónico de etapa 2 de Atom Bomb (los EDR que desplegaron las reglas Atom Bomb de la era 2017 buscan exactamente esto). AtomTableInformation es más raro en rutas de código normales y es una señal ligeramente más fuerte — un proceso no-sistema que lo invoque merece un pivot. El snapshot WinDbg / forense de la tabla global (`!atom`) es la primitiva blue-team ortogonal — cualquier entrada con bytes binarios o longitud > algunos cientos es sospechosa.
Ejemplos de syscalls directos
asmx64 direct stub (Win11 24H2)
; Direct syscall stub for NtQueryInformationAtom (SSN 0x152 on Win11 24H2)
NtQueryInformationAtom PROC
mov r10, rcx ; syscall convention
mov eax, 152h ; SSN — varies per build
syscall
ret
NtQueryInformationAtom ENDPcAtom Bombing — stage 2 (kernel writes shellcode into target)
// Inside the victim process, the queued APC runs this code.
// GlobalGetAtomNameA -> NtQueryInformationAtom -> kernel copies the atom
// 'name' bytes (which were our shellcode in stage 1) into 'buf'.
#include <windows.h>
VOID StageTwoApc(PVOID context) {
USHORT atomId = (USHORT)(ULONG_PTR)context;
char buf[4096]; // attacker-sized to fit the shellcode
UINT got = GlobalGetAtomNameA(atomId, buf, sizeof(buf));
// Stage 3 (not shown): NtSetContextThread / ROP -> NtProtectVirtualMemory
// flips buf to RWX and pivots execution into it.
(void)got;
}cAtom table enumeration (defensive or offensive)
// Dump every atom in the global table and print its name + refcount.
// Use defensively: hunt for binary residue (Atom Bomb IOC).
// Use offensively: read live IPC state (DDE topics, IME state).
#include <windows.h>
#include <winternl.h>
#include <stdio.h>
typedef struct _ATOM_TABLE_INFORMATION {
ULONG NumberOfAtoms;
USHORT Atoms[1];
} ATOM_TABLE_INFORMATION;
typedef struct _ATOM_BASIC_INFORMATION {
USHORT UsageCount;
USHORT Flags;
USHORT NameLength;
WCHAR Name[1];
} ATOM_BASIC_INFORMATION;
typedef NTSTATUS (NTAPI *pNtQueryInformationAtom)(
USHORT, ULONG, PVOID, ULONG, PULONG);
VOID DumpAtomTable(VOID) {
pNtQueryInformationAtom NtQueryInformationAtom = (pNtQueryInformationAtom)
GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQueryInformationAtom");
BYTE tbuf[8192]; ULONG ret = 0;
if (NtQueryInformationAtom(0, /*AtomTableInformation*/ 1,
tbuf, sizeof(tbuf), &ret) < 0) return;
ATOM_TABLE_INFORMATION* ti = (ATOM_TABLE_INFORMATION*)tbuf;
for (ULONG i = 0; i < ti->NumberOfAtoms; ++i) {
BYTE abuf[1024]; ULONG ar = 0;
if (NtQueryInformationAtom(ti->Atoms[i], /*AtomBasicInformation*/ 0,
abuf, sizeof(abuf), &ar) < 0) continue;
ATOM_BASIC_INFORMATION* ai = (ATOM_BASIC_INFORMATION*)abuf;
wprintf(L"0x%04X rc=%u name=%.*s\n",
ti->Atoms[i], ai->UsageCount, ai->NameLength / 2, ai->Name);
}
}Mapeos MITRE ATT&CK
Last verified: 2026-05-20