WSK Connect failed

Hello, I've been interested in kernel development lately, I'm working on a driver that uses WSK. So what I want is to connect to here -> (http://192.168.0.106:8080)

Under the code is a screenshot of what happens

#include <ntifs.h>
#include <ntddk.h>
#include <stdio.h>
#include <wsk.h>
#include <windef.h>

#define ADDR "192.168.0.104"
#define PORT 8080
#define WSK_WAIT_TIMEOUT 15


const WSK_CLIENT_DISPATCH WskAppDispatch = {
  MAKE_WSK_VERSION(1,0),
  0,
  NULL
};

typedef struct _WSK_APP_SOCKET_CONTEXT {
    PWSK_SOCKET Socket;
    SOCKADDR_IN localAddr;
} WSK_APP_SOCKET_CONTEXT, * PWSK_APP_SOCKET_CONTEXT;

WSK_APP_SOCKET_CONTEXT sockContext;
WSK_REGISTRATION wskRegistration;
WSK_PROVIDER_NPI wskProviderNpi;

NTSTATUS SyncIrpCompRtn(PDEVICE_OBJECT Reserved, PIRP Irp, PVOID Context) {
    PKEVENT compEvent = (PKEVENT)Context;
    if (Irp->PendingReturned) {
        KeSetEvent(compEvent, 2, FALSE);
    }
    return STATUS_MORE_PROCESSING_REQUIRED;
}


NTSTATUS CreateSocketComplete(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context);
NTSTATUS CreateSocket(PWSK_PROVIDER_NPI WskProviderNpi, PWSK_APP_SOCKET_CONTEXT socketContext) {
    PIRP Irp;
    NTSTATUS status;
    //KEVENT compEvent;
    //KeInitializeEvent(&compEvent, SynchronizationEvent, FALSE);

    Irp = IoAllocateIrp(1, FALSE);
    if (!Irp) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }
    //IoSetCompletionRoutine(Irp, SyncIrpCompRtn, &compEvent, TRUE, TRUE, TRUE);
    IoSetCompletionRoutine(Irp, CreateSocketComplete, socketContext, TRUE, TRUE, TRUE);
    status = WskProviderNpi->Dispatch->WskSocket(WskProviderNpi->Client, AF_INET, SOCK_STREAM, IPPROTO_TCP, WSK_FLAG_CONNECTION_SOCKET, NULL, NULL, NULL, NULL, NULL, Irp);
    /*if (status == STATUS_PENDING) {
        KeWaitForSingleObject(&compEvent, Executive, KernelMode, FALSE, NULL);
    }
    status = Irp->IoStatus.Status;
    IoFreeIrp(Irp);
    */
    return status;
}

NTSTATUS CreateSocketComplete(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context) {
    UNREFERENCED_PARAMETER(DeviceObject);
    UNREFERENCED_PARAMETER(Context);
    if (Irp->IoStatus.Status == STATUS_SUCCESS) {
        sockContext.Socket = (PWSK_SOCKET)(Irp->IoStatus.Information);
        KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[CreateSocketComplete] Socket creation success\n"));
    }
    else {
        KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[CreateSocketComplete] Socket creation failed\n"));
    }
    IoFreeIrp(Irp);
    return STATUS_MORE_PROCESSING_REQUIRED;
}

NTSTATUS BindSocketComplete(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context);
NTSTATUS BindSocket(PWSK_SOCKET Socket, SOCKADDR_IN localAddr) {
    PWSK_PROVIDER_CONNECTION_DISPATCH Dispatch;
    PIRP Irp;
    NTSTATUS status;
    //KEVENT compEvent;
    //KeInitializeEvent(&compEvent, SynchronizationEvent, FALSE);

    Dispatch = (PWSK_PROVIDER_CONNECTION_DISPATCH)(Socket->Dispatch);
    Irp = IoAllocateIrp(1, FALSE);
    if (!Irp) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }
    //IoSetCompletionRoutine(Irp, SyncIrpCompRtn, &compEvent, TRUE, TRUE, TRUE);
    IoSetCompletionRoutine(Irp, BindSocketComplete, Socket, TRUE, TRUE, TRUE);
    status = Dispatch->WskBind(Socket, (PSOCKADDR)&localAddr, 0, Irp);
    /*if (status == STATUS_PENDING) {
        KeWaitForSingleObject(&compEvent, Executive, KernelMode, FALSE, NULL);
    }
    status = Irp->IoStatus.Status;
    IoFreeIrp(Irp);
    */
    return status;

}

NTSTATUS BindSocketComplete(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context) {
    UNREFERENCED_PARAMETER(DeviceObject);
    UNREFERENCED_PARAMETER(Context);
    if (Irp->IoStatus.Status == STATUS_SUCCESS) {
        KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[BindSocketComplete] Socket bind success\n"));
    }
    else {
        KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[BindSocketComplete] Socket bind failed\n"));
    }
    IoFreeIrp(Irp);
    return STATUS_MORE_PROCESSING_REQUIRED;
}


NTSTATUS ConnectSocketComplete(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context);
NTSTATUS ConnectSocket(PWSK_SOCKET Socket, SOCKADDR_IN remoteAddr) {
    PWSK_PROVIDER_CONNECTION_DISPATCH Dispatch;
    PIRP Irp;
    NTSTATUS status;
    //KEVENT compEvent;
    //KeInitializeEvent(&compEvent, SynchronizationEvent, FALSE);

    Dispatch = (PWSK_PROVIDER_CONNECTION_DISPATCH)(Socket->Dispatch);
    Irp = IoAllocateIrp(1, FALSE);
    if (!Irp) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }
    //IoSetCompletionRoutine(Irp, SyncIrpCompRtn, &compEvent, TRUE, TRUE, TRUE);
    IoSetCompletionRoutine(Irp, ConnectSocketComplete, Socket, TRUE, TRUE, TRUE);
    status = Dispatch->WskConnect(Socket, (PSOCKADDR)&remoteAddr, 0, Irp);
    /*if (status == STATUS_PENDING) {
        KeWaitForSingleObject(&compEvent, Executive, KernelMode, FALSE, NULL);
    }
    status = Irp->IoStatus.Status;
    IoFreeIrp(Irp);
    */
    return status;
}

NTSTATUS ConnectSocketComplete(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context) {
    UNREFERENCED_PARAMETER(DeviceObject);
    UNREFERENCED_PARAMETER(Context);

    if (Irp->IoStatus.Status == STATUS_SUCCESS) {
        KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[ConnectSocketComplete] Socket connection success\n"));
    }
    else {
        KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[ConnectSocketComplete] Socket connection failed\n"));
    }
    IoFreeIrp(Irp);
    return STATUS_MORE_PROCESSING_REQUIRED;
}


NTSTATUS DriverEntry(
    _In_ PDRIVER_OBJECT DriverObject,
    _In_ PUNICODE_STRING RegistryPath
) {
    UNREFERENCED_PARAMETER(DriverObject);
    UNREFERENCED_PARAMETER(RegistryPath);
    NTSTATUS status;
    WSK_CLIENT_NPI wskClientNpi;

    wskClientNpi.ClientContext = NULL;
    wskClientNpi.Dispatch = &WskAppDispatch;

    SOCKADDR_IN serverAddr = { 0, };
    IN_ADDR Ipv4ServAddr;
    PCSTR tmpServAddr;
    SOCKADDR_IN localAddr;

    if (!NT_SUCCESS(RtlIpv4StringToAddressA(ADDR, TRUE, &tmpServAddr, &Ipv4ServAddr)))
    {
        KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[DriverEntry] RtlIpv4StringToAddressA failed\n"));
        return STATUS_UNSUCCESSFUL;
    }

    localAddr.sin_family = AF_INET;
    localAddr.sin_addr.s_addr = INADDR_ANY;
    localAddr.sin_port = 0;

    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr = Ipv4ServAddr;
    serverAddr.sin_port = (USHORT)RtlUlongByteSwap(PORT);

    //no bsod
    status = WskRegister(&wskClientNpi, &wskRegistration);
    if (!NT_SUCCESS(status)) {
        KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[DriverEntry] WSK registration failed\n"));
        return status;
    }
    //no bsod
    status = WskCaptureProviderNPI(&wskRegistration, WSK_WAIT_TIMEOUT, &wskProviderNpi);
    if (!NT_SUCCESS(status)) {
        KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[DriverEntry] NPI Capture failed\n"));
        return status;

    }
    //no bsod
    status = CreateSocket(&wskProviderNpi, &sockContext);
    if (!NT_SUCCESS(status)) {
        KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[DriverEntry] Socket creation failed\n"));
        return status;
    }
    else if (status == STATUS_PENDING) {
        KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[DriverEntry] Socket creation pending\n"));

    }
    else {
        KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[DriverEntry] Socket creation success\n"));
    }
    //no bsod
    status = BindSocket(sockContext.Socket, localAddr);
    if (!NT_SUCCESS(status)) {
        KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[DriverEntry] Socket bind failed\n"));
        return status;
    }
    else if (status == STATUS_PENDING) {
        KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[DriverEntry] Socket bind pending\n"));

    }
    else {
        KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[DriverEntry] Socket bind success\n"));
    }


    status = ConnectSocket(sockContext.Socket, serverAddr);
    if (!NT_SUCCESS(status)) {
        KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[DriverEntry] Socket connect failed\n"));
        return status;
    }
    else if (status == STATUS_PENDING) {
        KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[DriverEntry] Socket connect pending\n"));

    }
    else {
        KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[DriverEntry] Socket connect success\n"));
    }

    KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[DriverEntry] DriverEntry() completed without errors\n"));
    return STATUS_SUCCESS;
}

image
I have no idea why it doesn't work thought

What are you trying to do here? With TCP, if you are a server, you use "bind" and "listen". If you are a client, you use "connect". You seem to be trying to use both on a single socket.

1 Like

Hello Tim. I wanted to connect to a TCP Server on my Host Machine (from a VM) on port 8080.

Hi again, do you perhaps know whats wrong with this code? it doesn't work as it should

#include <ntifs.h>
#include <ntddk.h>
#include <stdio.h>
#include <wsk.h>
#include <windef.h>

#define ADDR "192.168.0.104"
#define PORT 8080
#define WSK_WAIT_TIMEOUT 15


const WSK_CLIENT_DISPATCH WskAppDispatch = {
  MAKE_WSK_VERSION(1,0), // Use WSK version 1.0
  0,    // Reserved
  NULL  // WskClientEvent callback not required for WSK version 1.0
};

typedef struct _WSK_APP_SOCKET_CONTEXT {
    PWSK_SOCKET Socket;
} WSK_APP_SOCKET_CONTEXT, * PWSK_APP_SOCKET_CONTEXT;

WSK_APP_SOCKET_CONTEXT sockContext;
WSK_REGISTRATION wskRegistration;
WSK_PROVIDER_NPI wskProviderNpi;

NTSTATUS IoCompletionRoutine(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context) {
    UNREFERENCED_PARAMETER(DeviceObject);
    UNREFERENCED_PARAMETER(Irp);
    KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE);
    return STATUS_MORE_PROCESSING_REQUIRED;
}

NTSTATUS CreateSocket(PWSK_PROVIDER_NPI WskProviderNpi, PWSK_APP_SOCKET_CONTEXT socketContext) {
    PIRP Irp;
    NTSTATUS status;
    KEVENT compEvent;
    KeInitializeEvent(&compEvent, NotificationEvent, FALSE);

    Irp = IoAllocateIrp(1, FALSE);
    if (!Irp) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }
    IoSetCompletionRoutine(Irp, IoCompletionRoutine, &compEvent, TRUE, TRUE, TRUE);
    status = WskProviderNpi->Dispatch->WskSocket(WskProviderNpi->Client, AF_INET, SOCK_STREAM, IPPROTO_TCP, WSK_FLAG_CONNECTION_SOCKET, NULL, NULL, NULL, NULL, NULL, Irp);
    if (!NT_SUCCESS(status)) {
        IoFreeIrp(Irp);
        return status;
    }
    if (status == STATUS_PENDING) {
        KeWaitForSingleObject(&compEvent, Executive, KernelMode, FALSE, NULL);
    }
    status = Irp->IoStatus.Status;
    socketContext->Socket = (PWSK_SOCKET)Irp->IoStatus.Information;
    IoFreeIrp(Irp);
    return status;
}

NTSTATUS BindSocket(PWSK_SOCKET Socket, PSOCKADDR localAddr) {
    PWSK_PROVIDER_CONNECTION_DISPATCH Dispatch;
    PIRP Irp;
    NTSTATUS status;
    KEVENT compEvent;
    KeInitializeEvent(&compEvent, NotificationEvent, FALSE);

    Dispatch = (PWSK_PROVIDER_CONNECTION_DISPATCH)(Socket->Dispatch);
    Irp = IoAllocateIrp(1, FALSE);
    if (!Irp) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }
    IoSetCompletionRoutine(Irp, IoCompletionRoutine, &compEvent, TRUE, TRUE, TRUE);
    status = Dispatch->WskBind(Socket, localAddr, 0, Irp);
    if (!NT_SUCCESS(status)) {
        IoFreeIrp(Irp);
        return status;
    }
    if (status == STATUS_PENDING) {
        KeWaitForSingleObject(&compEvent, Executive, KernelMode, FALSE, NULL);
    }
    status = Irp->IoStatus.Status;
    IoFreeIrp(Irp);
    return status;
}

NTSTATUS ConnectSocket(PWSK_SOCKET Socket, PSOCKADDR remoteAddr) {
    PWSK_PROVIDER_CONNECTION_DISPATCH Dispatch;
    PIRP Irp;
    NTSTATUS status;
    KEVENT compEvent;
    KeInitializeEvent(&compEvent, NotificationEvent, FALSE);

    Dispatch = (PWSK_PROVIDER_CONNECTION_DISPATCH)(Socket->Dispatch);
    Irp = IoAllocateIrp(1, FALSE);
    if (!Irp) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }
    IoSetCompletionRoutine(Irp, IoCompletionRoutine, &compEvent, TRUE, TRUE, TRUE);
    status = Dispatch->WskConnect(Socket, remoteAddr, 0, Irp);
    if (!NT_SUCCESS(status)) {
        IoFreeIrp(Irp);
        return status;
    }
    if (status == STATUS_PENDING) {
        KeWaitForSingleObject(&compEvent, Executive, KernelMode, FALSE, NULL);
    }
    status = Irp->IoStatus.Status;
    IoFreeIrp(Irp);
    return status;
}

NTSTATUS DriverEntry(
    _In_ PDRIVER_OBJECT DriverObject,
    _In_ PUNICODE_STRING RegistryPath
) {
    UNREFERENCED_PARAMETER(DriverObject);
    UNREFERENCED_PARAMETER(RegistryPath);
    NTSTATUS status;
    WSK_CLIENT_NPI wskClientNpi;

    wskClientNpi.ClientContext = NULL;
    wskClientNpi.Dispatch = &WskAppDispatch;

    SOCKADDR_IN serverAddr = { 0 };
    IN_ADDR Ipv4ServAddr;
    PCSTR tmpServAddr;
    SOCKADDR_IN localAddr = { 0 };

    if (!NT_SUCCESS(RtlIpv4StringToAddressA(ADDR, TRUE, &tmpServAddr, &Ipv4ServAddr)))
    {
        KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[DriverEntry] RtlIpv4StringToAddressA failed\n"));
        return STATUS_UNSUCCESSFUL;
    }

    localAddr.sin_family = AF_INET;

    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr = Ipv4ServAddr;
    serverAddr.sin_port = (USHORT)RtlUlongByteSwap(PORT);

    //no bsod
    status = WskRegister(&wskClientNpi, &wskRegistration);
    if (!NT_SUCCESS(status)) {
        KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[DriverEntry] WSK registration failed\n"));
        return status;
    }
    //no bsod
    status = WskCaptureProviderNPI(&wskRegistration, WSK_WAIT_TIMEOUT, &wskProviderNpi);
    if (!NT_SUCCESS(status)) {
        KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[DriverEntry] NPI Capture failed\n"));
        return status;

    }
    //no bsod
    status = CreateSocket(&wskProviderNpi, &sockContext);
    if (!NT_SUCCESS(status)) {
        KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[DriverEntry] Socket creation failed\n"));
        return status;
    } else {
        KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[DriverEntry] Socket creation success\n"));
    }
    //no bsod
    status = BindSocket(sockContext.Socket, (PSOCKADDR)&localAddr);
    if (!NT_SUCCESS(status)) {
        KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[DriverEntry] Socket bind failed\n"));
        return status;
    } else {
        KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[DriverEntry] Socket bind success\n"));
    }


    status = ConnectSocket(sockContext.Socket, (PSOCKADDR)&serverAddr);
    if (!NT_SUCCESS(status)) {
        KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[DriverEntry] Socket connect failed\n"));
        return status;
    } else {
        KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[DriverEntry] Socket connect success\n"));
    }

    KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[DriverEntry] DriverEntry() completed without errors\n"));
    return STATUS_SUCCESS;
}

IMG_20240512_203339

*Edit, also I was reading the documentation for WSK

  1. After a Winsock Kernel (WSK) application has bound a connection-oriented socket to a local transport address, it can connect the socket to a remote transport address in order to establish a connection with the remote system.

What error do you get? You aren't printing the status value.

And did you see this line in the documentation?

For connection-oriented sockets, a WSK application can call the WskSocketConnect function to create, bind, and connect a socket in a single function call.

One obvious problem with your code is RtlUlongByteSwap(PORT), that should be RtlUshortByteSwap().

Regarding bind before connect, I always do that in my WSK client code (because that's how it was done for TDI clients), and I can assure you that at least it doesn't hurt.

Hello, I already found out. Code works just fine, working on SendData function right now and it's kinda weird

This is what i put into my wsk_buffer structure as Message "Hello from kernel mode!"

What I receive:
Ncat: Connection from 192.168.0.106:51401.
p∩O≈7£␦æ !≡O≈7

How did you do that? That, frankly, looks like machine instructions.

Since you're not just crashing, I suppose that you properly managed to set up an MDL for your message buffer (IoAllocateMdl + MmProbeAndLockPages or, if your buffer is guaranteed to be nonpaged pool, IoAllocateMdl + MmBuildMdlForNonPagedPool)?

And be aware that, unlike send() in Winsock, WskSend() is not a fire-and-forget function: All your structures and buffers must remain valid until the IRP has returned.

I used char instead of PCHAR

Yep, everything is done and works well now.
I have one more question thought.
I can't figure out how to detect Connection Lost.
Like if the Server disconnects the client I want to Print a message "Connection Lost with %s:%d" in the WinDbg. i couldn't find anything related to that

WskSocket() and WskSocketConnect() take an optional Dispatch parameter. Point this at a static WSK_CLIENT_CONNECTION_DISPATCH structure. And be aware that you still have to enable event callbacks explicitly (WSK_EVENT_DISCONNECT, WSK_EVENT_RECEIVE etc.), either at socket level (SO_WSK_EVENT_CALLBACK) or at client level (WSK_SET_STATIC_EVENT_CALLBACKS).

There is no such notification. The only way you know a connection was lost is when a send fails.

so I can't use callbacks?

By design, TCP connections never terminate except explicitly (FIN + FIN ACK) or if there is data to be sent that can't be sent.

yea, but if i want to disconnect the client.
i want the client (kernel) to know it got disconnected

You're asking for a concept that doesn't exist. You can close your socket, and eventually the other end will figure it out, but there is nothing sent.

Thank you so much. I was confused because of the Disconnect Event.

TCP sockets that are gracefully closed end with the FIN + FIN ACK sequence?