> Windows Syscalls
ntoskrnl.exeT1559T1106

NtRequestWaitReplyPort

Envoie une requête LPC synchrone et bloque jusqu'à la réponse du serveur — la primitive RPC historique.

Prototype

NTSTATUS NtRequestWaitReplyPort(
  HANDLE         PortHandle,
  PPORT_MESSAGE  Request,
  PPORT_MESSAGE  Reply
);

Arguments

NameTypeDirDescription
PortHandleHANDLEinHandle vers un port LPC connecté, précédemment retourné par NtConnectPort / NtSecureConnectPort.
RequestPPORT_MESSAGEinEn-tête PORT_MESSAGE suivi du payload inline (≤ 256 octets pour les messages courts).
ReplyPPORT_MESSAGEoutTampon alloué par l'appelant recevant la réponse serveur ; doit être ≥ MaxMessageLength.

IDs de syscalls par version de Windows

Version de WindowsID de syscallBuild
Win10 15070x22win10-1507
Win10 16070x22win10-1607
Win10 17030x22win10-1703
Win10 17090x22win10-1709
Win10 18030x22win10-1803
Win10 18090x22win10-1809
Win10 19030x22win10-1903
Win10 19090x22win10-1909
Win10 20040x22win10-2004
Win10 20H20x22win10-20h2
Win10 21H10x22win10-21h1
Win10 21H20x22win10-21h2
Win10 22H20x22win10-22h2
Win11 21H20x22win11-21h2
Win11 22H20x22win11-22h2
Win11 23H20x22win11-23h2
Win11 24H20x22win11-24h2
Server 20160x22winserver-2016
Server 20190x22winserver-2019
Server 20220x22winserver-2022
Server 20250x22winserver-2025

Module noyau

ntoskrnl.exeNtRequestWaitReplyPort

APIs liées

NtRequestPortNtReplyPortNtReplyWaitReceivePortNtConnectPortNtAlpcSendWaitReceivePort

Stub du syscall

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

Notes non documentées

NtRequestWaitReplyPort est la primitive request/response synchrone du sous-système **LPC** historique — conceptuellement équivalente à `NtAlpcSendWaitReceivePort` avec `ALPC_MSGFLG_SYNC_REQUEST`. Elle envoie un PORT_MESSAGE et bloque le thread appelant jusqu'à ce que le serveur réponde via `NtReplyPort` ou `NtReplyWaitReceivePort`. Le SSN `0x22` est gelé depuis Windows 10 1507, reflétant le statut legacy de LPC dans la table. Le payload inline est plafonné à PORT_MAXIMUM_MESSAGE_LENGTH (256 octets) ; au-delà il faut une PORT_VIEW partagée échangée au connect.

Usage courant par les malwares

Sur Windows contemporain, l'usage pratique de NtRequestWaitReplyPort par les malwares est essentiellement *historique* : les rootkits user-mode pré-Vista et les premiers droppers IPC-aware l'utilisaient comme C2 furtif intra-host entre un loader et un payload injecté car aucun wrapper Win32 n'existait et le trafic ne touchait jamais la pile réseau. Les attaquants modernes préfèrent largement ALPC, les named pipes ou les sections partagées — toute observation de trafic LPC brut request/reply est donc en soi anormale et mérite enquête.

Opportunités de détection

Pas de provider ETW dédié au LPC historique équivalent à `Microsoft-Windows-Kernel-ALPC`. Les EDR kernel peuvent hooker le syscall directement ; les EDR user-mode hookent `ntdll!NtRequestWaitReplyPort`. Comme la baseline d'appelants légitimes sur Windows 10/11 est quasi nulle (presque rien dans l'OS n'utilise plus de LPC brut pour RPC), *tout* hit depuis un processus non signé ou sandboxé est à fort signal. La vue de ports par processus de SystemInformer affiche les handles LPC distinctement des handles ALPC.

Exemples de syscalls directs

asmx64 direct stub

; Direct syscall stub for NtRequestWaitReplyPort (SSN 0x22, stable Win10 1507+)
NtRequestWaitReplyPort PROC
    mov  r10, rcx          ; PortHandle
    mov  eax, 22h          ; SSN
    syscall
    ret
NtRequestWaitReplyPort ENDP

cSynchronous LPC request

// Send a request and wait for the reply on a connected LPC port.
#include <windows.h>
#include <winternl.h>

#define PORT_MAXIMUM_MESSAGE_LENGTH 256

typedef NTSTATUS (NTAPI *pNtRequestWaitReplyPort)(
    HANDLE, PVOID /*PPORT_MESSAGE*/, PVOID /*PPORT_MESSAGE*/);

NTSTATUS LpcCall(HANDLE hPort, void *reqBuf, void *replyBuf) {
    pNtRequestWaitReplyPort fn = (pNtRequestWaitReplyPort)GetProcAddress(
        GetModuleHandleA("ntdll.dll"), "NtRequestWaitReplyPort");
    return fn(hPort, reqBuf, replyBuf);
}

rustFFI declaration via ntapi

// Cargo: ntapi = "0.4"
use ntapi::ntlpcapi::NtRequestWaitReplyPort;
use winapi::shared::ntdef::{HANDLE, NTSTATUS};

unsafe fn lpc_call(port: HANDLE, req: *mut u8, reply: *mut u8) -> NTSTATUS {
    NtRequestWaitReplyPort(port, req as *mut _, reply as *mut _)
}

Mappings MITRE ATT&CK

Last verified: 2026-05-20