> Windows Syscalls
ntoskrnl.exeT1068T1559T1106

NtAlpcCreatePort

Crea un puerto de conexión ALPC del lado servidor que los clientes pueden alcanzar con NtAlpcConnectPort.

Prototipo

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

Argumentos

NameTypeDirDescription
PortHandlePHANDLEoutRecibe el handle del nuevo puerto de conexión del servidor.
ObjectAttributesPOBJECT_ATTRIBUTESinNombra el puerto en el espacio de objetos (p. ej. \RPC Control\foo) y aporta un SECURITY_DESCRIPTOR.
PortAttributesPALPC_PORT_ATTRIBUTESinLímites y comportamiento del puerto (MaxMessageLength, MemoryBandwidth, MaxViewSize, SecurityQos, Flags).

IDs de syscalls por versión de Windows

Versión de WindowsID de syscallBuild
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

Módulo del kernel

ntoskrnl.exeNtAlpcCreatePort

APIs relacionadas

NtAlpcConnectPortNtAlpcAcceptConnectPortNtAlpcSendWaitReceivePortNtAlpcDisconnectPortRpcServerUseProtseqEpWRpcServerRegisterIfEx

Stub del syscall

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

Notas no documentadas

`NtAlpcCreatePort` asigna el **puerto de conexión** del lado servidor — el objeto de escucha que los clientes apuntarán luego con `NtAlpcConnectPort`. El handle devuelto *no* es todavía un endpoint de comunicación; es el bind socket. Cada cliente aceptado recibe su propio puerto por-conexión vía `NtAlpcAcceptConnectPort`. Los procesos servidores típicamente registran el puerto bajo `\RPC Control\<endpoint>` (para RPC sobre `ncalrpc`) o `\Sessions\<n>\AppContainerNamedObjects\...` (para IPC aislado AppContainer). La implementación de kernel vive en `AlpcpCreateConnectionPort` dentro de ntoskrnl.exe.

Uso común por malware

Tres ángulos vistos en estado salvaje: 1. **Servidor RPC malicioso**: un implante expone un puerto `\RPC Control\<nombre>` para que implantes pares emitan comandos, a menudo combinado con un token de servicio ETW o NDIS capturado para aparentar un contexto privilegiado. 2. **Andamiaje de exploit**: cada PoC LPE ALPC construye el andamiaje gatillo en torno a una pareja de llamadas `NtAlpcCreatePort` — uno para el servidor falso, otro para el handshake simulado (p. ej. el truco *AlpcRpcGetUserName* de SandboxEscaper antes de CVE-2018-8440). 3. **C2 peer-to-peer sigiloso**: un beacon en SYSTEM crea un puerto ALPC con DACL restringida; un segundo implante en contexto de usuario se conecta. El tráfico es íntegramente in-kernel y nunca alcanza la pila de red.

Oportunidades de detección

Enumerar puertos ALPC por proceso (SystemInformer, `!alpc` en WinDbg, o `Get-WinEvent -ProviderName 'Microsoft-Windows-Kernel-ALPC'` si está activo) revela procesos no Microsoft hospedando un puerto de conexión — población muy pequeña en una estación típica. DACLs sospechosas (puerto que permite `Everyone`, o puerto perteneciente a proceso user-context con nombre que imita un servicio RPC) son indicadores fuertes. Combinar con ETW `Microsoft-Windows-RPC` para ver qué interfaces están registradas — un puerto ALPC sin interfaz pero que acepta conexiones no es RPC por definición y merece investigación.

Ejemplos de syscalls directos

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
}

Mapeos MITRE ATT&CK

Last verified: 2026-05-20