Implement ALPC port abstraction and implement DNS resolver port (#558)

This PR introduces an abstraction for ALPC ports to make them easier to
manage in the future, and implements the DNS resolver port, at least
enough to get host address queries working.
There's a lot of code in this PR that I'm not very confident about, so
don't hesitate on the feedback 😄

<img width="1377" height="624" alt="image"
src="https://github.com/user-attachments/assets/4d56b84d-4b87-42ed-9bfa-be04dbbf3735"
/>
This commit is contained in:
Maurice Heumann
2025-10-21 20:42:26 +02:00
committed by GitHub
15 changed files with 844 additions and 111 deletions

View File

@@ -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

View File

@@ -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<Emu64>::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 <typename Traits>
struct PORT_DATA_ENTRY
{
typename Traits::PVOID Base;
ULONG Size;
};
template <typename Traits>
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)

View File

@@ -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<Emu64>::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 <typename Traits>
struct PORT_DATA_ENTRY
{
typename Traits::PVOID Base;
ULONG Size;
};
template <typename Traits>
struct EMU_RTL_SRWLOCK
{

View File

@@ -0,0 +1,98 @@
#pragma once
namespace utils
{
template <typename Traits>
class aligned_binary_writer;
template <typename T, typename Traits>
concept Writable = requires(const T ac, aligned_binary_writer<Traits>& writer) {
{ ac.write(writer) } -> std::same_as<void>;
};
template <typename Traits>
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 <typename T>
requires(!is_optional<T>::value)
void write(const T& value)
{
constexpr auto is_trivially_copyable = std::is_trivially_copyable_v<T>;
if constexpr (Writable<T, Traits>)
{
value.write(*this);
}
else if constexpr (is_trivially_copyable)
{
write(&value, sizeof(T), alignof(T));
}
else
{
static_assert(std::is_trivially_copyable_v<T>, "Type must be trivially copyable or be writable!");
std::abort();
}
}
void write_ndr_pointer(bool not_null)
{
write<typename Traits::PVOID>(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<typename Traits::SIZE_T>(char_count);
write<typename Traits::SIZE_T>(0);
write<typename Traits::SIZE_T>(char_count);
write(str.c_str(), byte_length);
}
void pad(size_t count)
{
std::vector<uint8_t> padding(count, 0);
write(padding.data(), count);
}
void align_to(size_t alignment)
{
size_t offset_val = static_cast<size_t>(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;
};
}

View File

@@ -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

View File

@@ -0,0 +1,108 @@
#include "std_include.hpp"
#include "port.hpp"
#include "logger.hpp"
#include "windows_emulator.hpp"
#include "ports/api_port.hpp"
#include "ports/dns_resolver.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<port> 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<dummy_port>();
}
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<CSHORT>(context.recv_buffer_length);
recv_header.u1.s1.TotalLength = static_cast<CSHORT>(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<uint32_t>(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<uint32_t>(c.recv_buffer + 8, 0);
if (win_emu.emu().read_memory<uint32_t>(c.send_buffer + 32) == 3)
{
win_emu.emu().write_memory<uint32_t>(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<uint8_t>(c.send_buffer + 12);
std::array<uint8_t, 24> 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;
}

View File

@@ -0,0 +1,187 @@
#pragma once
#include <memory>
#include <arch_emulator.hpp>
#include <serialization.hpp>
#include "emulator_utils.hpp"
#include "handles.hpp"
class windows_emulator;
struct process_context;
struct lpc_message_context
{
emulator_object<PORT_MESSAGE64> send_message;
emulator_object<PORT_MESSAGE64> 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<x64_emulator_wrapper>().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<port> 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 <typename T = port>
requires(std::is_base_of_v<port, T> || std::is_same_v<port, T>)
T* get_internal_port() const
{
this->assert_validity();
auto* value = this->port_.get();
return dynamic_cast<T*>(value);
}
std::u16string_view get_port_name() const
{
this->assert_validity();
return this->port_name_;
}
private:
std::u16string port_name_{};
std::unique_ptr<port> port_{};
void setup()
{
this->port_ = create_port(this->port_name_);
}
void assert_validity() const
{
if (!this->port_)
{
throw std::runtime_error("Port not created!");
}
}
};

View File

@@ -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<PORT_DATA_ENTRY<EmulatorTraits<Emu64>>> 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<port> create_api_port()
{
return std::make_unique<api_port>();
}

View File

@@ -0,0 +1,4 @@
#pragma once
#include "../port.hpp"
std::unique_ptr<port> create_api_port();

View File

@@ -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<uint64_t, 2> IP6Qword;
};
struct DNS_AAAA_DATA
{
IP6_ADDRESS Ip6Address;
};
template <typename Traits>
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<Traits>& 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<const char16_t*>(this->pName));
}
};
static_assert(sizeof(DNS_RECORDW<EmulatorTraits<Emu64>>) == 48);
template <typename Traits>
struct DNS_QUERY_RESPONSE
{
std::optional<DNS_RECORDW<Traits>> dns_record;
uint64_t error_code{};
void write(utils::aligned_binary_writer<Traits>& 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 <typename Traits>
std::optional<DNS_RECORDW<Traits>> resolve_host_address(const std::u16string& host, const WORD dns_type)
{
addrinfo hints{};
hints.ai_family = AF_UNSPEC;
DNS_RECORDW<Traits> result{};
result.pName = reinterpret_cast<Traits::PVOID>(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<sockaddr_in*>(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<sockaddr_in6*>(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<uint8_t*>(&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<uint8_t, 8> 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<EmulatorTraits<Emu64>> 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 <typename Traits>
static void handle_dns_query(windows_emulator& win_emu, const lpc_request_context& c, utils::aligned_binary_writer<Traits>& writer)
{
auto& emu = win_emu.emu();
const auto hostname_length = static_cast<size_t>(emu.read_memory<uint64_t>(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<uint16_t>(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<Traits> response{};
response.dns_record = resolve_host_address<Traits>(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<ULONG>(writer.offset());
}
};
}
std::unique_ptr<port> create_dns_resolver()
{
return std::make_unique<dns_resolver>();
}

View File

@@ -0,0 +1,4 @@
#pragma once
#include "../port.hpp"
std::unique_ptr<port> create_dns_resolver();

View File

@@ -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<handle_types::section, section> sections{};
handle_store<handle_types::device, io_device_container> devices{};
handle_store<handle_types::semaphore, semaphore> semaphores{};
handle_store<handle_types::port, port> ports{};
handle_store<handle_types::port, port_container> ports{};
handle_store<handle_types::mutant, mutant> mutants{};
handle_store<handle_types::window, window> windows{};
handle_store<handle_types::timer, timer> timers{};

View File

@@ -171,8 +171,23 @@ namespace syscalls
emulator_object<REMOTE_PORT_VIEW64> server_shared_memory,
emulator_object<ULONG> maximum_message_length, emulator_pointer connection_info,
emulator_object<ULONG> connection_info_length);
NTSTATUS handle_NtAlpcConnectPort(const syscall_context& c, emulator_object<handle> port_handle,
emulator_object<UNICODE_STRING<EmulatorTraits<Emu64>>> server_port_name,
emulator_object<OBJECT_ATTRIBUTES<EmulatorTraits<Emu64>>> /*object_attributes*/,
emulator_pointer /*port_attributes*/, ULONG /*flags*/, emulator_pointer /*required_server_sid*/,
emulator_pointer /*connection_message*/,
emulator_object<EmulatorTraits<Emu64>::SIZE_T> /*buffer_length*/,
emulator_pointer /*out_message_attributes*/, emulator_pointer /*in_message_attributes*/,
emulator_object<LARGE_INTEGER> /*timeout*/);
NTSTATUS handle_NtAlpcConnectPortEx(const syscall_context& c, emulator_object<handle> port_handle,
emulator_object<OBJECT_ATTRIBUTES<EmulatorTraits<Emu64>>> connection_port_object_attributes,
emulator_object<OBJECT_ATTRIBUTES<EmulatorTraits<Emu64>>> /*client_port_object_attributes*/,
emulator_pointer port_attributes, ULONG flags, emulator_pointer /*server_security_requirements*/,
emulator_pointer connection_message, emulator_object<EmulatorTraits<Emu64>::SIZE_T> buffer_length,
emulator_pointer out_message_attributes, emulator_pointer in_message_attributes,
emulator_object<LARGE_INTEGER> timeout);
NTSTATUS handle_NtAlpcSendWaitReceivePort(const syscall_context& c, handle port_handle, ULONG /*flags*/,
emulator_object<PORT_MESSAGE64> /*send_message*/,
emulator_object<PORT_MESSAGE64> send_message,
emulator_object<ALPC_MESSAGE_ATTRIBUTES>
/*send_message_attributes*/,
emulator_object<PORT_MESSAGE64> receive_message,
@@ -180,8 +195,9 @@ namespace syscalls
emulator_object<ALPC_MESSAGE_ATTRIBUTES>
/*receive_message_attributes*/,
emulator_object<LARGE_INTEGER> /*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,
@@ -1072,8 +1088,9 @@ void syscall_dispatcher::add_handlers(std::map<std::string, syscall_handler>& 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);
@@ -1135,6 +1152,8 @@ void syscall_dispatcher::add_handlers(std::map<std::string, syscall_handler>& ha
add_handler(NtRemoveIoCompletionEx);
add_handler(NtCreateDebugObject);
add_handler(NtReleaseWorkerFactoryWorker);
add_handler(NtAlpcCreateSecurityContext);
add_handler(NtAlpcDeleteSecurityContext);
#undef add_handler
}

View File

@@ -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<size_t>(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<size_t>(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<handle> port_handle,
const emulator_object<UNICODE_STRING<EmulatorTraits<Emu64>>> server_port_name,
const emulator_object<OBJECT_ATTRIBUTES<EmulatorTraits<Emu64>>> /*object_attributes*/,
const emulator_pointer /*port_attributes*/, const ULONG /*flags*/,
const emulator_pointer /*required_server_sid*/, const emulator_pointer /*connection_message*/,
const emulator_object<EmulatorTraits<Emu64>::SIZE_T> /*buffer_length*/,
const emulator_pointer /*out_message_attributes*/, const emulator_pointer /*in_message_attributes*/,
const emulator_object<LARGE_INTEGER> /*timeout*/)
{
auto port_name = read_unicode_string(c.emu, server_port_name);
c.win_emu.callbacks.on_generic_access("Connecting port", port_name);
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<handle> port_handle,
const emulator_object<OBJECT_ATTRIBUTES<EmulatorTraits<Emu64>>> connection_port_object_attributes,
const emulator_object<OBJECT_ATTRIBUTES<EmulatorTraits<Emu64>>> /*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<EmulatorTraits<Emu64>::SIZE_T> buffer_length,
const emulator_pointer out_message_attributes, const emulator_pointer in_message_attributes,
const emulator_object<LARGE_INTEGER> 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<UNICODE_STRING<EmulatorTraits<Emu64>>> 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<PORT_MESSAGE64> /*send_message*/,
const emulator_object<PORT_MESSAGE64> send_message,
const emulator_object<ALPC_MESSAGE_ATTRIBUTES>
/*send_message_attributes*/,
const emulator_object<PORT_MESSAGE64> receive_message,
@@ -59,38 +106,30 @@ namespace syscalls
/*receive_message_attributes*/,
const emulator_object<LARGE_INTEGER> /*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<PORT_DATA_ENTRY<EmulatorTraits<Emu64>>> 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;
}

View File

@@ -290,21 +290,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);
}
};