diff --git a/src/common/network/socket.cpp b/src/common/network/socket.cpp index 2d16217..0e68ba5 100644 --- a/src/common/network/socket.cpp +++ b/src/common/network/socket.cpp @@ -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(pfds.size()), - static_cast(timeout.count())); + static_cast(timeout.count())); if (retval == SOCKET_ERROR) { diff --git a/src/common/network/socket.hpp b/src/common/network/socket.hpp index 3eda5cb..b66029c 100644 --- a/src/common/network/socket.hpp +++ b/src/common/network/socket.hpp @@ -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(); }; } diff --git a/src/windows-emulator/devices/afd_endpoint.cpp b/src/windows-emulator/devices/afd_endpoint.cpp index 4f8d51b..9c25106 100644 --- a/src/windows-emulator/devices/afd_endpoint.cpp +++ b/src/windows-emulator/devices/afd_endpoint.cpp @@ -1,87 +1,125 @@ #include "afd_endpoint.hpp" +#include "afd_types.hpp" #include "../windows_emulator.hpp" + #include #include +namespace +{ + struct afd_creation_data + { + 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"); + } -typedef LONG TDI_STATUS; -typedef PVOID CONNECTION_CONTEXT; + return emulator_object{data.emu, data.buffer}.read(); + } -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 + struct afd_endpoint : io_device { - HANDLE AddressHandle; - CONNECTION_CONTEXT ConnectionContext; - HANDLE ControlChannel; - } Handle; + std::optional s{}; - PVOID RequestNotifyObject; - PVOID RequestContext; - TDI_STATUS TdiStatus; -} TDI_REQUEST, *PTDI_REQUEST; + afd_endpoint() + { + network::initialize_wsa(); + } -typedef struct _TDI_REQUEST_SEND_DATAGRAM -{ - TDI_REQUEST Request; - PTDI_CONNECTION_INFORMATION SendDatagramInformation; -} TDI_REQUEST_SEND_DATAGRAM, *PTDI_REQUEST_SEND_DATAGRAM; + afd_endpoint(afd_endpoint&&) = delete; + afd_endpoint& operator=(afd_endpoint&&) = delete; -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; + ~afd_endpoint() override + { + if (this->s) + { + closesocket(*this->s); + } + } -namespace -{ - struct afd_endpoint : stateless_device - { - network::socket s{AF_INET}; + 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 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(); // IDK :( - const network::address addr = deserializer.read(); + 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(data.data() + address_offset); + const auto address_size = static_cast(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(buffer.buf), data.data(), data.size()); - if (!s.send(target, data.data(), data.size())) + const auto sent_data = sendto(*this->s, reinterpret_cast(data.data()), + static_cast(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(sent_data); c.io_status_block.write(block); } diff --git a/src/windows-emulator/devices/afd_types.hpp b/src/windows-emulator/devices/afd_types.hpp new file mode 100644 index 0000000..17a4cf0 --- /dev/null +++ b/src/windows-emulator/devices/afd_types.hpp @@ -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 diff --git a/src/windows-emulator/io_device.hpp b/src/windows-emulator/io_device.hpp index fa3f11e..a7d36ec 100644 --- a/src/windows-emulator/io_device.hpp +++ b/src/windows-emulator/io_device.hpp @@ -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 diff --git a/src/windows-emulator/std_include.hpp b/src/windows-emulator/std_include.hpp index 05e56c3..e2fe633 100644 --- a/src/windows-emulator/std_include.hpp +++ b/src/windows-emulator/std_include.hpp @@ -62,6 +62,7 @@ #include #include #include +#include #ifdef _WIN32 #pragma warning(pop) diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 1e3e5e6..f1ebce7 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -2058,8 +2058,8 @@ namespace const emulator_object /*io_status_block*/, const emulator_object /*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);