mirror of
https://github.com/BeneficialCode/WinArk
synced 2026-08-09 12:00:31 +00:00
497 lines
12 KiB
C++
497 lines
12 KiB
C++
#include "pch.h"
|
|
#include <ntddk.h>
|
|
#include <tdikrnl.h>
|
|
#include <ws2def.h>
|
|
#include "ktdi.h"
|
|
#include "ksocket.h"
|
|
|
|
#define SOCK_TAG 'kcos'
|
|
|
|
typedef struct _STREAM_SOCKET {
|
|
HANDLE connectionHandle;
|
|
PFILE_OBJECT connectionFileObject;
|
|
KEVENT disconnectEvent;
|
|
} STREAM_SOCKET, * PSTREAM_SOCKET;
|
|
|
|
typedef struct _SOCKET {
|
|
int type;
|
|
BOOLEAN isBound;
|
|
BOOLEAN isConnected;
|
|
BOOLEAN isListening;
|
|
BOOLEAN isShuttingdown;
|
|
BOOLEAN isShared;
|
|
HANDLE addressHandle;
|
|
PFILE_OBJECT addressFileObject;
|
|
PSTREAM_SOCKET streamSocket;
|
|
struct sockaddr peer;
|
|
} SOCKET, * PSOCKET;
|
|
|
|
NTSTATUS event_disconnect(PVOID TdiEventContext, CONNECTION_CONTEXT ConnectionContext, LONG DisconnectDataLength,
|
|
PVOID DisconnectData, LONG DisconnectInformationLength, PVOID DisconnectionInformation,
|
|
ULONG DisconnectFlags) {
|
|
PSOCKET s = (PSOCKET)TdiEventContext;
|
|
PSTREAM_SOCKET streamSocket = (PSTREAM_SOCKET)ConnectionContext;
|
|
KeSetEvent(&streamSocket->disconnectEvent, IO_NO_INCREMENT, FALSE);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
int bind(HANDLE socket, const struct sockaddr* addr, int addrlen) {
|
|
PSOCKET s = (PSOCKET)(-(INT_PTR)socket);
|
|
const struct sockaddr_in* localAddr = (const struct sockaddr_in*)addr;
|
|
UNICODE_STRING devName;
|
|
NTSTATUS status;
|
|
|
|
if (s->isBound || addr == nullptr || addrlen < sizeof(struct sockaddr_in)) {
|
|
return -1;
|
|
}
|
|
|
|
if (s->type == SOCK_DGRAM) {
|
|
RtlInitUnicodeString(&devName, L"\\Device\\Udp");
|
|
}
|
|
else if (s->type == SOCK_STREAM) {
|
|
RtlInitUnicodeString(&devName, L"\\Device\\Tcp");
|
|
}
|
|
else {
|
|
return -1;
|
|
}
|
|
|
|
status = tdi_open_transport_address(
|
|
&devName,
|
|
localAddr->sin_addr.s_addr,
|
|
localAddr->sin_port,
|
|
s->isShared,
|
|
&s->addressHandle,
|
|
&s->addressFileObject
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
s->addressFileObject = nullptr;
|
|
s->addressHandle = (HANDLE)-1;
|
|
return status;
|
|
}
|
|
|
|
if (s->type == SOCK_STREAM) {
|
|
tdi_set_event_handler(s->addressFileObject, TDI_EVENT_DISCONNECT, event_disconnect, s);
|
|
}
|
|
|
|
|
|
s->isBound = TRUE;
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int close(HANDLE socket) {
|
|
PSOCKET s = (PSOCKET)(-(INT_PTR)socket);
|
|
|
|
if (s->isBound) {
|
|
if (s->type == SOCK_STREAM && s->streamSocket) {
|
|
|
|
if (s->isConnected) {
|
|
if (!s->isShuttingdown) {
|
|
tdi_disconnect(s->streamSocket->connectionFileObject, TDI_DISCONNECT_RELEASE);
|
|
}
|
|
// wait 3s, if timeout, then force close
|
|
LARGE_INTEGER timeout{ 0 };
|
|
timeout.QuadPart = ((LONGLONG)(-10)) * 1000 * 1000 * 3;
|
|
KeWaitForSingleObject(&s->streamSocket->disconnectEvent, Executive, KernelMode, FALSE, &timeout);
|
|
tdi_unset_event_handler(s->addressFileObject, TDI_EVENT_DISCONNECT);
|
|
}
|
|
|
|
if (s->streamSocket->connectionFileObject) {
|
|
tdi_disassociate_address(s->streamSocket->connectionFileObject);
|
|
ObDereferenceObject(s->streamSocket->connectionFileObject);
|
|
}
|
|
if (s->streamSocket->connectionHandle != (HANDLE)-1) {
|
|
ZwClose(s->streamSocket->connectionHandle);
|
|
}
|
|
ExFreePool(s->streamSocket);
|
|
}
|
|
|
|
if (s->type == SOCK_DGRAM || s->type == SOCK_STREAM) {
|
|
ObDereferenceObject(s->addressFileObject);
|
|
if (s->addressHandle != (HANDLE)-1) {
|
|
ZwClose(s->addressHandle);
|
|
}
|
|
}
|
|
}
|
|
|
|
ExFreePool(s);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int connect(HANDLE socket, const struct sockaddr* addr, int addrlen) {
|
|
PSOCKET s = (PSOCKET)(-(INT_PTR)socket);
|
|
const struct sockaddr_in* remoteAddr = (const struct sockaddr_in*)addr;
|
|
UNICODE_STRING devName;
|
|
NTSTATUS status;
|
|
|
|
if (addr == nullptr || addrlen < sizeof(struct sockaddr_in)) {
|
|
return -1;
|
|
}
|
|
|
|
if (!s->isBound) {
|
|
struct sockaddr_in localAddr;
|
|
localAddr.sin_family = AF_INET;
|
|
localAddr.sin_port = 0;
|
|
localAddr.sin_addr.s_addr = INADDR_ANY;
|
|
|
|
status = bind(socket, (struct sockaddr*)&localAddr, sizeof(localAddr));
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
}
|
|
|
|
if (s->type == SOCK_STREAM) {
|
|
if (s->isConnected || s->isListening) {
|
|
return -1;
|
|
}
|
|
|
|
if (!s->streamSocket) {
|
|
s->streamSocket = (PSTREAM_SOCKET)ExAllocatePoolWithTag(NonPagedPool, sizeof(STREAM_SOCKET), SOCK_TAG);
|
|
if (!s->streamSocket) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory(s->streamSocket, sizeof(STREAM_SOCKET));
|
|
s->streamSocket->connectionHandle = (HANDLE)-1;
|
|
KeInitializeEvent(&s->streamSocket->disconnectEvent, NotificationEvent, FALSE);
|
|
}
|
|
|
|
RtlInitUnicodeString(&devName, L"\\Device\\Tcp");
|
|
status = tdi_open_connection_endpoint(&devName,
|
|
s->streamSocket,
|
|
s->isShared,
|
|
&s->streamSocket->connectionHandle,
|
|
&s->streamSocket->connectionFileObject);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
s->streamSocket->connectionFileObject = nullptr;
|
|
s->streamSocket->connectionHandle = (HANDLE)-1;
|
|
return status;
|
|
}
|
|
|
|
status = tdi_associate_address(s->streamSocket->connectionFileObject, s->addressHandle);
|
|
if (!NT_SUCCESS(status)) {
|
|
ObDereferenceObject(s->streamSocket->connectionFileObject);
|
|
s->streamSocket->connectionFileObject = nullptr;
|
|
ZwClose(s->streamSocket->connectionHandle);
|
|
s->streamSocket->connectionHandle = (HANDLE)-1;
|
|
return status;
|
|
}
|
|
|
|
status = tdi_connect(
|
|
s->streamSocket->connectionFileObject,
|
|
remoteAddr->sin_addr.s_addr,
|
|
remoteAddr->sin_port
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
tdi_disassociate_address(s->streamSocket->connectionFileObject);
|
|
ObDereferenceObject(s->streamSocket->connectionFileObject);
|
|
s->streamSocket->connectionFileObject = nullptr;
|
|
ZwClose(s->streamSocket->connectionHandle);
|
|
s->streamSocket->connectionHandle = (HANDLE)-1;
|
|
return status;
|
|
}
|
|
else {
|
|
s->peer = *addr;
|
|
s->isConnected = TRUE;
|
|
return 0;
|
|
}
|
|
}
|
|
else if (s->type == SOCK_DGRAM) {
|
|
s->peer = *addr;
|
|
if (remoteAddr->sin_addr.s_addr == 0 && remoteAddr->sin_port == 0) {
|
|
s->isConnected = FALSE;
|
|
}
|
|
else {
|
|
s->isConnected = TRUE;
|
|
}
|
|
return 0;
|
|
}
|
|
else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
int getpeername(HANDLE socket, struct sockaddr* addr, int* addrlen) {
|
|
PSOCKET s = (PSOCKET)(-(INT_PTR)socket);
|
|
if (!s->isConnected || addr == nullptr || addrlen == nullptr || *addrlen < sizeof(struct sockaddr_in)) {
|
|
return -1;
|
|
}
|
|
|
|
*addr = s->peer;
|
|
*addrlen = sizeof(s->peer);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int getsockname(HANDLE socket, struct sockaddr* addr, int* addrlen) {
|
|
PSOCKET s = (PSOCKET)(-(INT_PTR)socket);
|
|
struct sockaddr_in* localAddr = (sockaddr_in*)addr;
|
|
|
|
if (!s->isBound || addr == nullptr || addrlen == nullptr || *addrlen < sizeof(sockaddr_in)) {
|
|
return -1;
|
|
}
|
|
|
|
*addrlen = sizeof(sockaddr_in);
|
|
|
|
if (s->type == SOCK_DGRAM) {
|
|
return tdi_query_address(s->addressFileObject, &localAddr->sin_addr.s_addr, &localAddr->sin_port);
|
|
}
|
|
else if (s->type == SOCK_STREAM) {
|
|
PFILE_OBJECT FileObject = s->streamSocket && s->streamSocket->connectionFileObject ?
|
|
s->streamSocket->connectionFileObject : s->addressFileObject;
|
|
return tdi_query_address(FileObject,
|
|
&localAddr->sin_addr.s_addr,
|
|
&localAddr->sin_port);
|
|
}
|
|
else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
char* inet_ntoa(struct in_addr addr) {
|
|
char* name, * s;
|
|
ULONG n;
|
|
UCHAR byte;
|
|
|
|
static UCHAR buf[16] = { 0 };
|
|
|
|
name = (char*)buf;
|
|
|
|
if (name) {
|
|
for (n = 0, s = name; n < 4; n++) {
|
|
byte = (u_char)((addr.s_addr >> (8 * n)) & 0xff);
|
|
if (byte / 100) {
|
|
*s++ = byte / 100 + '0';
|
|
if (0 == ((byte % 100) / 100)) {
|
|
*s++ = '0';
|
|
}
|
|
}
|
|
if ((byte % 100) / 10) {
|
|
*s++ = (byte % 100) / 10 + '0';
|
|
}
|
|
*s++ = byte % 10 + '0';
|
|
*s++ = '.';
|
|
}
|
|
*--s = '\0';
|
|
}
|
|
|
|
return name;
|
|
}
|
|
|
|
int listen(HANDLE socket, int backlog) {
|
|
PSOCKET s = (PSOCKET)(-(INT_PTR)socket);
|
|
NTSTATUS status;
|
|
UNICODE_STRING devName;
|
|
|
|
if (s->type == SOCK_STREAM) {
|
|
if (s->isConnected) {
|
|
return -1;
|
|
}
|
|
if (s->isListening) {
|
|
return 0;
|
|
}
|
|
|
|
if (!s->isBound) {
|
|
return 10022L;
|
|
}
|
|
else {
|
|
if (!s->streamSocket) {
|
|
s->streamSocket = (PSTREAM_SOCKET)ExAllocatePoolWithTag(NonPagedPool, sizeof(STREAM_SOCKET), SOCK_TAG);
|
|
if (!s->streamSocket) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory(s->streamSocket, sizeof(STREAM_SOCKET));
|
|
s->streamSocket->connectionHandle = (HANDLE)-1;
|
|
KeInitializeEvent(&s->streamSocket->disconnectEvent, NotificationEvent, FALSE);
|
|
}
|
|
|
|
RtlInitUnicodeString(&devName, L"\\Device\\Tcp");
|
|
status = tdi_open_connection_endpoint(
|
|
&devName,
|
|
s->streamSocket,
|
|
s->isShared,
|
|
&s->streamSocket->connectionHandle,
|
|
&s->streamSocket->connectionFileObject
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
s->streamSocket->connectionFileObject = nullptr;
|
|
s->streamSocket->connectionHandle = (HANDLE)-1;
|
|
return status;
|
|
}
|
|
|
|
status = tdi_associate_address(s->streamSocket->connectionFileObject, s->addressHandle);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
ObDereferenceObject(s->streamSocket->connectionFileObject);
|
|
s->streamSocket->connectionFileObject = nullptr;
|
|
ZwClose(s->streamSocket->connectionHandle);
|
|
s->streamSocket->connectionHandle = (HANDLE)-1;
|
|
return status;
|
|
}
|
|
|
|
|
|
if (!s->streamSocket) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
s->isListening = TRUE;
|
|
return 0;
|
|
}
|
|
}
|
|
else {
|
|
return -1;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
int recv(HANDLE socket, char* buf, int len, int flags) {
|
|
PSOCKET s = (PSOCKET)(-(INT_PTR)socket);
|
|
|
|
if (s->type == SOCK_DGRAM) {
|
|
return recvfrom(socket, buf, len, flags, nullptr, nullptr);
|
|
}
|
|
else if (s->type == SOCK_STREAM) {
|
|
if (!s->isConnected) {
|
|
return -1;
|
|
}
|
|
|
|
return tdi_recv_stream(s->streamSocket->connectionFileObject,
|
|
buf, len,
|
|
flags == MSG_OOB ? TDI_RECEIVE_EXPEDITED : TDI_RECEIVE_NORMAL);
|
|
}
|
|
else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
int recvfrom(HANDLE socket, char* buf, int len, int flags, struct sockaddr* addr, int* addrlen) {
|
|
PSOCKET s = (PSOCKET)(-(INT_PTR)socket);
|
|
struct sockaddr_in* returnAddr = (sockaddr_in*)addr;
|
|
|
|
if (s->type == SOCK_STREAM) {
|
|
return recv(socket, buf, len, flags);
|
|
}
|
|
else if (s->type == SOCK_DGRAM) {
|
|
u_long* sin_addr = 0;
|
|
u_short* sin_port = 0;
|
|
|
|
if (!s->isBound) {
|
|
return -1;
|
|
}
|
|
|
|
if (addr != nullptr & addrlen != nullptr && *addrlen >= sizeof(sockaddr_in)) {
|
|
sin_addr = &returnAddr->sin_addr.s_addr;
|
|
sin_port = &returnAddr->sin_port;
|
|
*addrlen = sizeof(sockaddr_in);
|
|
}
|
|
|
|
return tdi_recv_dgram(s->addressFileObject, sin_addr, sin_port, buf, len, TDI_RECEIVE_NORMAL);
|
|
}
|
|
else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
int send(HANDLE socket, const char* buf, int len, int flags) {
|
|
PSOCKET s = (PSOCKET)(-(INT_PTR)socket);
|
|
|
|
if (!s->isConnected) {
|
|
return -1;
|
|
}
|
|
|
|
if (s->type == SOCK_DGRAM) {
|
|
return sendto(socket, buf, len, flags, &s->peer, sizeof(s->peer));
|
|
}
|
|
}
|
|
|
|
int sendto(HANDLE socket, const char* buf, int len, int flags,
|
|
const struct sockaddr* addr, int addrlen) {
|
|
PSOCKET s = (PSOCKET)(-(INT_PTR)socket);
|
|
const sockaddr_in* remoteAddr = (const sockaddr_in*)addr;
|
|
|
|
if (s->type == SOCK_STREAM) {
|
|
return send(socket, buf, len, flags);
|
|
}
|
|
else if (s->type == SOCK_DGRAM) {
|
|
sockaddr_in localAddr;
|
|
NTSTATUS status;
|
|
|
|
localAddr.sin_family = AF_INET;
|
|
localAddr.sin_port = 0;
|
|
localAddr.sin_addr.s_addr = INADDR_ANY;
|
|
|
|
status = bind(socket, (struct sockaddr*)&localAddr, sizeof(localAddr));
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
return tdi_send_dgram(s->addressFileObject,
|
|
remoteAddr->sin_addr.s_addr,
|
|
remoteAddr->sin_port,
|
|
buf, len);
|
|
}
|
|
else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
int shutdown(HANDLE socket, int how) {
|
|
PSOCKET s = (PSOCKET)(-(INT_PTR)socket);
|
|
|
|
if (!s->isConnected) {
|
|
return -1;
|
|
}
|
|
|
|
if (s->type == SOCK_STREAM) {
|
|
s->isShuttingdown = TRUE;
|
|
return tdi_disconnect(s->streamSocket->connectionFileObject, TDI_DISCONNECT_RELEASE);
|
|
}
|
|
else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
HANDLE socket(int af, int type, int protocol) {
|
|
PSOCKET s;
|
|
|
|
if (af != AF_INET) {
|
|
return LongToHandle(STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
s = (PSOCKET)ExAllocatePoolWithTag(NonPagedPool, sizeof(SOCKET), SOCK_TAG);
|
|
|
|
if (!s) {
|
|
return LongToHandle(STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
RtlZeroMemory(s, sizeof(SOCKET));
|
|
|
|
s->type = type;
|
|
s->addressHandle = (HANDLE)-1;
|
|
|
|
return (HANDLE)(-(INT_PTR)s);
|
|
}
|
|
|
|
int stream_recv(HANDLE socket, char* buf, int len) {
|
|
int left, recvBytes;
|
|
char* p;
|
|
left = len;
|
|
p = buf;
|
|
while (left > 0) {
|
|
recvBytes = left > 65536 ? 65536 : left;
|
|
recvBytes = recv(socket, p, recvBytes, 0);
|
|
if (recvBytes < 0)
|
|
return recvBytes;
|
|
left -= recvBytes;
|
|
p += recvBytes;
|
|
}
|
|
return 0;
|
|
} |