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
| Name | Type | Dir | Description |
|---|---|---|---|
| FileHandle | PHANDLE | out | Receives the handle to the newly created server end of the named pipe. |
| DesiredAccess | ULONG | in | Access mask, typically GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE. |
| ObjectAttributes | POBJECT_ATTRIBUTES | in | Names the pipe under \Device\NamedPipe (e.g. \??\pipe\msagent_xx) and supplies the SECURITY_DESCRIPTOR. |
| IoStatusBlock | PIO_STATUS_BLOCK | out | Receives the final NTSTATUS and information code (FILE_CREATED / FILE_OPENED). |
| ShareAccess | ULONG | in | FILE_SHARE_* flags controlling concurrent open semantics for the named pipe. |
| CreateDisposition | ULONG | in | FILE_CREATE, FILE_OPEN or FILE_OPEN_IF; controls behaviour if the name already exists. |
| CreateOptions | ULONG | in | FILE_SYNCHRONOUS_IO_NONALERT and friends — same flag set as NtCreateFile. |
| NamedPipeType | ULONG | in | FILE_PIPE_BYTE_STREAM_TYPE or FILE_PIPE_MESSAGE_TYPE — wire format. |
| ReadMode | ULONG | in | FILE_PIPE_BYTE_STREAM_MODE or FILE_PIPE_MESSAGE_MODE for reads. |
| CompletionMode | ULONG | in | FILE_PIPE_QUEUE_OPERATION (blocking) or FILE_PIPE_COMPLETE_OPERATION (return immediately). |
| MaximumInstances | ULONG | in | Maximum concurrent server instances of this pipe name; PIPE_UNLIMITED_INSTANCES = 0xFF. |
| InboundQuota | ULONG | in | Buffer size for client→server data, in bytes. |
| OutboundQuota | ULONG | in | Buffer size for server→client data, in bytes. |
| DefaultTimeout | PLARGE_INTEGER | in | Default timeout for blocking operations (100-ns units, negative = relative). NULL = 50 ms. |
Syscall IDs by Windows version
| Windows version | Syscall ID | Build |
|---|---|---|
| Win10 1507 | 0xA8 | win10-1507 |
| Win10 1607 | 0xAA | win10-1607 |
| Win10 1703 | 0xAD | win10-1703 |
| Win10 1709 | 0xAE | win10-1709 |
| Win10 1803 | 0xAF | win10-1803 |
| Win10 1809 | 0xAF | win10-1809 |
| Win10 1903 | 0xB0 | win10-1903 |
| Win10 1909 | 0xB0 | win10-1909 |
| Win10 2004 | 0xB4 | win10-2004 |
| Win10 20H2 | 0xB4 | win10-20h2 |
| Win10 21H1 | 0xB4 | win10-21h1 |
| Win10 21H2 | 0xB5 | win10-21h2 |
| Win10 22H2 | 0xB5 | win10-22h2 |
| Win11 21H2 | 0xB8 | win11-21h2 |
| Win11 22H2 | 0xB9 | win11-22h2 |
| Win11 23H2 | 0xB9 | win11-23h2 |
| Win11 24H2 | 0xBB | win11-24h2 |
| Server 2016 | 0xAA | winserver-2016 |
| Server 2019 | 0xAF | winserver-2019 |
| Server 2022 | 0xB7 | winserver-2022 |
| Server 2025 | 0xBB | winserver-2025 |
Kernel module
Related APIs
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 ENDPcCobalt-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