> Windows Syscalls
ntoskrnl.exeT1068T1559T1106

NtAlpcCreatePort

Erzeugt einen serverseitigen ALPC-Connection-Port, den Clients per NtAlpcConnectPort erreichen können.

Prototyp

NTSTATUS NtAlpcCreatePort(
  PHANDLE               PortHandle,
  POBJECT_ATTRIBUTES    ObjectAttributes,
  PALPC_PORT_ATTRIBUTES PortAttributes
);

Argumente

NameTypeDirDescription
PortHandlePHANDLEoutEmpfängt das Handle des neuen Server-Connection-Ports.
ObjectAttributesPOBJECT_ATTRIBUTESinBenennt den Port im Object-Namespace (z. B. \RPC Control\foo) und liefert einen SECURITY_DESCRIPTOR.
PortAttributesPALPC_PORT_ATTRIBUTESinPort-Limits und -Verhalten (MaxMessageLength, MemoryBandwidth, MaxViewSize, SecurityQos, Flags).

Syscall-IDs pro Windows-Version

Windows-VersionSyscall-IDBuild
Win10 15070x77win10-1507
Win10 16070x77win10-1607
Win10 17030x78win10-1703
Win10 17090x78win10-1709
Win10 18030x79win10-1803
Win10 18090x79win10-1809
Win10 19030x79win10-1903
Win10 19090x79win10-1909
Win10 20040x7Bwin10-2004
Win10 20H20x7Bwin10-20h2
Win10 21H10x7Bwin10-21h1
Win10 21H20x7Bwin10-21h2
Win10 22H20x7Bwin10-22h2
Win11 21H20x7Bwin11-21h2
Win11 22H20x7Bwin11-22h2
Win11 23H20x7Bwin11-23h2
Win11 24H20x7Dwin11-24h2
Server 20160x77winserver-2016
Server 20190x79winserver-2019
Server 20220x7Bwinserver-2022
Server 20250x7Dwinserver-2025

Kernel-Modul

ntoskrnl.exeNtAlpcCreatePort

Verwandte APIs

NtAlpcConnectPortNtAlpcAcceptConnectPortNtAlpcSendWaitReceivePortNtAlpcDisconnectPortRpcServerUseProtseqEpWRpcServerRegisterIfEx

Syscall-Stub

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

`NtAlpcCreatePort` allokiert den **Connection-Port** auf Server-Seite — das Lausch-Objekt, das Clients später per `NtAlpcConnectPort` adressieren. Das zurückgegebene Handle ist *noch kein* Communication-Endpoint; es ist die Bind-Socket. Jeder akzeptierte Client bekommt einen eigenen Per-Connection-Port über `NtAlpcAcceptConnectPort`. Serverprozesse registrieren den Port typischerweise unter `\RPC Control\<Endpoint>` (für RPC über `ncalrpc`) oder `\Sessions\<n>\AppContainerNamedObjects\...` (für AppContainer-isolierten IPC). Die Kernel-Implementierung lebt in `AlpcpCreateConnectionPort` in ntoskrnl.exe.

Häufige Malware-Nutzung

Drei in der Wildnis beobachtete Winkel: 1. **Schädlicher RPC-Server**: ein Implant exponiert einen `\RPC Control\<Name>`-Port, damit Peer-Implants Befehle absetzen — oft kombiniert mit einem gestohlenen ETW- oder NDIS-Service-Token, damit die Verbindung aus privilegiertem Kontext zu kommen scheint. 2. **Exploit-Setup**: jeder ALPC-LPE-PoC baut die Trigger-Infrastruktur um ein Paar `NtAlpcCreatePort`-Aufrufe — einer für den Fake-Server, einer für den nachgemachten Handshake (z. B. SandboxEscapers *AlpcRpcGetUserName*-Trick vor CVE-2018-8440). 3. **Verdeckter Peer-to-Peer-C2**: ein Beacon, der als SYSTEM läuft, erzeugt einen ACL-eingeschränkten ALPC-Port; ein zweites Implant im User-Context verbindet sich. Verkehr bleibt komplett im Kernel und erreicht den Netzwerk-Stack nie.

Erkennungs­möglichkeiten

ALPC-Ports pro Prozess enumerieren (SystemInformer, `!alpc` in WinDbg, oder `Get-WinEvent -ProviderName 'Microsoft-Windows-Kernel-ALPC'` falls aktiv) zeigt Nicht-Microsoft-Prozesse, die einen Connection-Port hosten — eine sehr kleine Population auf einer typischen Workstation. Verdächtige DACLs (Port, der `Everyone` Verbindung erlaubt, oder Port im Besitz eines User-Context-Prozesses mit RPC-Service-Imitations-Namen) sind starke Indikatoren. Mit ETW `Microsoft-Windows-RPC` kombinieren, um zu sehen, welche Interfaces auf dem Port registriert sind — ein ALPC-Port ohne registriertes Interface, der Verbindungen akzeptiert, ist per Definition kein RPC und gehört untersucht.

Direkte Syscall-Beispiele

asmx64 direct stub (Win11 24H2)

; Direct syscall stub for NtAlpcCreatePort (SSN 0x7D on Win11 24H2)
NtAlpcCreatePort PROC
    mov  r10, rcx          ; PortHandle
    mov  eax, 7Dh          ; SSN — version-sensitive, resolve dynamically
    syscall
    ret
NtAlpcCreatePort ENDP

cMinimal LRPC server bind

// Create \RPC Control\demo_port as a server connection port.
#include <windows.h>
#include <winternl.h>

typedef struct _ALPC_PORT_ATTRIBUTES {
    ULONG Flags;
    SECURITY_QUALITY_OF_SERVICE SecurityQos;
    SIZE_T MaxMessageLength;
    SIZE_T MemoryBandwidth;
    SIZE_T MaxPoolUsage;
    SIZE_T MaxSectionSize;
    SIZE_T MaxViewSize;
    SIZE_T MaxTotalSectionSize;
    ULONG DupObjectTypes;
#ifdef _WIN64
    ULONG Reserved;
#endif
} ALPC_PORT_ATTRIBUTES, *PALPC_PORT_ATTRIBUTES;

typedef NTSTATUS (NTAPI *pNtAlpcCreatePort)(
    PHANDLE, POBJECT_ATTRIBUTES, PALPC_PORT_ATTRIBUTES);

HANDLE CreateServer(LPCWSTR name) {
    UNICODE_STRING us; RtlInitUnicodeString(&us, name);
    OBJECT_ATTRIBUTES oa;
    InitializeObjectAttributes(&oa, &us, OBJ_CASE_INSENSITIVE, NULL, NULL);
    ALPC_PORT_ATTRIBUTES pa = {0};
    pa.MaxMessageLength = 0x1000;
    pa.SecurityQos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
    pa.SecurityQos.ImpersonationLevel = SecurityImpersonation;
    pa.SecurityQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
    pa.SecurityQos.EffectiveOnly = FALSE;
    HANDLE hPort = NULL;
    pNtAlpcCreatePort fn = (pNtAlpcCreatePort)GetProcAddress(
        GetModuleHandleA("ntdll.dll"), "NtAlpcCreatePort");
    fn(&hPort, &oa, &pa);
    return hPort;
}

rustwindows-sys handle wrapper

// Cargo: windows-sys = "0.59", features = ["Wdk_Foundation", "Win32_Foundation"]
use std::ptr::null_mut;
use windows_sys::Win32::Foundation::HANDLE;
use windows_sys::Wdk::Foundation::OBJECT_ATTRIBUTES;

// Phnt ALPC bindings are not in windows-sys today; resolve dynamically.
type FnCreate = unsafe extern "system" fn(
    *mut HANDLE, *const OBJECT_ATTRIBUTES, *const u8,
) -> i32;

pub unsafe fn create_alpc_port(
    name_obj_attrs: *const OBJECT_ATTRIBUTES,
    attrs: *const u8,
) -> HANDLE {
    let ntdll = libloading::Library::new("ntdll.dll").unwrap();
    let f: libloading::Symbol<FnCreate> = ntdll.get(b"NtAlpcCreatePort\0").unwrap();
    let mut h: HANDLE = 0;
    let _ = f(&mut h, name_obj_attrs, attrs);
    h
}

MITRE ATT&CK-Mappings

Last verified: 2026-05-20