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
| Name | Type | Dir | Description |
|---|---|---|---|
| PortHandle | PHANDLE | out | Recibe el handle del nuevo puerto de conexión del servidor. |
| ObjectAttributes | POBJECT_ATTRIBUTES | in | Nombra el puerto en el espacio de objetos (p. ej. \RPC Control\foo) y aporta un SECURITY_DESCRIPTOR. |
| PortAttributes | PALPC_PORT_ATTRIBUTES | in | Límites y comportamiento del puerto (MaxMessageLength, MemoryBandwidth, MaxViewSize, SecurityQos, Flags). |
IDs de syscalls por versión de Windows
| Versión de Windows | ID de syscall | Build |
|---|---|---|
| Win10 1507 | 0x77 | win10-1507 |
| Win10 1607 | 0x77 | win10-1607 |
| Win10 1703 | 0x78 | win10-1703 |
| Win10 1709 | 0x78 | win10-1709 |
| Win10 1803 | 0x79 | win10-1803 |
| Win10 1809 | 0x79 | win10-1809 |
| Win10 1903 | 0x79 | win10-1903 |
| Win10 1909 | 0x79 | win10-1909 |
| Win10 2004 | 0x7B | win10-2004 |
| Win10 20H2 | 0x7B | win10-20h2 |
| Win10 21H1 | 0x7B | win10-21h1 |
| Win10 21H2 | 0x7B | win10-21h2 |
| Win10 22H2 | 0x7B | win10-22h2 |
| Win11 21H2 | 0x7B | win11-21h2 |
| Win11 22H2 | 0x7B | win11-22h2 |
| Win11 23H2 | 0x7B | win11-23h2 |
| Win11 24H2 | 0x7D | win11-24h2 |
| Server 2016 | 0x77 | winserver-2016 |
| Server 2019 | 0x79 | winserver-2019 |
| Server 2022 | 0x7B | winserver-2022 |
| Server 2025 | 0x7D | winserver-2025 |
Módulo del kernel
APIs relacionadas
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 ENDPcMinimal 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