From 248c09d554a8451237fc7bd35ba9afd3a4eb2301 Mon Sep 17 00:00:00 2001 From: Igor Pissolati Date: Sun, 19 Oct 2025 18:06:15 -0300 Subject: [PATCH] Implement ALPC port abstraction and implement DNS resolver port --- src/common/platform/platform.hpp | 1 + src/common/platform/port.hpp | 80 +++++++ src/common/platform/process.hpp | 52 ----- src/emulator/binary_writer.hpp | 98 +++++++++ src/tools/create-root.bat | 1 + src/windows-emulator/port.cpp | 109 ++++++++++ src/windows-emulator/port.hpp | 187 ++++++++++++++++ src/windows-emulator/ports/api_port.cpp | 36 ++++ src/windows-emulator/ports/api_port.hpp | 4 + src/windows-emulator/ports/dns_resolver.cpp | 225 ++++++++++++++++++++ src/windows-emulator/ports/dns_resolver.hpp | 4 + src/windows-emulator/process_context.hpp | 3 +- src/windows-emulator/syscalls.cpp | 27 ++- src/windows-emulator/syscalls/port.cpp | 111 ++++++---- src/windows-emulator/windows_objects.hpp | 18 -- 15 files changed, 845 insertions(+), 111 deletions(-) create mode 100644 src/common/platform/port.hpp create mode 100644 src/emulator/binary_writer.hpp create mode 100644 src/windows-emulator/port.cpp create mode 100644 src/windows-emulator/port.hpp create mode 100644 src/windows-emulator/ports/api_port.cpp create mode 100644 src/windows-emulator/ports/api_port.hpp create mode 100644 src/windows-emulator/ports/dns_resolver.cpp create mode 100644 src/windows-emulator/ports/dns_resolver.hpp diff --git a/src/common/platform/platform.hpp b/src/common/platform/platform.hpp index fc4c1edf..da729274 100644 --- a/src/common/platform/platform.hpp +++ b/src/common/platform/platform.hpp @@ -26,6 +26,7 @@ #include "network.hpp" #include "threading.hpp" #include "window.hpp" +#include "port.hpp" #if defined(__GNUC__) || defined(__clang__) #pragma GCC diagnostic pop diff --git a/src/common/platform/port.hpp b/src/common/platform/port.hpp new file mode 100644 index 00000000..aa5107e9 --- /dev/null +++ b/src/common/platform/port.hpp @@ -0,0 +1,80 @@ +#pragma once + +// NOLINTBEGIN(modernize-use-using,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) + +#define LPC_REQUEST 1 +#define LPC_REPLY 2 +#define LPC_DATAGRAM 3 +#define LPC_LOST_REPLY 4 +#define LPC_PORT_CLOSED 5 +#define LPC_CLIENT_DIED 6 +#define LPC_EXCEPTION 7 +#define LPC_DEBUG_EVENT 8 +#define LPC_ERROR_EVENT 9 +#define LPC_CONNECTION_REQUEST 10 +#define LPC_NO_IMPERSONATE 0x4000 +#define LPC_KERNELMODE_MESSAGE 0x8000 + +#define LpcpGetMessageType(x) ((x)->u2.s2.Type & ~LPC_KERNELMODE_MESSAGE) + +struct PORT_MESSAGE64 +{ + union + { + struct + { + CSHORT DataLength; + CSHORT TotalLength; + } s1; + + ULONG Length; + } u1; + + union + { + struct + { + CSHORT Type; + CSHORT DataInfoOffset; + } s2; + + ULONG ZeroInit; + } u2; + + union + { + CLIENT_ID64 ClientId; + double DoNotUseThisField; + }; + + ULONG MessageId; + + union + { + EmulatorTraits::SIZE_T ClientViewSize; // only valid for LPC_CONNECTION_REQUEST messages + ULONG CallbackId; // only valid for LPC_REQUEST messages + }; +}; + +struct ALPC_MESSAGE_ATTRIBUTES +{ + ULONG AllocatedAttributes; + ULONG ValidAttributes; +}; + +template +struct PORT_DATA_ENTRY +{ + typename Traits::PVOID Base; + ULONG Size; +}; + +template +struct ALPC_SECURITY_ATTR +{ + ULONG Flags; + typename Traits::PVOID SecurityQos; + typename Traits::HANDLE ContextHandle; +}; + +// NOLINTEND(modernize-use-using,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) diff --git a/src/common/platform/process.hpp b/src/common/platform/process.hpp index d9d1a915..c2f77564 100644 --- a/src/common/platform/process.hpp +++ b/src/common/platform/process.hpp @@ -983,58 +983,6 @@ struct CLIENT_ID64 DWORD64 UniqueThread; }; -struct PORT_MESSAGE64 -{ - union - { - struct - { - CSHORT DataLength; - CSHORT TotalLength; - } s1; - - ULONG Length; - } u1; - - union - { - struct - { - CSHORT Type; - CSHORT DataInfoOffset; - } s2; - - ULONG ZeroInit; - } u2; - - union - { - CLIENT_ID64 ClientId; - double DoNotUseThisField; - }; - - ULONG MessageId; - - union - { - EmulatorTraits::SIZE_T ClientViewSize; // only valid for LPC_CONNECTION_REQUEST messages - ULONG CallbackId; // only valid for LPC_REQUEST messages - }; -}; - -struct ALPC_MESSAGE_ATTRIBUTES -{ - ULONG AllocatedAttributes; - ULONG ValidAttributes; -}; - -template -struct PORT_DATA_ENTRY -{ - typename Traits::PVOID Base; - ULONG Size; -}; - template struct EMU_RTL_SRWLOCK { diff --git a/src/emulator/binary_writer.hpp b/src/emulator/binary_writer.hpp new file mode 100644 index 00000000..c76a6213 --- /dev/null +++ b/src/emulator/binary_writer.hpp @@ -0,0 +1,98 @@ +#pragma once + +namespace utils +{ + template + class aligned_binary_writer; + + template + concept Writable = requires(const T ac, aligned_binary_writer& writer) { + { ac.write(writer) } -> std::same_as; + }; + + template + class aligned_binary_writer + { + public: + aligned_binary_writer(memory_interface& mem, uint64_t address) + : memory(mem), + base_address(address), + current_position(address) + { + } + + void write(const void* data, size_t size, size_t alignment = 1) + { + align_to(alignment); + memory.write_memory(current_position, data, size); + current_position += size; + } + + template + requires(!is_optional::value) + void write(const T& value) + { + constexpr auto is_trivially_copyable = std::is_trivially_copyable_v; + + if constexpr (Writable) + { + value.write(*this); + } + else if constexpr (is_trivially_copyable) + { + write(&value, sizeof(T), alignof(T)); + } + else + { + static_assert(std::is_trivially_copyable_v, "Type must be trivially copyable or be writable!"); + std::abort(); + } + } + + void write_ndr_pointer(bool not_null) + { + write(not_null ? 0x20000 : 0); + } + + void write_ndr_u16string(const std::u16string& str) + { + size_t char_count = str.size() + 1; + size_t byte_length = char_count * sizeof(char16_t); + + write(char_count); + write(0); + write(char_count); + write(str.c_str(), byte_length); + } + + void pad(size_t count) + { + std::vector padding(count, 0); + write(padding.data(), count); + } + + void align_to(size_t alignment) + { + size_t offset_val = static_cast(current_position) % alignment; + if (offset_val != 0) + { + pad(alignment - offset_val); + } + } + + uint64_t position() const + { + return current_position; + } + + uint64_t offset() const + { + return current_position - base_address; + } + + private: + memory_interface& memory; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members) + uint64_t base_address; + uint64_t current_position; + }; +} diff --git a/src/tools/create-root.bat b/src/tools/create-root.bat index cfe8125c..3c6137b4 100644 --- a/src/tools/create-root.bat +++ b/src/tools/create-root.bat @@ -136,6 +136,7 @@ CALL :collect srvcli.dll CALL :collect wlanapi.dll CALL :collect windowscodecs.dll CALL :collect mobilenetworking.dll +CALL :collect FWPUCLNT.dll CALL :collect locale.nls CALL :collect c_1252.nls diff --git a/src/windows-emulator/port.cpp b/src/windows-emulator/port.cpp new file mode 100644 index 00000000..dfe66019 --- /dev/null +++ b/src/windows-emulator/port.cpp @@ -0,0 +1,109 @@ +#include "std_include.hpp" +#include "port.hpp" +#include "logger.hpp" +#include "windows_emulator.hpp" +#include "ports/api_port.hpp" +#include "ports/dns_resolver.hpp" +#include "utils/finally.hpp" + +namespace +{ + struct dummy_port : port + { + NTSTATUS handle_request(windows_emulator& win_emu, const lpc_request_context&) override + { + win_emu.log.error("!!! BAD PORT\n"); + return STATUS_NOT_SUPPORTED; + } + }; +} + +std::unique_ptr create_port(const std::u16string_view port) +{ + if (port == u"\\Windows\\ApiPort") + { + return create_api_port(); + } + + if (port == u"\\RPC Control\\DNSResolver") + { + return create_dns_resolver(); + } + + return std::make_unique(); +} + +NTSTATUS port::handle_message(windows_emulator& win_emu, const lpc_message_context& c) +{ + const auto send_header = c.send_message.read(); + + auto recv_header = send_header; + recv_header.u2.s2.Type = LPC_REPLY; + + if (send_header.u2.s2.Type == LPC_NO_IMPERSONATE) + { + recv_header.u2.s2.Type |= LPC_NO_IMPERSONATE; + } + + lpc_request_context context{}; + context.send_buffer = c.send_message.value() + sizeof(PORT_MESSAGE64); + context.send_buffer_length = send_header.u1.s1.DataLength; + context.recv_buffer = c.receive_message.value() + sizeof(PORT_MESSAGE64); + context.recv_buffer_length = recv_header.u1.s1.DataLength; + + NTSTATUS status = this->handle_request(win_emu, context); + + recv_header.u1.s1.DataLength = static_cast(context.recv_buffer_length); + recv_header.u1.s1.TotalLength = static_cast(sizeof(PORT_MESSAGE64) + context.recv_buffer_length); + c.receive_message.write(recv_header); + + return status; +} + +NTSTATUS rpc_port::handle_request(windows_emulator& win_emu, const lpc_request_context& c) +{ + const auto operation = win_emu.emu().read_memory(c.send_buffer); + + switch (operation) + { + case 1: // Handshake + return handle_handshake(win_emu, c); + case 0: // Call + return handle_rpc_call(win_emu, c); + default: + win_emu.log.print(color::gray, "Unexpected RPC operation: 0x%X\n", operation); + return STATUS_NOT_SUPPORTED; + } +} + +NTSTATUS rpc_port::handle_handshake(windows_emulator& win_emu, const lpc_request_context& c) +{ + win_emu.emu().write_memory(c.recv_buffer + 8, 0); + + if (win_emu.emu().read_memory(c.send_buffer + 32) == 3) + { + win_emu.emu().write_memory(c.recv_buffer + 32, 2); + } + + return STATUS_SUCCESS; +} + +NTSTATUS rpc_port::handle_rpc_call(windows_emulator& win_emu, const lpc_request_context& c) +{ + const auto procedure_id = win_emu.emu().read_memory(c.send_buffer + 12); + + std::array header = {0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + procedure_id, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + win_emu.emu().write_memory(c.recv_buffer, header); + + lpc_request_context rpc_context{}; + rpc_context.send_buffer = c.send_buffer + 0x40; + rpc_context.send_buffer_length = c.send_buffer_length - 0x40; + rpc_context.recv_buffer = c.recv_buffer + sizeof(header); + rpc_context.recv_buffer_length = c.recv_buffer_length; + + NTSTATUS status = this->handle_rpc(win_emu, procedure_id, rpc_context); + c.recv_buffer_length = sizeof(header) + rpc_context.recv_buffer_length; + + return status; +} diff --git a/src/windows-emulator/port.hpp b/src/windows-emulator/port.hpp new file mode 100644 index 00000000..ec5e7d0c --- /dev/null +++ b/src/windows-emulator/port.hpp @@ -0,0 +1,187 @@ +#pragma once + +#include +#include +#include + +#include "emulator_utils.hpp" +#include "handles.hpp" + +class windows_emulator; +struct process_context; + +struct lpc_message_context +{ + emulator_object send_message; + emulator_object receive_message; + + lpc_message_context(x86_64_emulator& emu) + : send_message(emu), + receive_message(emu) + { + } + + lpc_message_context(utils::buffer_deserializer& buffer) + : lpc_message_context(buffer.read().get()) + { + } + + void serialize(utils::buffer_serializer& buffer) const + { + buffer.write(send_message); + buffer.write(receive_message); + } + + void deserialize(utils::buffer_deserializer& buffer) + { + buffer.read(send_message); + buffer.read(receive_message); + } +}; + +struct lpc_request_context +{ + emulator_pointer send_buffer{}; + ULONG send_buffer_length{}; + emulator_pointer recv_buffer{}; + mutable ULONG recv_buffer_length{}; + + void serialize(utils::buffer_serializer& buffer) const + { + buffer.write(send_buffer); + buffer.write(send_buffer_length); + buffer.write(recv_buffer); + buffer.write(recv_buffer_length); + } + + void deserialize(utils::buffer_deserializer& buffer) + { + buffer.read(send_buffer); + buffer.read(send_buffer_length); + buffer.read(recv_buffer); + buffer.read(recv_buffer_length); + } +}; + +struct port_creation_data +{ + uint64_t view_base; + int64_t view_size; +}; + +struct port : ref_counted_object +{ + uint64_t view_base{}; + int64_t view_size{}; + + port() = default; + ~port() override = default; + + port(port&&) = default; + port& operator=(port&&) = default; + + port(const port&) = delete; + port& operator=(const port&) = delete; + + void serialize_object(utils::buffer_serializer& buffer) const override + { + buffer.write(this->view_base); + buffer.write(this->view_size); + } + + void deserialize_object(utils::buffer_deserializer& buffer) override + { + buffer.read(this->view_base); + buffer.read(this->view_size); + } + + virtual void create(windows_emulator& win_emu, const port_creation_data& data) + { + (void)win_emu; + view_base = data.view_base; + view_size = data.view_size; + } + + NTSTATUS handle_message(windows_emulator& win_emu, const lpc_message_context& c); + + virtual NTSTATUS handle_request(windows_emulator& win_emu, const lpc_request_context& c) = 0; +}; + +struct rpc_port : port +{ + NTSTATUS handle_request(windows_emulator& win_emu, const lpc_request_context& c) override; + + virtual NTSTATUS handle_rpc(windows_emulator& win_emu, uint32_t procedure_id, const lpc_request_context& c) = 0; + + private: + static NTSTATUS handle_handshake(windows_emulator& win_emu, const lpc_request_context& c); + NTSTATUS handle_rpc_call(windows_emulator& win_emu, const lpc_request_context& c); +}; + +std::unique_ptr create_port(std::u16string_view port); + +class port_container : public port +{ + public: + port_container() = default; + + port_container(std::u16string port, windows_emulator& win_emu, const port_creation_data& data) + : port_name_(std::move(port)) + { + this->setup(); + this->port_->create(win_emu, data); + } + + NTSTATUS handle_request(windows_emulator& win_emu, const lpc_request_context& c) override + { + this->assert_validity(); + return this->port_->handle_request(win_emu, c); + } + + void serialize_object(utils::buffer_serializer& buffer) const override + { + this->assert_validity(); + + buffer.write_string(this->port_name_); + this->port_->serialize(buffer); + } + + void deserialize_object(utils::buffer_deserializer& buffer) override + { + buffer.read_string(this->port_name_); + this->setup(); + this->port_->deserialize(buffer); + } + + template + requires(std::is_base_of_v || std::is_same_v) + T* get_internal_port() const + { + this->assert_validity(); + auto* value = this->port_.get(); + return dynamic_cast(value); + } + + std::u16string_view get_port_name() const + { + this->assert_validity(); + return this->port_name_; + } + + private: + std::u16string port_name_{}; + std::unique_ptr port_{}; + + void setup() + { + this->port_ = create_port(this->port_name_); + } + + void assert_validity() const + { + if (!this->port_) + { + throw std::runtime_error("Port not created!"); + } + } +}; diff --git a/src/windows-emulator/ports/api_port.cpp b/src/windows-emulator/ports/api_port.cpp new file mode 100644 index 00000000..5b17b4c9 --- /dev/null +++ b/src/windows-emulator/ports/api_port.cpp @@ -0,0 +1,36 @@ +#include "../std_include.hpp" +#include "api_port.hpp" + +#include "../windows_emulator.hpp" + +namespace +{ + struct api_port : port + { + NTSTATUS handle_request(windows_emulator& win_emu, const lpc_request_context& c) override + { + // TODO: Fix this. This is broken and wrong. + + try + { + const emulator_object>> data{win_emu.emu(), c.recv_buffer + 0x20}; + const auto dest = data.read(); + const auto base = dest.Base; + + const auto value = base + 0x10; + win_emu.emu().write_memory(base + 8, &value, sizeof(value)); + } + catch (...) + { + return STATUS_NOT_SUPPORTED; + } + + return STATUS_SUCCESS; + } + }; +} + +std::unique_ptr create_api_port() +{ + return std::make_unique(); +} diff --git a/src/windows-emulator/ports/api_port.hpp b/src/windows-emulator/ports/api_port.hpp new file mode 100644 index 00000000..bf47351f --- /dev/null +++ b/src/windows-emulator/ports/api_port.hpp @@ -0,0 +1,4 @@ +#pragma once +#include "../port.hpp" + +std::unique_ptr create_api_port(); diff --git a/src/windows-emulator/ports/dns_resolver.cpp b/src/windows-emulator/ports/dns_resolver.cpp new file mode 100644 index 00000000..aa6f61b5 --- /dev/null +++ b/src/windows-emulator/ports/dns_resolver.cpp @@ -0,0 +1,225 @@ +#include "../std_include.hpp" +#include "dns_resolver.hpp" + +#include "binary_writer.hpp" +#include "../windows_emulator.hpp" + +#define DNS_TYPE_A 0x01 +#define DNS_TYPE_CNAME 0x05 +#define DNS_TYPE_AAAA 0x1C + +#ifndef OS_WINDOWS +#define ERROR_SUCCESS 0x0 +#define DNS_ERROR_RCODE_NAME_ERROR 0x232B +#endif + +namespace +{ + using IP4_ADDRESS = DWORD; + + struct DNS_A_DATA + { + IP4_ADDRESS IpAddress; + }; + + struct IP6_ADDRESS + { + std::array IP6Qword; + }; + + struct DNS_AAAA_DATA + { + IP6_ADDRESS Ip6Address; + }; + + template + struct DNS_RECORDW + { + EMULATOR_CAST(Traits::PVOID, DNS_RECORDW*) pNext; + EMULATOR_CAST(Traits::PVOID, const char16_t*) pName; + WORD wType; + WORD wDataLength; + DWORD Flags; + DWORD dwTtl; + DWORD dwReserved; + union + { + DNS_A_DATA A; + DNS_AAAA_DATA AAAA; + } Data; + + void write(utils::aligned_binary_writer& writer) const + { + writer.write_ndr_pointer(this->pNext); + writer.write_ndr_pointer(this->pName); + writer.write(this->wType); + writer.write(this->wDataLength); + writer.write(this->Flags); + writer.write(this->dwTtl); + writer.write(this->dwReserved); + + writer.write(this->wType); // union identifier + writer.write(&this->Data, this->wDataLength, sizeof(typename Traits::PVOID)); + + writer.write_ndr_u16string(reinterpret_cast(this->pName)); + } + }; + static_assert(sizeof(DNS_RECORDW>) == 48); + + template + struct DNS_QUERY_RESPONSE + { + std::optional> dns_record; + uint64_t error_code{}; + + void write(utils::aligned_binary_writer& writer) const + { + // NOTE: The response is pretty much just an array of DNS_RECORD, marshalled using NDR64. + if (!this->dns_record) + { + writer.write_ndr_pointer(false); + } + else + { + writer.write_ndr_pointer(true); + writer.write(*this->dns_record); + } + + writer.align_to(sizeof(typename Traits::PVOID)); + writer.pad(24); + writer.write(error_code); + writer.pad(64); + } + }; + + WORD convert_socket_famity_to_dns_type(const int family) + { + switch (family) + { + case AF_INET: + return DNS_TYPE_A; + case AF_INET6: + return DNS_TYPE_AAAA; + default: + throw std::runtime_error("Unexpected DNS type!"); + } + } + + template + std::optional> resolve_host_address(const std::u16string& host, const WORD dns_type) + { + addrinfo hints{}; + hints.ai_family = AF_UNSPEC; + + DNS_RECORDW result{}; + result.pName = reinterpret_cast(host.c_str()); + result.Flags = 0x2009; + result.dwTtl = 0x708; + + addrinfo* res = nullptr; + int status = getaddrinfo(u16_to_u8(host).c_str(), nullptr, &hints, &res); + if (status == 0) + { + for (addrinfo* p = res; p != nullptr && dns_type != result.wType; p = p->ai_next) + { + if (p->ai_family == AF_INET) + { + auto* ipv4 = reinterpret_cast(p->ai_addr); + memset(&result.Data, 0, 16); + memcpy(&result.Data, &ipv4->sin_addr, sizeof(ipv4->sin_addr)); + result.wDataLength = sizeof(ipv4->sin_addr); + } + else if (p->ai_family == AF_INET6) + { + auto* ipv6 = reinterpret_cast(p->ai_addr); + memset(&result.Data, 0, 16); + memcpy(&result.Data, &ipv6->sin6_addr, sizeof(ipv6->sin6_addr)); + result.wDataLength = sizeof(ipv6->sin6_addr); + } + else + { + continue; + } + result.wType = convert_socket_famity_to_dns_type(p->ai_family); + } + + freeaddrinfo(res); + } + + if (result.wType == DNS_TYPE_A && dns_type == DNS_TYPE_AAAA) + { + auto* addr = reinterpret_cast(&result.Data); + addr[10] = 0xff; + addr[11] = 0xff; + memcpy(addr + 12, addr, 4); + memset(addr, 0, 10); + result.wType = DNS_TYPE_AAAA; + } + + if (result.wType != dns_type || result.wType == 0) + { + return {}; + } + + return result; + } + + struct dns_resolver : rpc_port + { + NTSTATUS handle_rpc(windows_emulator& win_emu, const uint32_t procedure_id, const lpc_request_context& c) override + { + std::array request_cookie; + win_emu.emu().read_memory(c.send_buffer + c.send_buffer_length - 8, request_cookie.data(), request_cookie.size()); + + utils::aligned_binary_writer> writer(win_emu.emu(), c.recv_buffer); + writer.write(request_cookie); + + switch (procedure_id) + { + case 2: + handle_dns_query(win_emu, c, writer); + break; + case 3: + return STATUS_NOT_SUPPORTED; + default: + throw std::runtime_error("Unimplemented procedure!"); + } + + return STATUS_SUCCESS; + } + + template + static void handle_dns_query(windows_emulator& win_emu, const lpc_request_context& c, utils::aligned_binary_writer& writer) + { + auto& emu = win_emu.emu(); + + const auto hostname_length = static_cast(emu.read_memory(c.send_buffer + 0x08)); + const auto hostname_offset = c.send_buffer + 0x20; + + std::u16string hostname; + hostname.resize(hostname_length - 1); + emu.read_memory(hostname_offset, hostname.data(), (hostname_length - 1) * sizeof(char16_t)); + + const auto query_type = emu.read_memory(hostname_offset + hostname_length * sizeof(char16_t)); + + if (query_type != DNS_TYPE_A && query_type != DNS_TYPE_AAAA) + { + throw std::runtime_error("Unexpected DNS query type!"); + } + + win_emu.callbacks.on_generic_activity("DNS query: " + u16_to_u8(hostname)); + + DNS_QUERY_RESPONSE response{}; + response.dns_record = resolve_host_address(hostname, query_type); + response.error_code = response.dns_record ? ERROR_SUCCESS : DNS_ERROR_RCODE_NAME_ERROR; + writer.write(response); + + c.recv_buffer_length = static_cast(writer.offset()); + } + }; +} + +std::unique_ptr create_dns_resolver() +{ + return std::make_unique(); +} diff --git a/src/windows-emulator/ports/dns_resolver.hpp b/src/windows-emulator/ports/dns_resolver.hpp new file mode 100644 index 00000000..53bfb182 --- /dev/null +++ b/src/windows-emulator/ports/dns_resolver.hpp @@ -0,0 +1,4 @@ +#pragma once +#include "../port.hpp" + +std::unique_ptr create_dns_resolver(); diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index 66b21342..8d7bb178 100644 --- a/src/windows-emulator/process_context.hpp +++ b/src/windows-emulator/process_context.hpp @@ -13,6 +13,7 @@ #include "kusd_mmio.hpp" #include "windows_objects.hpp" #include "emulator_thread.hpp" +#include "port.hpp" #include "apiset/apiset.hpp" @@ -107,7 +108,7 @@ struct process_context handle_store sections{}; handle_store devices{}; handle_store semaphores{}; - handle_store ports{}; + handle_store ports{}; handle_store mutants{}; handle_store windows{}; handle_store timers{}; diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 714bc7be..9e0b3347 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -170,8 +170,23 @@ namespace syscalls emulator_object server_shared_memory, emulator_object maximum_message_length, emulator_pointer connection_info, emulator_object connection_info_length); + NTSTATUS handle_NtAlpcConnectPort(const syscall_context& c, emulator_object port_handle, + emulator_object>> server_port_name, + emulator_object>> /*object_attributes*/, + emulator_pointer /*port_attributes*/, ULONG /*flags*/, emulator_pointer /*required_server_sid*/, + emulator_pointer /*connection_message*/, + emulator_object::SIZE_T> /*buffer_length*/, + emulator_pointer /*out_message_attributes*/, emulator_pointer /*in_message_attributes*/, + emulator_object /*timeout*/); + NTSTATUS handle_NtAlpcConnectPortEx(const syscall_context& c, emulator_object port_handle, + emulator_object>> connection_port_object_attributes, + emulator_object>> /*client_port_object_attributes*/, + emulator_pointer port_attributes, ULONG flags, emulator_pointer /*server_security_requirements*/, + emulator_pointer connection_message, emulator_object::SIZE_T> buffer_length, + emulator_pointer out_message_attributes, emulator_pointer in_message_attributes, + emulator_object timeout); NTSTATUS handle_NtAlpcSendWaitReceivePort(const syscall_context& c, handle port_handle, ULONG /*flags*/, - emulator_object /*send_message*/, + emulator_object send_message, emulator_object /*send_message_attributes*/, emulator_object receive_message, @@ -179,8 +194,9 @@ namespace syscalls emulator_object /*receive_message_attributes*/, emulator_object /*timeout*/); - NTSTATUS handle_NtAlpcConnectPort(); - NTSTATUS handle_NtAlpcConnectPortEx(); + NTSTATUS handle_NtAlpcQueryInformation(); + NTSTATUS handle_NtAlpcCreateSecurityContext(); + NTSTATUS handle_NtAlpcDeleteSecurityContext(); // syscalls/process.cpp: NTSTATUS handle_NtQueryInformationProcess(const syscall_context& c, handle process_handle, uint32_t info_class, @@ -1070,8 +1086,9 @@ void syscall_dispatcher::add_handlers(std::map& ha add_handler(NtReleaseSemaphore); add_handler(NtEnumerateKey); add_handler(NtEnumerateValueKey); - add_handler(NtAlpcConnectPort); add_handler(NtAlpcConnectPortEx); + add_handler(NtAlpcConnectPort); + add_handler(NtAlpcQueryInformation); add_handler(NtGetNextThread); add_handler(NtSetInformationObject); add_handler(NtUserGetCursorPos); @@ -1133,6 +1150,8 @@ void syscall_dispatcher::add_handlers(std::map& ha add_handler(NtRemoveIoCompletionEx); add_handler(NtCreateDebugObject); add_handler(NtReleaseWorkerFactoryWorker); + add_handler(NtAlpcCreateSecurityContext); + add_handler(NtAlpcDeleteSecurityContext); #undef add_handler } diff --git a/src/windows-emulator/syscalls/port.cpp b/src/windows-emulator/syscalls/port.cpp index fcaf7319..c4c21714 100644 --- a/src/windows-emulator/syscalls/port.cpp +++ b/src/windows-emulator/syscalls/port.cpp @@ -1,6 +1,7 @@ #include "../std_include.hpp" #include "../emulator_utils.hpp" #include "../syscall_utils.hpp" +#include "../port.hpp" namespace syscalls { @@ -15,8 +16,18 @@ namespace syscalls auto port_name = read_unicode_string(c.emu, server_port_name); c.win_emu.callbacks.on_generic_access("Connecting port", port_name); - port p{}; - p.name = std::move(port_name); + port_creation_data data{}; + client_shared_memory.access([&](PORT_VIEW64& view) { + data.view_size = view.ViewSize; + data.view_base = c.win_emu.memory.allocate_memory(static_cast(data.view_size), memory_permission::read_write); + view.ViewBase = data.view_base; + view.ViewRemoteBase = view.ViewBase; + }); + + port_container container{std::u16string(port_name), c.win_emu, data}; + + const auto handle = c.proc.ports.store(std::move(container)); + client_port_handle.write(handle); if (connection_info) { @@ -25,15 +36,6 @@ namespace syscalls c.emu.write_memory(connection_info, zero_mem.data(), zero_mem.size()); } - client_shared_memory.access([&](PORT_VIEW64& view) { - p.view_base = c.win_emu.memory.allocate_memory(static_cast(view.ViewSize), memory_permission::read_write); - view.ViewBase = p.view_base; - view.ViewRemoteBase = view.ViewBase; - }); - - const auto handle = c.proc.ports.store(std::move(p)); - client_port_handle.write(handle); - return STATUS_SUCCESS; } @@ -49,8 +51,53 @@ namespace syscalls maximum_message_length, connection_info, connection_info_length); } + NTSTATUS handle_NtAlpcConnectPort(const syscall_context& c, const emulator_object port_handle, + const emulator_object>> server_port_name, + const emulator_object>> /*object_attributes*/, + const emulator_pointer /*port_attributes*/, const ULONG /*flags*/, + const emulator_pointer /*required_server_sid*/, const emulator_pointer /*connection_message*/, + const emulator_object::SIZE_T> /*buffer_length*/, + const emulator_pointer /*out_message_attributes*/, const emulator_pointer /*in_message_attributes*/, + const emulator_object /*timeout*/) + { + auto port_name = read_unicode_string(c.emu, server_port_name); + c.win_emu.log.print(color::dark_gray, "NtAlpcConnectPort: %s\n", u16_to_u8(port_name).c_str()); + + port_container container{std::u16string(port_name), c.win_emu, {}}; + + const auto handle = c.proc.ports.store(std::move(container)); + port_handle.write(handle); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtAlpcConnectPortEx(const syscall_context& c, const emulator_object port_handle, + const emulator_object>> connection_port_object_attributes, + const emulator_object>> /*client_port_object_attributes*/, + const emulator_pointer port_attributes, const ULONG flags, + const emulator_pointer /*server_security_requirements*/, const emulator_pointer connection_message, + const emulator_object::SIZE_T> buffer_length, + const emulator_pointer out_message_attributes, const emulator_pointer in_message_attributes, + const emulator_object timeout) + { + if (!connection_port_object_attributes) + { + return STATUS_INVALID_PARAMETER; + } + + const auto attributes = connection_port_object_attributes.read(); + if (!attributes.ObjectName) + { + return STATUS_INVALID_PARAMETER; + } + + emulator_object>> port_name{c.emu, attributes.ObjectName}; + return handle_NtAlpcConnectPort(c, port_handle, port_name, connection_port_object_attributes, port_attributes, flags, {}, + connection_message, buffer_length, out_message_attributes, in_message_attributes, timeout); + } + NTSTATUS handle_NtAlpcSendWaitReceivePort(const syscall_context& c, const handle port_handle, const ULONG /*flags*/, - const emulator_object /*send_message*/, + const emulator_object send_message, const emulator_object /*send_message_attributes*/, const emulator_object receive_message, @@ -59,38 +106,30 @@ namespace syscalls /*receive_message_attributes*/, const emulator_object /*timeout*/) { - const auto* port = c.proc.ports.get(port_handle); + auto* port = c.proc.ports.get(port_handle); if (!port) { return STATUS_INVALID_HANDLE; } - if (port->name != u"\\Windows\\ApiPort") - { - c.win_emu.log.error("!!! BAD PORT\n"); - return STATUS_NOT_SUPPORTED; - } + lpc_message_context context{c.emu}; + context.send_message = send_message; + context.receive_message = receive_message; - // TODO: Fix this. This is broken and wrong. - - try - { - const emulator_object>> data{c.emu, receive_message.value() + 0x48}; - const auto dest = data.read(); - const auto base = dest.Base; - - const auto value = base + 0x10; - c.emu.write_memory(base + 8, &value, sizeof(value)); - } - catch (...) - { - return STATUS_NOT_SUPPORTED; - } - - return STATUS_SUCCESS; + return port->handle_message(c.win_emu, context); } - NTSTATUS handle_NtAlpcConnectPort() + NTSTATUS handle_NtAlpcQueryInformation() + { + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtAlpcCreateSecurityContext() + { + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtAlpcDeleteSecurityContext() { return STATUS_NOT_SUPPORTED; } diff --git a/src/windows-emulator/windows_objects.hpp b/src/windows-emulator/windows_objects.hpp index 912bfb46..1637804e 100644 --- a/src/windows-emulator/windows_objects.hpp +++ b/src/windows-emulator/windows_objects.hpp @@ -289,21 +289,3 @@ struct semaphore : ref_counted_object buffer.read(this->max_count); } }; - -struct port : ref_counted_object -{ - std::u16string name{}; - uint64_t view_base{}; - - void serialize_object(utils::buffer_serializer& buffer) const override - { - buffer.write(this->name); - buffer.write(this->view_base); - } - - void deserialize_object(utils::buffer_deserializer& buffer) override - { - buffer.read(this->name); - buffer.read(this->view_base); - } -};