From cef85295aff61713fd3857e8de6b32733e6b17cd Mon Sep 17 00:00:00 2001 From: momo5502 Date: Thu, 12 Sep 2024 13:05:02 +0200 Subject: [PATCH] Prepare serialization support --- src/emulator/byte_buffer.hpp | 191 ------------------------ src/emulator/memory_manager.cpp | 36 ++++- src/emulator/memory_manager.hpp | 5 + src/emulator/serializable.hpp | 9 -- src/emulator/serialization.hpp | 235 ++++++++++++++++++++++++++++++ src/windows_emulator/main.cpp | 12 +- src/windows_emulator/syscalls.cpp | 17 +++ 7 files changed, 301 insertions(+), 204 deletions(-) delete mode 100644 src/emulator/byte_buffer.hpp delete mode 100644 src/emulator/serializable.hpp create mode 100644 src/emulator/serialization.hpp diff --git a/src/emulator/byte_buffer.hpp b/src/emulator/byte_buffer.hpp deleted file mode 100644 index b06a376b..00000000 --- a/src/emulator/byte_buffer.hpp +++ /dev/null @@ -1,191 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace utils -{ - class buffer_deserializer - { - public: - template - buffer_deserializer(const std::basic_string_view& buffer) - : buffer_(reinterpret_cast(buffer.data()), buffer.size() * sizeof(T)) - { - static_assert(std::is_trivially_copyable_v, "Type must be trivially copyable"); - } - - template - buffer_deserializer(const std::basic_string& buffer) - : buffer_deserializer(std::basic_string_view(buffer.data(), buffer.size())) - { - } - - template - buffer_deserializer(const std::vector& buffer) - : buffer_deserializer(std::basic_string_view(buffer.data(), buffer.size())) - { - } - - void read(void* data, const size_t length) - { - if (this->offset_ + length > this->buffer_.size()) - { - throw std::runtime_error("Out of bounds read from byte buffer"); - } - - memcpy(data, this->buffer_.data() + this->offset_, length); - this->offset_ += length; - } - - std::string read_data(const size_t length) - { - std::string result{}; - result.resize(length); - - this->read(result.data(), result.size()); - - return result; - } - - template - T read() - { - static_assert(std::is_trivially_copyable_v, "Type must be trivially copyable"); - - T object{}; - this->read(&object, sizeof(object)); - return object; - } - - template - std::vector read_vector() - { - static_assert(std::is_trivially_copyable_v, "Type must be trivially copyable"); - - std::vector result{}; - const auto size = this->read(); - const auto totalSize = size * sizeof(T); - - if (this->offset_ + totalSize > this->buffer_.size()) - { - throw std::runtime_error("Out of bounds read from byte buffer"); - } - - result.resize(size); - this->read(result.data(), totalSize); - - return result; - } - - std::string read_string() - { - std::string result{}; - const auto size = this->read(); - - if (this->offset_ + size > this->buffer_.size()) - { - throw std::runtime_error("Out of bounds read from byte buffer"); - } - - result.resize(size); - this->read(result.data(), size); - - return result; - } - - size_t get_remaining_size() const - { - return this->buffer_.size() - offset_; - } - - std::string get_remaining_data() - { - return this->read_data(this->get_remaining_size()); - } - - size_t get_offset() const - { - return this->offset_; - } - - private: - size_t offset_{0}; - std::basic_string_view buffer_{}; - }; - - class buffer_serializer - { - public: - buffer_serializer() = default; - - void write(const void* buffer, const size_t length) - { - this->buffer_.append(static_cast(buffer), length); - } - - void write(const char* text) - { - this->write(text, strlen(text)); - } - - void write_string(const char* str, const size_t length) - { - this->write(static_cast(length)); - this->write(str, length); - } - - void write_string(const std::string& str) - { - this->write_string(str.data(), str.size()); - } - - void write_string(const char* str) - { - this->write_string(str, strlen(str)); - } - - void write(const buffer_serializer& object) - { - const auto& buffer = object.get_buffer(); - this->write(buffer.data(), buffer.size()); - } - - template - void write(const T& object) - { - static_assert(std::is_trivially_copyable_v, "Type must be trivially copyable"); - this->write(&object, sizeof(object)); - } - - template - void write(const std::vector& vec) - { - static_assert(std::is_trivially_copyable_v, "Type must be trivially copyable"); - this->write(vec.data(), vec.size() * sizeof(T)); - } - - template - void write_vector(const std::vector& vec) - { - static_assert(std::is_trivially_copyable_v, "Type must be trivially copyable"); - this->write(static_cast(vec.size())); - this->write(vec); - } - - const std::string& get_buffer() const - { - return this->buffer_; - } - - std::string move_buffer() - { - return std::move(this->buffer_); - } - - private: - std::string buffer_{}; - }; -} diff --git a/src/emulator/memory_manager.cpp b/src/emulator/memory_manager.cpp index ba53171f..46f8d09f 100644 --- a/src/emulator/memory_manager.cpp +++ b/src/emulator/memory_manager.cpp @@ -63,6 +63,40 @@ namespace } } +static void serialize(utils::buffer_serializer& buffer, const memory_manager::committed_region& region) +{ + buffer.write(region.length); + buffer.write(region.pemissions); +} + +static void deserialize(utils::buffer_deserializer& buffer, memory_manager::committed_region& region) +{ + region.length = static_cast(buffer.read()); + region.pemissions = buffer.read(); +} + +static void serialize(utils::buffer_serializer& buffer, const memory_manager::reserved_region& region) +{ + buffer.write(region.length); + buffer.write_map(region.committed_regions); +} + +static void deserialize(utils::buffer_deserializer& buffer, memory_manager::reserved_region& region) +{ + region.length = static_cast(buffer.read()); + region.committed_regions = buffer.read_map(); +} + +void memory_manager::serialize_memory_state(utils::buffer_serializer& buffer) const +{ + buffer.write_map(this->reserved_regions_); +} + +void memory_manager::deserialize_memory_state(utils::buffer_deserializer& buffer) +{ + this->reserved_regions_ = buffer.read_map(); +} + bool memory_manager::protect_memory(const uint64_t address, const size_t size, const memory_permission permissions, memory_permission* old_permissions) { @@ -293,7 +327,7 @@ uint64_t memory_manager::find_free_allocation_base(const size_t size, const uint for (const auto& region : this->reserved_regions_) { const auto region_end = region.first + region.second.length; - if(region_end < start_address) + if (region_end < start_address) { continue; } diff --git a/src/emulator/memory_manager.hpp b/src/emulator/memory_manager.hpp index b7059ba4..0205644e 100644 --- a/src/emulator/memory_manager.hpp +++ b/src/emulator/memory_manager.hpp @@ -3,6 +3,7 @@ #include "memory_region.hpp" #include "address_utils.hpp" +#include "serialization.hpp" struct region_info : basic_memory_region { @@ -85,4 +86,8 @@ private: virtual void unmap_memory(uint64_t address, size_t size) = 0; virtual void apply_memory_protection(uint64_t address, size_t size, memory_permission permissions) = 0; + +protected: + void serialize_memory_state(utils::buffer_serializer& buffer) const; + void deserialize_memory_state(utils::buffer_deserializer& buffer); }; diff --git a/src/emulator/serializable.hpp b/src/emulator/serializable.hpp deleted file mode 100644 index 3d4cb32f..00000000 --- a/src/emulator/serializable.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "byte_buffer.hpp" - -struct serializable -{ - virtual ~serializable() = default; - virtual void serialize(utils::buffer_serializer& buffer) = 0; - virtual void deserialize(utils::buffer_deserializer& buffer) = 0; -}; diff --git a/src/emulator/serialization.hpp b/src/emulator/serialization.hpp new file mode 100644 index 00000000..5235de2a --- /dev/null +++ b/src/emulator/serialization.hpp @@ -0,0 +1,235 @@ +#pragma once + +#include +#include +#include +#include + +namespace utils +{ + class buffer_serializer; + class buffer_deserializer; + + struct serializable + { + virtual ~serializable() = default; + virtual void serialize(buffer_serializer& buffer) const = 0; + virtual void deserialize(buffer_deserializer& buffer) = 0; + }; + + namespace detail + { + template + struct has_serialize_function : std::false_type {}; + + template + struct has_serialize_function(), std::declval()))>> + : std::true_type {}; + + template + struct has_deserialize_function : std::false_type {}; + + template + struct has_deserialize_function(), std::declval()))>> + : std::true_type {}; + } + + class buffer_deserializer + { + public: + template + buffer_deserializer(const std::span& buffer) + : buffer_(reinterpret_cast(buffer.data()), buffer.size() * sizeof(T)) + { + static_assert(std::is_trivially_copyable_v, "Type must be trivially copyable"); + } + + std::span read_data(const size_t length) + { + if (this->offset_ + length > this->buffer_.size()) + { + throw std::runtime_error("Out of bounds read from byte buffer"); + } + + const std::span result(this->buffer_.data() + this->offset_, length); + this->offset_ += length; + + return result; + } + + void read(void* data, const size_t length) + { + const auto span = this->read_data(length); + memcpy(data, span.data(), length); + } + + template + T read() + { + T object{}; + + if constexpr (std::is_base_of_v) + { + object.deserialize(*this); + } + else if constexpr (detail::has_deserialize_function::value) + { + deserialize(*this, object); + } + else if constexpr (std::is_trivially_copyable_v) + { + this->read(&object, sizeof(object)); + } + else + { + static_assert(std::false_type::value, "Key must be trivially copyable or implement serializable!"); + std::abort(); + } + + return object; + } + + template + std::vector read_vector() + { + static_assert(std::is_trivially_copyable_v, "Type must be trivially copyable"); + + std::vector result{}; + const auto size = this->read(); + const auto totalSize = size * sizeof(T); + + if (this->offset_ + totalSize > this->buffer_.size()) + { + throw std::runtime_error("Out of bounds read from byte buffer"); + } + + result.resize(size); + this->read(result.data(), totalSize); + + return result; + } + + template + std::map read_map() + { + const auto size = this->read(); + std::map map{}; + + for (uint64_t i = 0; i < size; ++i) + { + auto key = this->read(); + auto value = this->read(); + + map[std::move(key)] = std::move(value); + } + + return map; + } + + std::string read_string() + { + std::string result{}; + const auto size = this->read(); + const auto span = this->read_data(size); + + result.resize(size); + memcpy(result.data(), span.data(), size); + + return result; + } + + size_t get_remaining_size() const + { + return this->buffer_.size() - offset_; + } + + std::span get_remaining_data() + { + return this->read_data(this->get_remaining_size()); + } + + size_t get_offset() const + { + return this->offset_; + } + + private: + size_t offset_{0}; + std::span buffer_{}; + }; + + class buffer_serializer + { + public: + buffer_serializer() = default; + + void write(const void* buffer, const size_t length) + { + this->buffer_.append(static_cast(buffer), length); + } + + void write(const buffer_serializer& object) + { + const auto& buffer = object.get_buffer(); + this->write(buffer.data(), buffer.size()); + } + + template + void write(const T& object) + { + if constexpr (std::is_base_of_v) + { + object.serialize(*this); + } + else if constexpr (detail::has_serialize_function::value) + { + serialize(*this, object); + } + else if constexpr (std::is_trivially_copyable_v) + { + this->write(&object, sizeof(object)); + } + else + { + static_assert(std::false_type::value, "Key must be trivially copyable or implement serializable!"); + std::abort(); + } + } + + template + void write_span(const std::span vec) + { + this->write(static_cast(vec.size())); + + for (const auto& v : vec) + { + this->write(v); + } + } + + template + void write_map(const std::map& map) + { + this->write(map.size()); + + for (const auto& entry : map) + { + this->write(entry.first); + this->write(entry.second); + } + } + + const std::string& get_buffer() const + { + return this->buffer_; + } + + std::string move_buffer() + { + return std::move(this->buffer_); + } + + private: + std::string buffer_{}; + }; +} diff --git a/src/windows_emulator/main.cpp b/src/windows_emulator/main.cpp index 556899b2..3c983883 100644 --- a/src/windows_emulator/main.cpp +++ b/src/windows_emulator/main.cpp @@ -318,7 +318,7 @@ namespace context.process_params.access([&](RTL_USER_PROCESS_PARAMETERS& proc_params) { proc_params.Length = sizeof(proc_params); - proc_params.Flags = 0x6001; //| 0x80000000; // Prevent CsrClientConnectToServer + proc_params.Flags = 0x6001 | 0x80000000; // Prevent CsrClientConnectToServer proc_params.ConsoleHandle = CONSOLE_HANDLE.h; proc_params.StandardOutput = STDOUT_HANDLE.h; @@ -572,6 +572,7 @@ namespace const auto permission = get_permission_string(operation); const auto ip = emu->read_instruction_pointer(); + if (type == memory_violation_type::protection) { printf("Protection violation: %llX (%zX) - %s at %llX\n", address, size, permission.c_str(), ip); @@ -585,18 +586,23 @@ namespace return memory_violation_continuation::resume; }); - /* watch_object(*emu, context.teb); watch_object(*emu, context.peb); watch_object(*emu, context.process_params); watch_object(*emu, context.kusd); - */ + context.verbose = false; emu->hook_memory_execution(0, std::numeric_limits::max(), [&](const uint64_t address, const size_t) { ++context.executed_instructions; + if(address == 0x1800629BA) + { + puts("Bad dll"); + emu->stop(); + } + const auto* binary = context.module_manager.find_by_address(address); if (binary) diff --git a/src/windows_emulator/syscalls.cpp b/src/windows_emulator/syscalls.cpp index 91b34227..09863317 100644 --- a/src/windows_emulator/syscalls.cpp +++ b/src/windows_emulator/syscalls.cpp @@ -1316,6 +1316,22 @@ namespace return STATUS_NOT_SUPPORTED; } + NTSTATUS handle_NtAlpcSendWaitReceivePort(const syscall_context& /*c*/, const uint64_t /*port_handle*/, const ULONG /*flags*/, + const emulator_object /*send_message*/, + const emulator_object /*send_message_attributes*/, + const emulator_object receive_message, + const emulator_object /*buffer_length*/, + const emulator_object /*receive_message_attributes*/, + const emulator_object /*timeout*/) + { + receive_message.access([](PORT_MESSAGE& msg) + { + msg.u1.Length = 0; + }); + + return STATUS_SUCCESS; + } + NTSTATUS handle_NtInitializeNlsFiles(const syscall_context& c, const emulator_object base_address, const emulator_object default_locale_id, const emulator_object /*default_casing_table_size*/) @@ -1602,6 +1618,7 @@ syscall_dispatcher::syscall_dispatcher(const exported_symbols& ntdll_exports, co add_handler(NtDuplicateObject); add_handler(NtQueryInformationThread); add_handler(NtQueryWnfStateNameInformation); + add_handler(NtAlpcSendWaitReceivePort); #undef add_handler }