> Windows Syscalls
ntoskrnl.exeT1571T1090T1559

NtCreateNamedPipeFile

Creates the server end of a named pipe in the \Device\NamedPipe device namespace.

Prototype

NTSTATUS NtCreateNamedPipeFile(
  PHANDLE            FileHandle,
  ULONG              DesiredAccess,
  POBJECT_ATTRIBUTES ObjectAttributes,
  PIO_STATUS_BLOCK   IoStatusBlock,
  ULONG              ShareAccess,
  ULONG              CreateDisposition,
  ULONG              CreateOptions,
  ULONG              NamedPipeType,
  ULONG              ReadMode,
  ULONG              CompletionMode,
  ULONG              MaximumInstances,
  ULONG              InboundQuota,
  ULONG              OutboundQuota,
  PLARGE_INTEGER     DefaultTimeout
);

Arguments

NameTypeDirDescription
FileHandlePHANDLEoutReceives the handle to the newly created server end of the named pipe.
DesiredAccessULONGinAccess mask, typically GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE.
ObjectAttributesPOBJECT_ATTRIBUTESinNames the pipe under \Device\NamedPipe (e.g. \??\pipe\msagent_xx) and supplies the SECURITY_DESCRIPTOR.
IoStatusBlockPIO_STATUS_BLOCKoutReceives the final NTSTATUS and information code (FILE_CREATED / FILE_OPENED).
ShareAccessULONGinFILE_SHARE_* flags controlling concurrent open semantics for the named pipe.
CreateDispositionULONGinFILE_CREATE, FILE_OPEN or FILE_OPEN_IF; controls behaviour if the name already exists.
CreateOptionsULONGinFILE_SYNCHRONOUS_IO_NONALERT and friends — same flag set as NtCreateFile.
NamedPipeTypeULONGinFILE_PIPE_BYTE_STREAM_TYPE or FILE_PIPE_MESSAGE_TYPE — wire format.
ReadModeULONGinFILE_PIPE_BYTE_STREAM_MODE or FILE_PIPE_MESSAGE_MODE for reads.
CompletionModeULONGinFILE_PIPE_QUEUE_OPERATION (blocking) or FILE_PIPE_COMPLETE_OPERATION (return immediately).
MaximumInstancesULONGinMaximum concurrent server instances of this pipe name; PIPE_UNLIMITED_INSTANCES = 0xFF.
InboundQuotaULONGinBuffer size for client→server data, in bytes.
OutboundQuotaULONGinBuffer size for server→client data, in bytes.
DefaultTimeoutPLARGE_INTEGERinDefault timeout for blocking operations (100-ns units, negative = relative). NULL = 50 ms.

Syscall IDs by Windows version

Windows versionSyscall IDBuild
Win10 15070xA8win10-1507
Win10 16070xAAwin10-1607
Win10 17030xADwin10-1703
Win10 17090xAEwin10-1709
Win10 18030xAFwin10-1803
Win10 18090xAFwin10-1809
Win10 19030xB0win10-1903
Win10 19090xB0win10-1909
Win10 20040xB4win10-2004
Win10 20H20xB4win10-20h2
Win10 21H10xB4win10-21h1
Win10 21H20xB5win10-21h2
Win10 22H20xB5win10-22h2
Win11 21H20xB8win11-21h2
Win11 22H20xB9win11-22h2
Win11 23H20xB9win11-23h2
Win11 24H20xBBwin11-24h2
Server 20160xAAwinserver-2016
Server 20190xAFwinserver-2019
Server 20220xB7winserver-2022
Server 20250xBBwinserver-2025

Kernel module

ntoskrnl.exeNtCreateNamedPipeFile

Related APIs

CreateNamedPipeWConnectNamedPipeDisconnectNamedPipeWaitNamedPipeWCallNamedPipeWNtFsControlFileNtCreateFile

Syscall stub

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

Undocumented notes

`NtCreateNamedPipeFile` is the largest single Native API by parameter count (14) and the foundation for `CreateNamedPipeW`. Pipe names live under `\Device\NamedPipe\`; the user-mode form is `\\.\pipe\<name>` or, remotely, `\\<host>\pipe\<name>`. Remote opens travel over SMB and are subject to firewall/NetBIOS settings — which is exactly why Cobalt Strike's SMB beacon listens on a named pipe rather than a TCP socket. The SSN changes every two or three feature updates (`0xA8` on Win10 1507 → `0xBB` on Win11 24H2), so portable shellcode resolves it dynamically.

Common malware usage

Named pipes are the *de facto* IPC channel for modern post-exploitation: - **Cobalt Strike SMB beacon**: peer beacons connect over a server-named pipe (default `\\.\pipe\msagent_xx`, `\\.\pipe\status_xx`, etc.). C2 traffic is tunnelled inside the pipe so it never touches the network adapter of the egress host. - **Sliver named-pipe transport**: same idea — implant↔implant communication for lateral movement without opening new TCP ports. - **PsExec-style services** create `\pipe\psexesvc` for command-channel return. - Many ransomware families (Conti, BlackCat) coordinate their encryption workers over a pipe to centralise progress reporting. The attacker chooses a pipe name that mimics a legitimate Microsoft service (`\pipe\lsass`, `\pipe\spoolss`, `\pipe\mojo.*`) to blend in with browser/IPC noise.

Detection opportunities

Sysmon **Event ID 17 (PipeEvent: Pipe Created)** and **18 (PipeEvent: Pipe Connected)** are the highest-signal detections for this syscall. Unusual pipe names — random suffixes, GUID-looking names, `msagent_*` on a non-Cobalt-targeted host, or `\pipe\` openings from unexpected processes (e.g. notepad.exe, wmiprvse.exe) — are strong indicators of an SMB beacon or peer-to-peer implant. ETW provider `Microsoft-Windows-Kernel-File` covers create/open of pipe FOs. EDRs also alert on the pattern `NtCreateNamedPipeFile` followed by `NtFsControlFile(FSCTL_PIPE_LISTEN)` from a non-service process.

Direct syscall examples

asmx64 direct stub (Win11 24H2)

; Direct syscall stub for NtCreateNamedPipeFile (SSN 0xBB on Win11 24H2)
NtCreateNamedPipeFile PROC
    mov  r10, rcx          ; FileHandle
    mov  eax, 0BBh         ; SSN — version-sensitive, resolve dynamically
    syscall
    ret
NtCreateNamedPipeFile ENDP

cCobalt-Strike-style SMB beacon listener

// Create \\.\pipe\msagent_42 as a message-mode server pipe.
#include <windows.h>
#include <winternl.h>

typedef NTSTATUS (NTAPI *pNtCreateNamedPipeFile)(
    PHANDLE, ULONG, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK,
    ULONG, ULONG, ULONG, ULONG, ULONG, ULONG, ULONG, ULONG, ULONG, PLARGE_INTEGER);

HANDLE OpenBeaconPipe(void) {
    UNICODE_STRING name;
    RtlInitUnicodeString(&name, L"\\??\\pipe\\msagent_42");
    OBJECT_ATTRIBUTES oa;
    InitializeObjectAttributes(&oa, &name, OBJ_CASE_INSENSITIVE, NULL, NULL);
    IO_STATUS_BLOCK iosb = {0};
    LARGE_INTEGER timeout; timeout.QuadPart = -50LL * 10000LL; // 50 ms
    HANDLE hPipe = NULL;

    pNtCreateNamedPipeFile fn = (pNtCreateNamedPipeFile)GetProcAddress(
        GetModuleHandleA("ntdll.dll"), "NtCreateNamedPipeFile");
    fn(&hPipe,
       GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
       &oa, &iosb,
       FILE_SHARE_READ | FILE_SHARE_WRITE,
       FILE_CREATE,
       FILE_SYNCHRONOUS_IO_NONALERT,
       1 /* FILE_PIPE_MESSAGE_TYPE   */,
       1 /* FILE_PIPE_MESSAGE_MODE   */,
       0 /* FILE_PIPE_QUEUE_OP       */,
       0xFF /* PIPE_UNLIMITED_INSTANCES */,
       0x1000, 0x1000,
       &timeout);
    return hPipe;
}

rustwindows-sys wrapper

// Cargo: windows-sys = "0.59", features = ["Wdk_Storage_FileSystem", "Win32_System_IO"]
use std::ptr::null_mut;
use windows_sys::Wdk::Storage::FileSystem::NtCreateNamedPipeFile;
use windows_sys::Win32::Storage::FileSystem::*;
use windows_sys::Win32::System::IO::IO_STATUS_BLOCK;
use windows_sys::Win32::System::WindowsProgramming::*;
use windows_sys::Wdk::Foundation::OBJECT_ATTRIBUTES;

pub fn create_message_pipe(_name: &str) -> isize {
    let mut handle: isize = 0;
    let mut iosb: IO_STATUS_BLOCK = unsafe { std::mem::zeroed() };
    let timeout: i64 = -50 * 10_000; // 50 ms relative
    // ObjectAttributes / UNICODE_STRING construction elided — see ntdll helpers.
    let oa: OBJECT_ATTRIBUTES = unsafe { std::mem::zeroed() };
    unsafe {
        NtCreateNamedPipeFile(
            &mut handle,
            (GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE) as u32,
            &oa, &mut iosb,
            (FILE_SHARE_READ | FILE_SHARE_WRITE) as u32,
            FILE_CREATE,
            FILE_SYNCHRONOUS_IO_NONALERT,
            1, 1, 0, 0xFF, 0x1000, 0x1000,
            &timeout as *const _ as *mut _,
        );
    }
    handle
}

MITRE ATT&CK mappings

Last verified: 2026-05-20