Prepare support for more socket types

This commit is contained in:
momo5502
2024-11-08 20:41:06 +01:00
parent b367db3584
commit a63ae4e782
7 changed files with 251 additions and 73 deletions

View File

@@ -29,14 +29,7 @@ namespace network
socket::~socket()
{
if (this->socket_ != INVALID_SOCKET)
{
#ifdef _WIN32
closesocket(this->socket_);
#else
close(this->socket_);
#endif
}
this->release();
}
socket::socket(socket&& obj) noexcept
@@ -48,7 +41,7 @@ namespace network
{
if (this != &obj)
{
this->~socket();
this->release();
this->socket_ = obj.socket_;
this->port_ = obj.port_;
this->address_family_ = obj.address_family_;
@@ -60,6 +53,15 @@ namespace network
return *this;
}
void socket::release()
{
if (this->socket_ != INVALID_SOCKET)
{
closesocket(this->socket_);
this->socket_ = INVALID_SOCKET;
}
}
bool socket::bind_port(const address& target)
{
const auto result = bind(this->socket_, &target.get_addr(), target.get_size()) == 0;
@@ -182,7 +184,7 @@ namespace network
}
const auto retval = poll(pfds.data(), static_cast<uint32_t>(pfds.size()),
static_cast<int>(timeout.count()));
static_cast<int>(timeout.count()));
if (retval == SOCKET_ERROR)
{

View File

@@ -13,6 +13,7 @@ using socklen_t = int;
#define INVALID_SOCKET (SOCKET)(~0)
#define SOCKET_ERROR (-1)
#define GET_SOCKET_ERROR() (errno)
#define closesocket close
#endif
namespace network
@@ -56,5 +57,7 @@ namespace network
int address_family_{AF_UNSPEC};
uint16_t port_ = 0;
SOCKET socket_ = INVALID_SOCKET;
void release();
};
}

View File

@@ -1,87 +1,125 @@
#include "afd_endpoint.hpp"
#include "afd_types.hpp"
#include "../windows_emulator.hpp"
#include <network/address.hpp>
#include <network/socket.hpp>
typedef LONG TDI_STATUS;
typedef PVOID CONNECTION_CONTEXT;
typedef struct _TDI_CONNECTION_INFORMATION
{
LONG UserDataLength;
PVOID UserData;
LONG OptionsLength;
PVOID Options;
LONG RemoteAddressLength;
PVOID RemoteAddress;
} TDI_CONNECTION_INFORMATION, *PTDI_CONNECTION_INFORMATION;
typedef struct _TDI_REQUEST
{
union
{
HANDLE AddressHandle;
CONNECTION_CONTEXT ConnectionContext;
HANDLE ControlChannel;
} Handle;
PVOID RequestNotifyObject;
PVOID RequestContext;
TDI_STATUS TdiStatus;
} TDI_REQUEST, *PTDI_REQUEST;
typedef struct _TDI_REQUEST_SEND_DATAGRAM
{
TDI_REQUEST Request;
PTDI_CONNECTION_INFORMATION SendDatagramInformation;
} TDI_REQUEST_SEND_DATAGRAM, *PTDI_REQUEST_SEND_DATAGRAM;
typedef struct _AFD_SEND_DATAGRAM_INFO
{
LPWSABUF BufferArray;
ULONG BufferCount;
ULONG AfdFlags;
TDI_REQUEST_SEND_DATAGRAM TdiRequest;
TDI_CONNECTION_INFORMATION TdiConnInfo;
} AFD_SEND_DATAGRAM_INFO, *PAFD_SEND_DATAGRAM_INFO;
namespace
{
struct afd_endpoint : stateless_device
struct afd_creation_data
{
network::socket s{AF_INET};
uint64_t unk1;
char afd_open_packet_xx[0x10];
uint64_t unk2;
int address_family;
int type;
int protocol;
// ...
};
afd_creation_data get_creation_data(const io_device_creation_data& data)
{
if (!data.buffer || data.length < sizeof(afd_creation_data))
{
throw std::runtime_error("Bad AFD creation data");
}
return emulator_object<afd_creation_data>{data.emu, data.buffer}.read();
}
struct afd_endpoint : io_device
{
std::optional<SOCKET> s{};
afd_endpoint()
{
network::initialize_wsa();
}
afd_endpoint(afd_endpoint&&) = delete;
afd_endpoint& operator=(afd_endpoint&&) = delete;
~afd_endpoint() override
{
if (this->s)
{
closesocket(*this->s);
}
}
void create(const io_device_creation_data& data) override
{
const auto creation_data = get_creation_data(data);
const auto sock = socket(creation_data.address_family, creation_data.type, creation_data.protocol);
if (sock == INVALID_SOCKET)
{
throw std::runtime_error("Failed to create socket!");
}
s = sock;
}
void deserialize(utils::buffer_deserializer&) override
{
// TODO
}
void serialize(utils::buffer_serializer&) const override
{
// TODO
}
NTSTATUS io_control(const io_device_context& c) override
{
c.io_status_block.write({});
if (_AFD_BASE(c.io_control_code) != FSCTL_AFD_BASE)
{
c.win_emu.logger.print(color::cyan, "Bad AFD IOCTL: %X\n", c.io_control_code);
return STATUS_NOT_SUPPORTED;
}
c.win_emu.logger.print(color::cyan, "AFD IOCTL: %X\n", c.io_control_code);
switch (c.io_control_code)
const auto request = _AFD_REQUEST(c.io_control_code);
switch (request)
{
case 0x12003:
case AFD_BIND:
return this->ioctl_bind(c);
case 0x12023:
case AFD_SEND_DATAGRAM:
return this->ioctl_send_datagram(c);
case 0x12047: // ?
case 0x1207B: // ?
case AFD_SET_CONTEXT:
return STATUS_SUCCESS;
case AFD_GET_INFORMATION:
return STATUS_SUCCESS;
}
return STATUS_SUCCESS;
c.win_emu.logger.print(color::gray, "Unsupported AFD IOCTL: %X\n", c.io_control_code);
return STATUS_NOT_SUPPORTED;
}
NTSTATUS ioctl_bind(const io_device_context& c)
NTSTATUS ioctl_bind(const io_device_context& c) const
{
std::vector<std::byte> data{};
data.resize(c.input_buffer_length);
c.emu.read_memory(c.input_buffer, data.data(), c.input_buffer_length);
utils::buffer_deserializer deserializer{data, true};
deserializer.read<uint32_t>(); // IDK :(
const network::address addr = deserializer.read<sockaddr_in>();
constexpr auto address_offset = 4;
if (!this->s.bind_port(addr))
if (data.size() < address_offset)
{
return STATUS_BUFFER_TOO_SMALL;
}
const auto* address = reinterpret_cast<const sockaddr*>(data.data() + address_offset);
const auto address_size = static_cast<int>(data.size() - address_offset);
const network::address addr(address, address_size);
if (bind(*this->s, &addr.get_addr(), addr.get_size()) == SOCKET_ERROR)
{
return STATUS_ADDRESS_ALREADY_ASSOCIATED;
}
@@ -89,7 +127,7 @@ namespace
return STATUS_SUCCESS;
}
NTSTATUS ioctl_send_datagram(const io_device_context& c)
NTSTATUS ioctl_send_datagram(const io_device_context& c) const
{
if (c.input_buffer_length < sizeof(AFD_SEND_DATAGRAM_INFO))
{
@@ -111,7 +149,11 @@ namespace
data.resize(buffer.len);
c.emu.read_memory(reinterpret_cast<uint64_t>(buffer.buf), data.data(), data.size());
if (!s.send(target, data.data(), data.size()))
const auto sent_data = sendto(*this->s, reinterpret_cast<const char*>(data.data()),
static_cast<int>(data.size()), 0 /* ? */, &target.get_addr(),
target.get_size());
if (sent_data < 0)
{
return STATUS_CONNECTION_REFUSED;
}
@@ -119,7 +161,7 @@ namespace
if (c.io_status_block)
{
IO_STATUS_BLOCK block{};
block.Information = data.size();
block.Information = static_cast<uint32_t>(sent_data);
c.io_status_block.write(block);
}

View File

@@ -0,0 +1,102 @@
#pragma once
#include "../std_include.hpp"
typedef LONG TDI_STATUS;
typedef PVOID CONNECTION_CONTEXT;
typedef struct _TDI_CONNECTION_INFORMATION
{
LONG UserDataLength;
PVOID UserData;
LONG OptionsLength;
PVOID Options;
LONG RemoteAddressLength;
PVOID RemoteAddress;
} TDI_CONNECTION_INFORMATION, *PTDI_CONNECTION_INFORMATION;
typedef struct _TDI_REQUEST
{
union
{
HANDLE AddressHandle;
CONNECTION_CONTEXT ConnectionContext;
HANDLE ControlChannel;
} Handle;
PVOID RequestNotifyObject;
PVOID RequestContext;
TDI_STATUS TdiStatus;
} TDI_REQUEST, *PTDI_REQUEST;
typedef struct _TDI_REQUEST_SEND_DATAGRAM
{
TDI_REQUEST Request;
PTDI_CONNECTION_INFORMATION SendDatagramInformation;
} TDI_REQUEST_SEND_DATAGRAM, *PTDI_REQUEST_SEND_DATAGRAM;
typedef struct _AFD_SEND_DATAGRAM_INFO
{
LPWSABUF BufferArray;
ULONG BufferCount;
ULONG AfdFlags;
TDI_REQUEST_SEND_DATAGRAM TdiRequest;
TDI_CONNECTION_INFORMATION TdiConnInfo;
} AFD_SEND_DATAGRAM_INFO, *PAFD_SEND_DATAGRAM_INFO;
#define _AFD_REQUEST(ioctl) \
((((ULONG)(ioctl)) >> 2) & 0x03FF)
#define _AFD_BASE(ioctl) \
((((ULONG)(ioctl)) >> 12) & 0xFFFFF)
#define FSCTL_AFD_BASE FILE_DEVICE_NETWORK
#define AFD_BIND 0
#define AFD_CONNECT 1
#define AFD_START_LISTEN 2
#define AFD_WAIT_FOR_LISTEN 3
#define AFD_ACCEPT 4
#define AFD_RECEIVE 5
#define AFD_RECEIVE_DATAGRAM 6
#define AFD_SEND 7
#define AFD_SEND_DATAGRAM 8
#define AFD_POLL 9
#define AFD_PARTIAL_DISCONNECT 10
#define AFD_GET_ADDRESS 11
#define AFD_QUERY_RECEIVE_INFO 12
#define AFD_QUERY_HANDLES 13
#define AFD_SET_INFORMATION 14
#define AFD_GET_CONTEXT_LENGTH 15
#define AFD_GET_CONTEXT 16
#define AFD_SET_CONTEXT 17
#define AFD_SET_CONNECT_DATA 18
#define AFD_SET_CONNECT_OPTIONS 19
#define AFD_SET_DISCONNECT_DATA 20
#define AFD_SET_DISCONNECT_OPTIONS 21
#define AFD_GET_CONNECT_DATA 22
#define AFD_GET_CONNECT_OPTIONS 23
#define AFD_GET_DISCONNECT_DATA 24
#define AFD_GET_DISCONNECT_OPTIONS 25
#define AFD_SIZE_CONNECT_DATA 26
#define AFD_SIZE_CONNECT_OPTIONS 27
#define AFD_SIZE_DISCONNECT_DATA 28
#define AFD_SIZE_DISCONNECT_OPTIONS 29
#define AFD_GET_INFORMATION 30
#define AFD_TRANSMIT_FILE 31
#define AFD_SUPER_ACCEPT 32
#define AFD_EVENT_SELECT 33
#define AFD_ENUM_NETWORK_EVENTS 34
#define AFD_DEFER_ACCEPT 35
#define AFD_WAIT_FOR_LISTEN_LIFO 36
#define AFD_SET_QOS 37
#define AFD_GET_QOS 38
#define AFD_NO_OPERATION 39
#define AFD_VALIDATE_GROUP 40
#define AFD_GET_UNACCEPTED_CONNECT_DATA 41

View File

@@ -27,6 +27,16 @@ struct io_device_context
ULONG output_buffer_length;
};
struct io_device_creation_data
{
windows_emulator& win_emu;
x64_emulator& emu;
process_context& proc;
uint64_t buffer;
uint32_t length;
};
struct io_device
{
io_device() = default;
@@ -40,12 +50,21 @@ struct io_device
virtual NTSTATUS io_control(const io_device_context& context) = 0;
virtual void create(const io_device_creation_data& data)
{
(void)data;
}
virtual void serialize(utils::buffer_serializer& buffer) const = 0;
virtual void deserialize(utils::buffer_deserializer& buffer) = 0;
};
struct stateless_device : io_device
{
void create(const io_device_creation_data&) final
{
}
void serialize(utils::buffer_serializer&) const override
{
}
@@ -62,10 +81,11 @@ class io_device_container : public io_device
public:
io_device_container() = default;
io_device_container(std::wstring device)
io_device_container(std::wstring device, const io_device_creation_data& data)
: device_name_(std::move(device))
{
this->setup();
this->device_->create(data);
}
NTSTATUS io_control(const io_device_context& context) override

View File

@@ -62,6 +62,7 @@
#include <phnt_windows.h>
#include <phnt.h>
#include <ntgdi.h>
#include <ws2def.h>
#ifdef _WIN32
#pragma warning(pop)

View File

@@ -2058,8 +2058,8 @@ namespace
const emulator_object<IO_STATUS_BLOCK> /*io_status_block*/,
const emulator_object<LARGE_INTEGER> /*allocation_size*/, ULONG /*file_attributes*/,
ULONG /*share_access*/, ULONG create_disposition, ULONG create_options,
uint64_t /*ea_buffer*/,
ULONG /*ea_length*/)
uint64_t ea_buffer,
ULONG ea_length)
{
const auto attributes = object_attributes.read();
auto filename = read_unicode_string(c.emu, attributes.ObjectName);
@@ -2072,8 +2072,16 @@ namespace
constexpr std::wstring_view device_prefix = L"\\Device\\";
if (filename.starts_with(device_prefix))
{
const io_device_creation_data data{
.win_emu = c.win_emu,
.emu = c.emu,
.proc = c.proc,
.buffer = ea_buffer,
.length = ea_length,
};
auto device_name = filename.substr(device_prefix.size());
io_device_container container{std::move(device_name)};
io_device_container container{std::move(device_name), data};
const auto handle = c.proc.devices.store(std::move(container));
file_handle.write(handle);