> Windows Syscalls
ntoskrnl.exeT1083T1518.001T1106

NtQueryDirectoryObject

Enumeriert die Einträge (Name + Typ) innerhalb eines Object-Manager-Verzeichnisses.

Prototyp

NTSTATUS NtQueryDirectoryObject(
  HANDLE   DirectoryHandle,
  PVOID    Buffer,
  ULONG    Length,
  BOOLEAN  ReturnSingleEntry,
  BOOLEAN  RestartScan,
  PULONG   Context,
  PULONG   ReturnLength
);

Argumente

NameTypeDirDescription
DirectoryHandleHANDLEinHandle aus NtOpenDirectoryObject, geöffnet mit DIRECTORY_QUERY.
BufferPVOIDoutEmpfängt eine oder mehrere OBJECT_DIRECTORY_INFORMATION-Einträge gefolgt von deren UNICODE_STRING-Bodies.
LengthULONGinGröße von Buffer in Bytes.
ReturnSingleEntryBOOLEANinTRUE liefert einen Eintrag pro Aufruf; FALSE packt so viele wie passen.
RestartScanBOOLEANinTRUE startet die Enumeration neu; FALSE setzt mittels Context fort.
ContextPULONGin/outVom Kernel verwalteter In/Out-Enumerations-Cursor.
ReturnLengthPULONGoutEmpfängt die tatsächlich nach Buffer geschriebenen Bytes.

Syscall-IDs pro Windows-Version

Windows-VersionSyscall-IDBuild
Win10 15070x12Bwin10-1507
Win10 16070x131win10-1607
Win10 17030x136win10-1703
Win10 17090x139win10-1709
Win10 18030x13Bwin10-1803
Win10 18090x13Cwin10-1809
Win10 19030x13Dwin10-1903
Win10 19090x13Dwin10-1909
Win10 20040x143win10-2004
Win10 20H20x143win10-20h2
Win10 21H10x143win10-21h1
Win10 21H20x144win10-21h2
Win10 22H20x144win10-22h2
Win11 21H20x14Awin11-21h2
Win11 22H20x14Cwin11-22h2
Win11 23H20x14Cwin11-23h2
Win11 24H20x14Ewin11-24h2
Server 20160x131winserver-2016
Server 20190x13Cwinserver-2019
Server 20220x149winserver-2022
Server 20250x14Ewinserver-2025

Kernel-Modul

ntoskrnl.exeNtQueryDirectoryObject

Verwandte APIs

NtOpenDirectoryObjectNtCreateDirectoryObjectFindFirstFileNtQuerySystemInformation

Syscall-Stub

4C 8B D1            mov r10, rcx
B8 4E 01 00 00      mov eax, 0x14E
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

Undokumentierte Hinweise

NtQueryDirectoryObject gehört zu den SSN-volatilsten Syscalls (`0x12B` → `0x14E`), weil er spät in der Tabelle liegt und Microsoft fast jedes Release neue Einträge davor einfügt. Der Ausgabepuffer ist ein gepacktes Array `OBJECT_DIRECTORY_INFORMATION { UNICODE_STRING Name; UNICODE_STRING TypeName; }`, dessen UNICODE_STRING-`Buffer`-Felder in denselben Puffer zurückzeigen; ein NULL-Name beendet die Liste. Jeder Eintrag sagt sowohl **was** benannt ist (z. B. `Cor_SxSPublic_IPCBlock_Perfmon_v4.0.30319_Global_Mutex`) als auch **welchen Typs** (`Event`, `Mutant`, `Section`, `Directory`, `SymbolicLink`, `ALPC Port`, `Job`, `Semaphore`).

Häufige Malware-Nutzung

Drei Hauptnutzungen. **Security-Software-Discovery** — `\\Sessions\\<n>\\BaseNamedObjects` und `\\BaseNamedObjects` durchgehen, Namen gegen eine kuratierte Liste AV/EDR-Mutants und -Events abgleichen (Defender, Sophos, Bitdefender, CrowdStrike Falcon, SentinelOne, Carbon Black). Eine der billigsten Sandbox-Discovery-Techniken, da keine Imports außer ntdll nötig sind und weder FS- noch Registry-Traffic anfällt. **C2/Implant-Rendezvous-Discovery** — gleiche Primitive, gesucht wird das per-Session Marker-Verzeichnis des Angreifers zur Koordination von Multi-Implant-Operationen. **FS/Device-Discovery aus einer Sandbox** — `\\??` und `\\Device` durchgehen, um zu sehen, welche Mount-Manager-Devices und DOS-Buchstaben in der aktuellen Job-/AppContainer-Sicht existieren; nötiges Intel für Sandbox-Escape via Symlink-Planting (CVE-2019-0808-Linie). Auch `\\Driver` enthüllt, welche Third-Party-Kernel-Treiber (insbesondere EDR-Minifilter) geladen sind — exakt das Intel, das BYOVD-Angriffe zu verwundbaren Treibern brauchen.

Erkennungs­möglichkeiten

Fingerabdruck: **ein Prozess öffnet ein Object-Manager-Directory (NtOpenDirectoryObject mit DIRECTORY_QUERY) und ruft sofort NtQueryDirectoryObject in einer Schleife auf**. Kaum eine legitime User-Mode-Software tut das — Process Explorer, WinObj, Process Hacker und einige EDR-Self-Checks. Detektion über kernelseitiges ObRegisterCallbacks auf `IoDirectoryObjectType` sieht die Enumeration nicht direkt, EDR-Hooks auf NtQueryDirectoryObject in ntdll fangen sie ab; ETW Microsoft-Windows-Kernel-Audit-API-Calls macht sie ebenfalls sichtbar. Die Defender-ASR-Regel 'Block process creations originating from PSExec and WMI commands' hat historisch auch bei NtQueryDirectoryObject-Bursts aus Office-Kindern alarmiert.

Direkte Syscall-Beispiele

asmx64 direct stub (Win11 24H2)

; Direct syscall stub for NtQueryDirectoryObject (SSN 0x14E, Win11 24H2)
NtQueryDirectoryObject PROC
    mov  r10, rcx          ; syscall convention
    mov  eax, 14Eh         ; SSN (BUILD-SPECIFIC, resolve dynamically)
    syscall
    ret
NtQueryDirectoryObject ENDP

cBNO mutex sweep for AV/EDR fingerprints

// Walk \Sessions\<n>\BaseNamedObjects matching entries against a small
// AV/EDR mutex list. Returns the first hit's UNICODE name or NULL.
#include <windows.h>
#include <winternl.h>

typedef struct _OBJECT_DIRECTORY_INFORMATION {
    UNICODE_STRING Name;
    UNICODE_STRING TypeName;
} OBJECT_DIRECTORY_INFORMATION;

typedef NTSTATUS (NTAPI *pNtQueryDirectoryObject)(
    HANDLE, PVOID, ULONG, BOOLEAN, BOOLEAN, PULONG, PULONG);

static const WCHAR* kHits[] = {
    L"Global\\SQMMUTEX_TIMER",         // Defender
    L"CrowdStrikeFalconRules",          // Falcon
    L"SentinelOne_Mutex",               // S1
};

BOOL ScanBNO(HANDLE hDir) {
    pNtQueryDirectoryObject NtQueryDirectoryObject = (pNtQueryDirectoryObject)
        GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQueryDirectoryObject");
    BYTE buf[8192]; ULONG ctx = 0, ret = 0; BOOLEAN restart = TRUE;
    while (NT_SUCCESS(NtQueryDirectoryObject(hDir, buf, sizeof(buf),
                                             FALSE, restart, &ctx, &ret))) {
        restart = FALSE;
        OBJECT_DIRECTORY_INFORMATION* p = (OBJECT_DIRECTORY_INFORMATION*)buf;
        while (p->Name.Length) {
            for (int i = 0; i < _countof(kHits); ++i) {
                if (wcsstr(p->Name.Buffer, kHits[i])) return TRUE;
            }
            p++;
        }
    }
    return FALSE;
}

rustEnumerate \Driver for BYOVD intel

// Cargo: ntapi = "0.4"
// Dump loaded kernel driver object names — exactly what BYOVD attacks need to
// know about EDR minifilters and exploitable third-party drivers on the host.
use ntapi::ntobapi::NtQueryDirectoryObject;
use winapi::shared::ntdef::UNICODE_STRING;

#[repr(C)]
struct ObjectDirectoryInformation {
    name: UNICODE_STRING,
    type_name: UNICODE_STRING,
}

pub unsafe fn list_drivers(driver_dir: isize) -> Vec<String> {
    let mut out = Vec::new();
    let mut buf = vec![0u8; 16 * 1024];
    let mut ctx: u32 = 0; let mut ret: u32 = 0; let mut restart = 1u8;
    loop {
        let s = NtQueryDirectoryObject(driver_dir as _,
            buf.as_mut_ptr() as _, buf.len() as u32, 0, restart,
            &mut ctx, &mut ret);
        if s < 0 { break; }
        restart = 0;
        let mut p = buf.as_ptr() as *const ObjectDirectoryInformation;
        while (*p).name.Length != 0 {
            let n = &(*p).name;
            let slice = std::slice::from_raw_parts(n.Buffer, (n.Length / 2) as usize);
            out.push(String::from_utf16_lossy(slice));
            p = p.add(1);
        }
        if s == 0 { break; }
    }
    out
}

MITRE ATT&CK-Mappings

Last verified: 2026-05-20