NtConnectPort
Client-seitige Verbindung zu einem Legacy-LPC-Server-Port, das Pre-ALPC-Pendant zu NtAlpcConnectPort.
Prototyp
NTSTATUS NtConnectPort( PHANDLE PortHandle, PUNICODE_STRING PortName, PSECURITY_QUALITY_OF_SERVICE SecurityQos, PPORT_VIEW ClientView, PREMOTE_PORT_VIEW ServerView, PULONG MaxMessageLength, PVOID ConnectionInformation, PULONG ConnectionInformationLength );
Argumente
| Name | Type | Dir | Description |
|---|---|---|---|
| PortHandle | PHANDLE | out | Empfängt das Handle auf den verbundenen Client-Port, wenn der Server annimmt. |
| PortName | PUNICODE_STRING | in | Voll qualifizierter LPC-Port-Name im Object-Namespace, z. B. \RPC Control\myport. |
| SecurityQos | PSECURITY_QUALITY_OF_SERVICE | in | Impersonation-Level und Tracking-Modus, den der Server dem Client zuweisen darf (üblicherweise Identification). |
| ClientView | PPORT_VIEW | in/out | Optionale Shared-Section, die der Client dem Server anbietet; wird mit der Server-seitigen Adresse befüllt. |
| ServerView | PREMOTE_PORT_VIEW | out | Empfängt die Shared-Section-View des Servers (sofern dieser im Accept eine angehängt hat). |
| MaxMessageLength | PULONG | out | Empfängt die mit dem Server ausgehandelte maximale LPC-Message-Länge (PORT_MAXIMUM_MESSAGE_LENGTH = 256). |
| ConnectionInformation | PVOID | in/out | Optionale Payload im Connect; bei Rückkehr mit den Connect-Accept-Daten des Servers überschrieben. |
| ConnectionInformationLength | PULONG | in/out | Eingangs Größe von ConnectionInformation; ausgangs Größe der Server-Antwort. |
Syscall-IDs pro Windows-Version
| Windows-Version | Syscall-ID | Build |
|---|---|---|
| Win10 1507 | 0x99 | win10-1507 |
| Win10 1607 | 0x9A | win10-1607 |
| Win10 1703 | 0x9C | win10-1703 |
| Win10 1709 | 0x9D | win10-1709 |
| Win10 1803 | 0x9E | win10-1803 |
| Win10 1809 | 0x9E | win10-1809 |
| Win10 1903 | 0x9E | win10-1903 |
| Win10 1909 | 0x9E | win10-1909 |
| Win10 2004 | 0xA0 | win10-2004 |
| Win10 20H2 | 0xA0 | win10-20h2 |
| Win10 21H1 | 0xA0 | win10-21h1 |
| Win10 21H2 | 0xA0 | win10-21h2 |
| Win10 22H2 | 0xA0 | win10-22h2 |
| Win11 21H2 | 0xA2 | win11-21h2 |
| Win11 22H2 | 0xA2 | win11-22h2 |
| Win11 23H2 | 0xA2 | win11-23h2 |
| Win11 24H2 | 0xA4 | win11-24h2 |
| Server 2016 | 0x9A | winserver-2016 |
| Server 2019 | 0x9E | winserver-2019 |
| Server 2022 | 0xA2 | winserver-2022 |
| Server 2025 | 0xA4 | winserver-2025 |
Kernel-Modul
Verwandte APIs
Syscall-Stub
4C 8B D1 mov r10, rcx B8 A4 00 00 00 mov eax, 0xA4 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
NtConnectPort ist das Client-Gegenstück zu NtAcceptConnectPort und der Pre-Vista-Vorläufer von NtAlpcConnectPort. Die 8-Argument-Signatur ist von phnt und dem Windows-Internals-Buch dokumentiert; die Kernel-Implementierung liegt in `LpcpConnectPort` in ntoskrnl.exe. Obwohl ALPC LPC ab Vista funktional ablöste, wurde der LPC-Dispatch-Pfad nie entfernt — diese SSNs sind weiterhin verdrahtet und liefern auf Windows 11 24H2 funktionierenden Code. Die SSN driftet zwischen Builds (anders als bei NtAcceptConnectPort), Direkt-Syscall-Stubs müssen sie also dynamisch auflösen.
Häufige Malware-Nutzung
Moderne Malware wählt selten LPC anstelle von ALPC oder Named Pipes, doch die Fläche bleibt eine brauchbare IPC-Primitive für Komponenten, die die besser instrumentierten ALPC-Pfade meiden wollen. Historisch (XP- / 2003-Ära) nutzten manche User-Mode-Rootkits LPC zur Inter-Modul-Kommunikation zwischen Loader und injiziertem Payload, da kein Win32-Wrapper existierte und der Verkehr vollständig im Kernel blieb. Heute ist die praktische Relevanz vor allem *historisch und didaktisch*; jeder User-Mode-Caller ist verdächtig, da auf zeitgenössischem Windows kaum etwas legitim rohes LPC einsetzt.
Erkennungsmöglichkeiten
Es gibt keinen ETW-Provider `Microsoft-Windows-Kernel-LPC` analog zu ALPC; Verteidiger verlassen sich auf Syscall-Tabellen-Hooks (Kernel-EDR) oder User-Mode-Hooks auf `ntdll!NtConnectPort`. Die Baseline ist auf Windows 10/11 so niedrig, dass *jeder* Treffer auf NtConnectPort aus einem Nicht-System-Prozess alarmwürdig ist. SystemInformer listet LPC- und ALPC-Ports pro Prozess — ein unerwartetes LPC-Handle in einer Sandbox-App oder einem unsignierten Binary ist ein hochkonfidentes Indiz. PORT_VIEW Shared-Sections erzeugen zudem VAD-Einträge, die die Verbindung überdauern.
Direkte Syscall-Beispiele
asmx64 direct stub (Win11 24H2)
; Direct syscall stub for NtConnectPort (SSN 0xA4 on Win11 24H2 — drifts per build)
NtConnectPort PROC
mov r10, rcx ; PortHandle
mov eax, 0A4h ; SSN
syscall
ret
NtConnectPort ENDPcConnect to a named LPC server
// Connect to a legacy LPC server port; minimal connect message, no shared view.
#include <windows.h>
#include <winternl.h>
typedef NTSTATUS (NTAPI *pNtConnectPort)(
PHANDLE, PUNICODE_STRING, PVOID /*PSECURITY_QOS*/,
PVOID, PVOID, PULONG, PVOID, PULONG);
HANDLE LpcConnect(LPCWSTR name) {
UNICODE_STRING us; RtlInitUnicodeString(&us, name);
SECURITY_QUALITY_OF_SERVICE qos = {
sizeof(qos), SecurityIdentification, SECURITY_DYNAMIC_TRACKING, FALSE
};
HANDLE h = NULL; ULONG maxLen = 0, cinfoLen = 0;
pNtConnectPort fn = (pNtConnectPort)GetProcAddress(
GetModuleHandleA("ntdll.dll"), "NtConnectPort");
fn(&h, &us, &qos, NULL, NULL, &maxLen, NULL, &cinfoLen);
return h;
}rustResolve and call via GetProcAddress
// Cargo: windows-sys = "0.59"
use std::ffi::c_void;
use windows_sys::Win32::System::LibraryLoader::{GetModuleHandleA, GetProcAddress};
type NtConnectPortFn = unsafe extern "system" fn(
*mut *mut c_void, *const c_void, *const c_void,
*mut c_void, *mut c_void, *mut u32, *mut c_void, *mut u32,
) -> i32;
unsafe fn resolve() -> Option<NtConnectPortFn> {
let h = GetModuleHandleA(b"ntdll.dll\0".as_ptr());
let p = GetProcAddress(h, b"NtConnectPort\0".as_ptr())?;
Some(std::mem::transmute(p))
}MITRE ATT&CK-Mappings
Last verified: 2026-05-20