From 456dc99fb6e44fec1d650ef599b339108af6a2dd Mon Sep 17 00:00:00 2001 From: brian Date: Fri, 9 Jan 2026 00:38:03 +0800 Subject: [PATCH 1/6] Improve Windows version detection and LdrSystemDllInitBlock initialization - Add WINDOWS_VERSION enum and PS_SYSTEM_DLL_INIT_BLOCK sizes for WOW64 support across different Windows builds. - Read system information (SystemRoot, BuildNumber, UpdateBuildRevision) from registry instead of hardcoded paths. - Add build comparison helpers in process_context for precise build checks. --- src/common/platform/kernel_mapped.hpp | 28 ++++++ .../module/module_manager.cpp | 94 ++++++++++++++----- .../module/module_manager.hpp | 16 +++- src/windows-emulator/process_context.cpp | 32 +------ src/windows-emulator/process_context.hpp | 47 +++++++++- src/windows-emulator/windows_emulator.cpp | 5 +- 6 files changed, 161 insertions(+), 61 deletions(-) diff --git a/src/common/platform/kernel_mapped.hpp b/src/common/platform/kernel_mapped.hpp index cad0ecf0..27a8d4e7 100644 --- a/src/common/platform/kernel_mapped.hpp +++ b/src/common/platform/kernel_mapped.hpp @@ -2003,4 +2003,32 @@ typedef enum class _SECTION_INFORMATION_CLASS SectionInternalImageInformation = 4 } SECTION_INFORMATION_CLASS, *PSECTION_INFORMATION_CLASS; +enum WINDOWS_VERSION : uint32_t +{ + WINDOWS_10_1507 = 10240, + WINDOWS_10_1511 = 10586, + WINDOWS_10_1607 = 14393, + WINDOWS_10_1703 = 15063, + WINDOWS_10_1709 = 16299, + WINDOWS_10_1803 = 17134, + WINDOWS_10_1809 = 17763, + WINDOWS_10_1903 = 18362, + WINDOWS_10_1909 = 18363, + WINDOWS_10_2004 = 19041, + WINDOWS_10_20H2 = 19042, + WINDOWS_10_21H1 = 19043, + WINDOWS_10_21H2 = 19044, + WINDOWS_10_22H2 = 19045, + WINDOWS_11_21H2 = 22000, + WINDOWS_11_22H2 = 22621, + WINDOWS_11_23H2 = 22631, + WINDOWS_11_24H2 = 26100, +}; + +constexpr uint64_t PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V1 = sizeof(PS_SYSTEM_DLL_INIT_BLOCK_V1); +constexpr uint64_t PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V2_1703 = offsetof(PS_SYSTEM_DLL_INIT_BLOCK_V2, MitigationAuditOptionsMap); +constexpr uint64_t PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V2 = sizeof(PS_SYSTEM_DLL_INIT_BLOCK_V2); +constexpr uint64_t PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V3_2004 = offsetof(PS_SYSTEM_DLL_INIT_BLOCK_V3, ScpCfgCheckFunction); +constexpr uint64_t PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V3 = sizeof(PS_SYSTEM_DLL_INIT_BLOCK_V3); + // NOLINTEND(modernize-use-using,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) diff --git a/src/windows-emulator/module/module_manager.cpp b/src/windows-emulator/module/module_manager.cpp index fb6610e4..73d0ea3d 100644 --- a/src/windows-emulator/module/module_manager.cpp +++ b/src/windows-emulator/module/module_manager.cpp @@ -4,6 +4,8 @@ #include "platform/win_pefile.hpp" #include "windows-emulator/logger.hpp" #include "../wow64_heaven_gate.hpp" +#include "../registry/registry_manager.hpp" +#include "../process_context.hpp" #include #include @@ -205,6 +207,52 @@ module_manager::module_manager(memory_manager& memory, file_system& file_sys, ca { } +void module_manager::get_system_information_from_registry(registry_manager& registry, system_information& info, const logger& logger) +{ + constexpr auto version_key_path = R"(\Registry\Machine\Software\Microsoft\Windows NT\CurrentVersion)"; + + const auto version_key = registry.get_key({version_key_path}); + if (!version_key) + { + throw std::runtime_error("Failed to get CurrentVersion registry key"); + } + + for (size_t i = 0; const auto value = registry.get_value(*version_key, i); ++i) + { + if (value->name == "SystemRoot" && value->type == REG_SZ && !value->data.empty()) + { + const auto* data_ptr = reinterpret_cast(value->data.data()); + const auto char_count = value->data.size() / sizeof(char16_t); + std::u16string system_root(data_ptr, char_count > 0 && data_ptr[char_count - 1] == u'\0' ? char_count - 1 : char_count); + info.system_root = windows_path{system_root}; + } + else if ((value->name == "CurrentBuildNumber" || value->name == "CurrentBuild") && value->type == REG_SZ) + { + const auto* s = reinterpret_cast(value->data.data()); + info.build_number = static_cast(std::strtoul(u16_to_u8(s).c_str(), nullptr, 10)); + } + else if (value->name == "UBR" && value->type == REG_DWORD && value->data.size() >= sizeof(uint32_t)) + { + info.update_build_revision = *reinterpret_cast(value->data.data()); + } + } + + if (info.system_root.u16string().empty()) + { + throw std::runtime_error("SystemRoot not found in registry"); + } + + if (info.build_number == 0) + { + logger.error("Failed to get CurrentBuildNumber from registry\n"); + } + + if (info.update_build_revision == 0) + { + logger.error("Failed to get UBR from registry\n"); + } +} + // Core mapping logic to eliminate code duplication mapped_module* module_manager::map_module_core(const pe_detection_result& detection_result, const std::function& mapper, const logger& logger, bool is_static) @@ -257,23 +305,19 @@ void module_manager::load_native_64bit_modules(const windows_path& executable_pa this->win32u = this->map_module(win32u_path, logger, true); } -// WOW64 module loading (with TODO placeholders for 32-bit details) +// WOW64 module loading void module_manager::load_wow64_modules(const windows_path& executable_path, const windows_path& ntdll_path, - const windows_path& win32u_path, const windows_path& ntdll32_path, const logger& logger) + const windows_path& win32u_path, const windows_path& ntdll32_path, process_context& context, + const logger& logger) { logger.info("Loading WOW64 modules for 32-bit application\n"); - // Load 32-bit main executable this->executable = this->map_module(executable_path, logger, true); + this->ntdll = this->map_module(ntdll_path, logger, true); + this->win32u = this->map_module(win32u_path, logger, true); - // Load 64-bit system modules for WOW64 subsystem - this->ntdll = this->map_module(ntdll_path, logger, true); // 64-bit ntdll - this->win32u = this->map_module(win32u_path, logger, true); // 64-bit win32u + this->wow64_modules_.ntdll32 = this->map_module(ntdll32_path, logger, true); - // Load 32-bit ntdll module for WOW64 subsystem - this->wow64_modules_.ntdll32 = this->map_module(ntdll32_path, logger, true); // 32-bit ntdll - - // Get original ImageBase values from PE files const auto ntdll32_original_imagebase = this->wow64_modules_.ntdll32->get_image_base_file(); const auto ntdll64_original_imagebase = this->ntdll->get_image_base_file(); @@ -283,12 +327,10 @@ void module_manager::load_wow64_modules(const windows_path& executable_path, con return; } - // Set up LdrSystemDllInitBlock structure PS_SYSTEM_DLL_INIT_BLOCK init_block = {}; - constexpr uint64_t symtem_dll_init_block_fix_size = 0xF0; // Wine or WIN10 + const auto init_block_size = context.get_system_dll_init_block_size(); - // Basic structure initialization - init_block.Size = symtem_dll_init_block_fix_size; + init_block.Size = static_cast(init_block_size); // Calculate relocation values // SystemDllWowRelocation = mapped_base - original_imagebase for 32-bit ntdll @@ -344,8 +386,7 @@ void module_manager::load_wow64_modules(const windows_path& executable_path, con return; } - // Write the initialized structure to the export address - this->memory_->write_memory(ldr_init_block_addr, &init_block, symtem_dll_init_block_fix_size); + this->memory_->write_memory(ldr_init_block_addr, &init_block, init_block_size); logger.info("Successfully initialized LdrSystemDllInitBlock at 0x%" PRIx64 "\n", ldr_init_block_addr); @@ -422,14 +463,20 @@ void module_manager::install_wow64_heaven_gate(const logger& logger) } } -// Refactored map_main_modules with execution mode detection -void module_manager::map_main_modules(const windows_path& executable_path, const windows_path& system32_path, - const windows_path& syswow64_path, const logger& logger) +void module_manager::map_main_modules(const windows_path& executable_path, registry_manager& registry, process_context& context, + const logger& logger) { - // Detect execution mode based on executable architecture - current_execution_mode_ = detect_execution_mode(executable_path, logger); + system_information sys_info{}; + module_manager::get_system_information_from_registry(registry, sys_info, logger); + const auto system32_path = sys_info.system_root / "System32"; + const auto syswow64_path = sys_info.system_root / "SysWOW64"; + + context.windows_build_number = sys_info.build_number; + context.windows_update_build_revision_number = sys_info.update_build_revision; + + current_execution_mode_ = detect_execution_mode(executable_path, logger); + context.is_wow64_process = (current_execution_mode_ == execution_mode::wow64_32bit); - // Load modules based on detected execution mode switch (current_execution_mode_) { case execution_mode::native_64bit: @@ -437,7 +484,8 @@ void module_manager::map_main_modules(const windows_path& executable_path, const break; case execution_mode::wow64_32bit: - load_wow64_modules(executable_path, system32_path / "ntdll.dll", system32_path / "win32u.dll", syswow64_path / "ntdll.dll", logger); + load_wow64_modules(executable_path, system32_path / "ntdll.dll", system32_path / "win32u.dll", syswow64_path / "ntdll.dll", context, + logger); break; case execution_mode::unknown: diff --git a/src/windows-emulator/module/module_manager.hpp b/src/windows-emulator/module/module_manager.hpp index dfbaaebe..402a0955 100644 --- a/src/windows-emulator/module/module_manager.hpp +++ b/src/windows-emulator/module/module_manager.hpp @@ -7,6 +7,8 @@ #include "platform/win_pefile.hpp" class logger; +class registry_manager; +struct process_context; // Execution mode for the emulated process enum class execution_mode @@ -78,6 +80,13 @@ class pe_architecture_detector static execution_mode determine_execution_mode(winpe::pe_arch executable_arch); }; +struct system_information +{ + windows_path system_root{}; + uint32_t build_number{0}; + uint32_t update_build_revision{0}; +}; + class module_manager { public: @@ -91,8 +100,7 @@ class module_manager module_manager(memory_manager& memory, file_system& file_sys, callbacks& cb); - void map_main_modules(const windows_path& executable_path, const windows_path& system32_path, const windows_path& syswow64_path, - const logger& logger); + void map_main_modules(const windows_path& executable_path, registry_manager& registry, process_context& context, const logger& logger); mapped_module* map_module(const windows_path& file, const logger& logger, bool is_static = false); mapped_module* map_local_module(const std::filesystem::path& file, const logger& logger, bool is_static = false); @@ -186,11 +194,13 @@ class module_manager // Execution mode detection execution_mode detect_execution_mode(const windows_path& executable_path, const logger& logger); + static void get_system_information_from_registry(registry_manager& registry, system_information& info, const logger& logger); + // Module loading helpers void load_native_64bit_modules(const windows_path& executable_path, const windows_path& ntdll_path, const windows_path& win32u_path, const logger& logger); void load_wow64_modules(const windows_path& executable_path, const windows_path& ntdll_path, const windows_path& win32u_path, - const windows_path& ntdll32_path, const logger& logger); + const windows_path& ntdll32_path, process_context& context, const logger& logger); void install_wow64_heaven_gate(const logger& logger); diff --git a/src/windows-emulator/process_context.cpp b/src/windows-emulator/process_context.cpp index d28138fa..c3f5d641 100644 --- a/src/windows-emulator/process_context.cpp +++ b/src/windows-emulator/process_context.cpp @@ -176,40 +176,12 @@ namespace return env_map; } - - uint32_t read_windows_build(registry_manager& registry) - { - const auto key = registry.get_key({R"(\Registry\Machine\Software\Microsoft\Windows NT\CurrentVersion)"}); - - if (!key) - { - return 0; - } - - for (size_t i = 0; const auto value = registry.get_value(*key, i); ++i) - { - if (value->type != REG_SZ) - { - continue; - } - - if (value->name == "CurrentBuildNumber" || value->name == "CurrentBuild") - { - const auto* s = reinterpret_cast(value->data.data()); - return static_cast(std::strtoul(u16_to_u8(s).c_str(), nullptr, 10)); - } - } - - return 0; - } } void process_context::setup(x86_64_emulator& emu, memory_manager& memory, registry_manager& registry, const application_settings& app_settings, const mapped_module& executable, const mapped_module& ntdll, const apiset::container& apiset_container, const mapped_module* ntdll32) { - this->windows_build_number = read_windows_build(registry); - setup_gdt(emu, memory); this->kusd.setup(); @@ -428,7 +400,7 @@ void process_context::setup(x86_64_emulator& emu, memory_manager& memory, regist monitor.hmon = h.bits; monitor.rcMonitor = {.left = 0, .top = 0, .right = 1920, .bottom = 1080}; monitor.rcWork = monitor.rcMonitor; - if (this->is_older_windows_build()) + if (this->is_build_before(26040)) { monitor.b20.monitorDpi = 96; monitor.b20.nativeDpi = monitor.b20.monitorDpi; @@ -465,6 +437,7 @@ void process_context::serialize(utils::buffer_serializer& buffer) const buffer.write(this->is_wow64_process); buffer.write(this->windows_build_number); + buffer.write(this->windows_update_build_revision_number); buffer.write(this->ntdll_image_base); buffer.write(this->ldr_initialize_thunk); buffer.write(this->rtl_user_thread_start); @@ -514,6 +487,7 @@ void process_context::deserialize(utils::buffer_deserializer& buffer) buffer.read(this->is_wow64_process); buffer.read(this->windows_build_number); + buffer.read(this->windows_update_build_revision_number); buffer.read(this->ntdll_image_base); buffer.read(this->ldr_initialize_thunk); buffer.read(this->rtl_user_thread_start); diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index e38cbe5d..b27e8264 100644 --- a/src/windows-emulator/process_context.hpp +++ b/src/windows-emulator/process_context.hpp @@ -94,10 +94,53 @@ struct process_context bool is_wow64_process{false}; uint32_t windows_build_number{0}; + uint32_t windows_update_build_revision_number{0}; - bool is_older_windows_build() const + bool is_build_before(uint32_t build, std::optional ubr = std::nullopt) const { - return windows_build_number < 26040; + if (windows_build_number != build) + return windows_build_number < build; + return ubr.has_value() && windows_update_build_revision_number < *ubr; + } + + bool is_build_before_or_equal(uint32_t build, std::optional ubr = std::nullopt) const + { + if (windows_build_number != build) + return windows_build_number < build; + return !ubr.has_value() || windows_update_build_revision_number <= *ubr; + } + + bool is_build_after_or_equal(uint32_t build, std::optional ubr = std::nullopt) const + { + if (windows_build_number != build) + return windows_build_number > build; + return !ubr.has_value() || windows_update_build_revision_number >= *ubr; + } + + bool is_build_after(uint32_t build, std::optional ubr = std::nullopt) const + { + if (windows_build_number != build) + return windows_build_number > build; + return ubr.has_value() && windows_update_build_revision_number > *ubr; + } + + bool is_build_within(uint32_t start_build, uint32_t end_build, std::optional start_ubr = std::nullopt, + std::optional end_ubr = std::nullopt) const + { + return is_build_after_or_equal(start_build, start_ubr) && is_build_before(end_build, end_ubr); + } + + uint64_t get_system_dll_init_block_size() const + { + if (is_build_after_or_equal(WINDOWS_VERSION::WINDOWS_11_24H2)) + return PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V3; + if (is_build_after_or_equal(WINDOWS_VERSION::WINDOWS_10_2004)) + return PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V3_2004; + if (is_build_after_or_equal(WINDOWS_VERSION::WINDOWS_10_1709)) + return PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V2; + if (is_build_after_or_equal(WINDOWS_VERSION::WINDOWS_10_1703)) + return PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V2_1703; + return PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V1; } callbacks* callbacks_{}; diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index c4057fc4..2fc214e2 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -351,10 +351,7 @@ void windows_emulator::setup_process(const application_settings& app_settings) const auto& emu = this->emu(); auto& context = this->process; - this->mod_manager.map_main_modules(app_settings.application, R"(C:\Windows\System32)", R"(C:\Windows\SysWOW64)", this->log); - - // Set WOW64 flag based on the detected execution mode - context.is_wow64_process = (this->mod_manager.get_execution_mode() == execution_mode::wow64_32bit); + this->mod_manager.map_main_modules(app_settings.application, this->registry, context, this->log); const auto* executable = this->mod_manager.executable; const auto* ntdll = this->mod_manager.ntdll; From a544ad9c89b7eb946af859a109f1a0d1d466ad2c Mon Sep 17 00:00:00 2001 From: brian Date: Fri, 9 Jan 2026 00:47:47 +0800 Subject: [PATCH 2/6] Fix clang tidy --- src/windows-emulator/module/module_manager.cpp | 2 +- src/windows-emulator/process_context.hpp | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/windows-emulator/module/module_manager.cpp b/src/windows-emulator/module/module_manager.cpp index 73d0ea3d..7d7ac9d2 100644 --- a/src/windows-emulator/module/module_manager.cpp +++ b/src/windows-emulator/module/module_manager.cpp @@ -386,7 +386,7 @@ void module_manager::load_wow64_modules(const windows_path& executable_path, con return; } - this->memory_->write_memory(ldr_init_block_addr, &init_block, init_block_size); + this->memory_->write_memory(ldr_init_block_addr, &init_block, static_cast(init_block_size)); logger.info("Successfully initialized LdrSystemDllInitBlock at 0x%" PRIx64 "\n", ldr_init_block_addr); diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index b27e8264..b5d5f850 100644 --- a/src/windows-emulator/process_context.hpp +++ b/src/windows-emulator/process_context.hpp @@ -99,28 +99,36 @@ struct process_context bool is_build_before(uint32_t build, std::optional ubr = std::nullopt) const { if (windows_build_number != build) + { return windows_build_number < build; + } return ubr.has_value() && windows_update_build_revision_number < *ubr; } bool is_build_before_or_equal(uint32_t build, std::optional ubr = std::nullopt) const { if (windows_build_number != build) + { return windows_build_number < build; + } return !ubr.has_value() || windows_update_build_revision_number <= *ubr; } bool is_build_after_or_equal(uint32_t build, std::optional ubr = std::nullopt) const { if (windows_build_number != build) + { return windows_build_number > build; + } return !ubr.has_value() || windows_update_build_revision_number >= *ubr; } bool is_build_after(uint32_t build, std::optional ubr = std::nullopt) const { if (windows_build_number != build) + { return windows_build_number > build; + } return ubr.has_value() && windows_update_build_revision_number > *ubr; } @@ -133,13 +141,21 @@ struct process_context uint64_t get_system_dll_init_block_size() const { if (is_build_after_or_equal(WINDOWS_VERSION::WINDOWS_11_24H2)) + { return PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V3; + } if (is_build_after_or_equal(WINDOWS_VERSION::WINDOWS_10_2004)) + { return PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V3_2004; + } if (is_build_after_or_equal(WINDOWS_VERSION::WINDOWS_10_1709)) + { return PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V2; + } if (is_build_after_or_equal(WINDOWS_VERSION::WINDOWS_10_1703)) + { return PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V2_1703; + } return PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V1; } From 0a414ca346a209a5a080a7ee4083c71cf3b25b4b Mon Sep 17 00:00:00 2001 From: brian Date: Fri, 9 Jan 2026 16:44:48 +0800 Subject: [PATCH 3/6] Extract Windows version management into separate module --- src/common/platform/kernel_mapped.hpp | 4 +- src/windows-emulator/kusd_mmio.cpp | 18 ++- src/windows-emulator/kusd_mmio.hpp | 3 +- .../module/module_manager.cpp | 66 +-------- .../module/module_manager.hpp | 15 +- src/windows-emulator/process_context.cpp | 21 ++- src/windows-emulator/process_context.hpp | 73 +-------- .../version/windows_version_manager.cpp | 138 ++++++++++++++++++ .../version/windows_version_manager.hpp | 84 +++++++++++ src/windows-emulator/windows_emulator.cpp | 14 +- src/windows-emulator/windows_emulator.hpp | 2 + 11 files changed, 277 insertions(+), 161 deletions(-) create mode 100644 src/windows-emulator/version/windows_version_manager.cpp create mode 100644 src/windows-emulator/version/windows_version_manager.hpp diff --git a/src/common/platform/kernel_mapped.hpp b/src/common/platform/kernel_mapped.hpp index 27a8d4e7..4413e518 100644 --- a/src/common/platform/kernel_mapped.hpp +++ b/src/common/platform/kernel_mapped.hpp @@ -2003,7 +2003,7 @@ typedef enum class _SECTION_INFORMATION_CLASS SectionInternalImageInformation = 4 } SECTION_INFORMATION_CLASS, *PSECTION_INFORMATION_CLASS; -enum WINDOWS_VERSION : uint32_t +typedef enum _WINDOWS_VERSION : uint32_t { WINDOWS_10_1507 = 10240, WINDOWS_10_1511 = 10586, @@ -2023,7 +2023,7 @@ enum WINDOWS_VERSION : uint32_t WINDOWS_11_22H2 = 22621, WINDOWS_11_23H2 = 22631, WINDOWS_11_24H2 = 26100, -}; +} WINDOWS_VERSION, *PWINDOWS_VERSION; constexpr uint64_t PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V1 = sizeof(PS_SYSTEM_DLL_INIT_BLOCK_V1); constexpr uint64_t PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V2_1703 = offsetof(PS_SYSTEM_DLL_INIT_BLOCK_V2, MitigationAuditOptionsMap); diff --git a/src/windows-emulator/kusd_mmio.cpp b/src/windows-emulator/kusd_mmio.cpp index 8657ee04..b4ccd5d5 100644 --- a/src/windows-emulator/kusd_mmio.cpp +++ b/src/windows-emulator/kusd_mmio.cpp @@ -2,6 +2,7 @@ #include "kusd_mmio.hpp" #include #include "windows_emulator.hpp" +#include "version/windows_version_manager.hpp" #include @@ -11,7 +12,7 @@ constexpr auto KUSD_BUFFER_SIZE = page_align_up(KUSD_SIZE); namespace { - void setup_kusd(KUSER_SHARED_DATA64& kusd) + void setup_kusd(KUSER_SHARED_DATA64& kusd, const windows_version_manager& version) { memset(reinterpret_cast(&kusd), 0, sizeof(kusd)); @@ -29,11 +30,12 @@ namespace kusd.LargePageMinimum = 0x00200000; kusd.RNGSeedVersion = 0; kusd.TimeZoneBiasStamp = 0x00000004; - kusd.NtBuildNumber = 19045; + kusd.NtBuildNumber = version.get_windows_build_number(); kusd.NtProductType = NtProductWinNt; kusd.ProductTypeIsValid = 0x01; kusd.NativeProcessorArchitecture = 0x0009; - kusd.NtMajorVersion = 0x0000000a; + kusd.NtMajorVersion = version.get_major_version(); + kusd.NtMinorVersion = version.get_minor_version(); kusd.BootId = 0; kusd.SystemExpirationDate.QuadPart = 0; kusd.SuiteMask = 0; @@ -80,8 +82,10 @@ namespace kusd.ProcessorFeatures.arr[PF_RDTSCP_INSTRUCTION_AVAILABLE] = 1; kusd.ProcessorFeatures.arr[PF_RDPID_INSTRUCTION_AVAILABLE] = 0; - constexpr std::u16string_view root_dir{u"C:\\Windows"}; - memcpy(&kusd.NtSystemRoot.arr[0], root_dir.data(), root_dir.size() * 2); + const auto& system_root = version.get_system_root(); + const auto& root_str = system_root.u16string(); + const auto copy_size = std::min(root_str.size() * sizeof(char16_t), sizeof(kusd.NtSystemRoot.arr) - sizeof(char16_t)); + memcpy(&kusd.NtSystemRoot.arr[0], root_str.data(), copy_size); kusd.ImageNumberLow = IMAGE_FILE_MACHINE_AMD64; kusd.ImageNumberHigh = IMAGE_FILE_MACHINE_AMD64; @@ -118,9 +122,9 @@ kusd_mmio::kusd_mmio(utils::buffer_deserializer& buffer) { } -void kusd_mmio::setup() +void kusd_mmio::setup(const windows_version_manager& version) { - setup_kusd(this->kusd_); + setup_kusd(this->kusd_, version); this->register_mmio(); } diff --git a/src/windows-emulator/kusd_mmio.hpp b/src/windows-emulator/kusd_mmio.hpp index 449b534b..48b0fc63 100644 --- a/src/windows-emulator/kusd_mmio.hpp +++ b/src/windows-emulator/kusd_mmio.hpp @@ -9,6 +9,7 @@ struct process_context; class windows_emulator; +class windows_version_manager; class kusd_mmio { @@ -38,7 +39,7 @@ class kusd_mmio static uint64_t address(); - void setup(); + void setup(const windows_version_manager& version); private: memory_manager* memory_{}; diff --git a/src/windows-emulator/module/module_manager.cpp b/src/windows-emulator/module/module_manager.cpp index 7d7ac9d2..b3c251f8 100644 --- a/src/windows-emulator/module/module_manager.cpp +++ b/src/windows-emulator/module/module_manager.cpp @@ -4,7 +4,7 @@ #include "platform/win_pefile.hpp" #include "windows-emulator/logger.hpp" #include "../wow64_heaven_gate.hpp" -#include "../registry/registry_manager.hpp" +#include "../version/windows_version_manager.hpp" #include "../process_context.hpp" #include @@ -207,52 +207,6 @@ module_manager::module_manager(memory_manager& memory, file_system& file_sys, ca { } -void module_manager::get_system_information_from_registry(registry_manager& registry, system_information& info, const logger& logger) -{ - constexpr auto version_key_path = R"(\Registry\Machine\Software\Microsoft\Windows NT\CurrentVersion)"; - - const auto version_key = registry.get_key({version_key_path}); - if (!version_key) - { - throw std::runtime_error("Failed to get CurrentVersion registry key"); - } - - for (size_t i = 0; const auto value = registry.get_value(*version_key, i); ++i) - { - if (value->name == "SystemRoot" && value->type == REG_SZ && !value->data.empty()) - { - const auto* data_ptr = reinterpret_cast(value->data.data()); - const auto char_count = value->data.size() / sizeof(char16_t); - std::u16string system_root(data_ptr, char_count > 0 && data_ptr[char_count - 1] == u'\0' ? char_count - 1 : char_count); - info.system_root = windows_path{system_root}; - } - else if ((value->name == "CurrentBuildNumber" || value->name == "CurrentBuild") && value->type == REG_SZ) - { - const auto* s = reinterpret_cast(value->data.data()); - info.build_number = static_cast(std::strtoul(u16_to_u8(s).c_str(), nullptr, 10)); - } - else if (value->name == "UBR" && value->type == REG_DWORD && value->data.size() >= sizeof(uint32_t)) - { - info.update_build_revision = *reinterpret_cast(value->data.data()); - } - } - - if (info.system_root.u16string().empty()) - { - throw std::runtime_error("SystemRoot not found in registry"); - } - - if (info.build_number == 0) - { - logger.error("Failed to get CurrentBuildNumber from registry\n"); - } - - if (info.update_build_revision == 0) - { - logger.error("Failed to get UBR from registry\n"); - } -} - // Core mapping logic to eliminate code duplication mapped_module* module_manager::map_module_core(const pe_detection_result& detection_result, const std::function& mapper, const logger& logger, bool is_static) @@ -307,7 +261,7 @@ void module_manager::load_native_64bit_modules(const windows_path& executable_pa // WOW64 module loading void module_manager::load_wow64_modules(const windows_path& executable_path, const windows_path& ntdll_path, - const windows_path& win32u_path, const windows_path& ntdll32_path, process_context& context, + const windows_path& win32u_path, const windows_path& ntdll32_path, windows_version_manager& version, const logger& logger) { logger.info("Loading WOW64 modules for 32-bit application\n"); @@ -328,7 +282,7 @@ void module_manager::load_wow64_modules(const windows_path& executable_path, con } PS_SYSTEM_DLL_INIT_BLOCK init_block = {}; - const auto init_block_size = context.get_system_dll_init_block_size(); + const auto init_block_size = version.get_system_dll_init_block_size(); init_block.Size = static_cast(init_block_size); @@ -463,16 +417,12 @@ void module_manager::install_wow64_heaven_gate(const logger& logger) } } -void module_manager::map_main_modules(const windows_path& executable_path, registry_manager& registry, process_context& context, +void module_manager::map_main_modules(const windows_path& executable_path, windows_version_manager& version, process_context& context, const logger& logger) { - system_information sys_info{}; - module_manager::get_system_information_from_registry(registry, sys_info, logger); - const auto system32_path = sys_info.system_root / "System32"; - const auto syswow64_path = sys_info.system_root / "SysWOW64"; - - context.windows_build_number = sys_info.build_number; - context.windows_update_build_revision_number = sys_info.update_build_revision; + const auto& system_root = version.get_system_root(); + const auto system32_path = system_root / "System32"; + const auto syswow64_path = system_root / "SysWOW64"; current_execution_mode_ = detect_execution_mode(executable_path, logger); context.is_wow64_process = (current_execution_mode_ == execution_mode::wow64_32bit); @@ -484,7 +434,7 @@ void module_manager::map_main_modules(const windows_path& executable_path, regis break; case execution_mode::wow64_32bit: - load_wow64_modules(executable_path, system32_path / "ntdll.dll", system32_path / "win32u.dll", syswow64_path / "ntdll.dll", context, + load_wow64_modules(executable_path, system32_path / "ntdll.dll", system32_path / "win32u.dll", syswow64_path / "ntdll.dll", version, logger); break; diff --git a/src/windows-emulator/module/module_manager.hpp b/src/windows-emulator/module/module_manager.hpp index 402a0955..0cc9d475 100644 --- a/src/windows-emulator/module/module_manager.hpp +++ b/src/windows-emulator/module/module_manager.hpp @@ -8,6 +8,7 @@ class logger; class registry_manager; +class windows_version_manager; struct process_context; // Execution mode for the emulated process @@ -80,13 +81,6 @@ class pe_architecture_detector static execution_mode determine_execution_mode(winpe::pe_arch executable_arch); }; -struct system_information -{ - windows_path system_root{}; - uint32_t build_number{0}; - uint32_t update_build_revision{0}; -}; - class module_manager { public: @@ -100,7 +94,8 @@ class module_manager module_manager(memory_manager& memory, file_system& file_sys, callbacks& cb); - void map_main_modules(const windows_path& executable_path, registry_manager& registry, process_context& context, const logger& logger); + void map_main_modules(const windows_path& executable_path, windows_version_manager& version, process_context& context, + const logger& logger); mapped_module* map_module(const windows_path& file, const logger& logger, bool is_static = false); mapped_module* map_local_module(const std::filesystem::path& file, const logger& logger, bool is_static = false); @@ -194,13 +189,11 @@ class module_manager // Execution mode detection execution_mode detect_execution_mode(const windows_path& executable_path, const logger& logger); - static void get_system_information_from_registry(registry_manager& registry, system_information& info, const logger& logger); - // Module loading helpers void load_native_64bit_modules(const windows_path& executable_path, const windows_path& ntdll_path, const windows_path& win32u_path, const logger& logger); void load_wow64_modules(const windows_path& executable_path, const windows_path& ntdll_path, const windows_path& win32u_path, - const windows_path& ntdll32_path, process_context& context, const logger& logger); + const windows_path& ntdll32_path, windows_version_manager& version, const logger& logger); void install_wow64_heaven_gate(const logger& logger); diff --git a/src/windows-emulator/process_context.cpp b/src/windows-emulator/process_context.cpp index c3f5d641..35545df9 100644 --- a/src/windows-emulator/process_context.cpp +++ b/src/windows-emulator/process_context.cpp @@ -3,6 +3,7 @@ #include "emulator_utils.hpp" #include "windows_emulator.hpp" +#include "version/windows_version_manager.hpp" namespace { @@ -178,13 +179,13 @@ namespace } } -void process_context::setup(x86_64_emulator& emu, memory_manager& memory, registry_manager& registry, +void process_context::setup(x86_64_emulator& emu, memory_manager& memory, registry_manager& registry, windows_version_manager& version, const application_settings& app_settings, const mapped_module& executable, const mapped_module& ntdll, const apiset::container& apiset_container, const mapped_module* ntdll32) { setup_gdt(emu, memory); - this->kusd.setup(); + this->kusd.setup(version); this->base_allocator = create_allocator(memory, PEB_SEGMENT_SIZE, this->is_wow64_process); auto& allocator = this->base_allocator; @@ -276,8 +277,9 @@ void process_context::setup(x86_64_emulator& emu, memory_manager& memory, regist p.ImageSubsystemMajorVersion = 6; p.OSPlatformId = 2; - p.OSMajorVersion = 0x0000000a; - p.OSBuildNumber = 0x00006c51; + p.OSMajorVersion = version.get_major_version(); + p.OSMinorVersion = version.get_minor_version(); + p.OSBuildNumber = static_cast(version.get_windows_build_number()); // p.AnsiCodePageData = allocator.reserve().value(); // p.OemCodePageData = allocator.reserve().value(); @@ -367,8 +369,9 @@ void process_context::setup(x86_64_emulator& emu, memory_manager& memory, regist p32.ImageSubsystemMajorVersion = 6; p32.OSPlatformId = 2; - p32.OSMajorVersion = 0x0a; - p32.OSBuildNumber = 0x6c51; + p32.OSMajorVersion = version.get_major_version(); + p32.OSMinorVersion = version.get_minor_version(); + p32.OSBuildNumber = static_cast(version.get_windows_build_number()); // Initialize NLS tables for 32-bit processes // These need to be in 32-bit addressable space @@ -400,7 +403,7 @@ void process_context::setup(x86_64_emulator& emu, memory_manager& memory, regist monitor.hmon = h.bits; monitor.rcMonitor = {.left = 0, .top = 0, .right = 1920, .bottom = 1080}; monitor.rcWork = monitor.rcMonitor; - if (this->is_build_before(26040)) + if (version.is_build_before(26040)) { monitor.b20.monitorDpi = 96; monitor.b20.nativeDpi = monitor.b20.monitorDpi; @@ -436,8 +439,6 @@ void process_context::serialize(utils::buffer_serializer& buffer) const buffer.write(this->kusd); buffer.write(this->is_wow64_process); - buffer.write(this->windows_build_number); - buffer.write(this->windows_update_build_revision_number); buffer.write(this->ntdll_image_base); buffer.write(this->ldr_initialize_thunk); buffer.write(this->rtl_user_thread_start); @@ -486,8 +487,6 @@ void process_context::deserialize(utils::buffer_deserializer& buffer) buffer.read(this->kusd); buffer.read(this->is_wow64_process); - buffer.read(this->windows_build_number); - buffer.read(this->windows_update_build_revision_number); buffer.read(this->ntdll_image_base); buffer.read(this->ldr_initialize_thunk); buffer.read(this->rtl_user_thread_start); diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index b5d5f850..a5283cdc 100644 --- a/src/windows-emulator/process_context.hpp +++ b/src/windows-emulator/process_context.hpp @@ -33,6 +33,7 @@ struct emulator_settings; struct application_settings; +class windows_version_manager; struct process_context { @@ -72,9 +73,9 @@ struct process_context { } - void setup(x86_64_emulator& emu, memory_manager& memory, registry_manager& registry, const application_settings& app_settings, - const mapped_module& executable, const mapped_module& ntdll, const apiset::container& apiset_container, - const mapped_module* ntdll32 = nullptr); + void setup(x86_64_emulator& emu, memory_manager& memory, registry_manager& registry, windows_version_manager& version, + const application_settings& app_settings, const mapped_module& executable, const mapped_module& ntdll, + const apiset::container& apiset_container, const mapped_module* ntdll32 = nullptr); handle create_thread(memory_manager& memory, uint64_t start_address, uint64_t argument, uint64_t stack_size, uint32_t create_flags, bool initial_thread = false); @@ -93,72 +94,6 @@ struct process_context // WOW64 support flag - set during process setup based on executable architecture bool is_wow64_process{false}; - uint32_t windows_build_number{0}; - uint32_t windows_update_build_revision_number{0}; - - bool is_build_before(uint32_t build, std::optional ubr = std::nullopt) const - { - if (windows_build_number != build) - { - return windows_build_number < build; - } - return ubr.has_value() && windows_update_build_revision_number < *ubr; - } - - bool is_build_before_or_equal(uint32_t build, std::optional ubr = std::nullopt) const - { - if (windows_build_number != build) - { - return windows_build_number < build; - } - return !ubr.has_value() || windows_update_build_revision_number <= *ubr; - } - - bool is_build_after_or_equal(uint32_t build, std::optional ubr = std::nullopt) const - { - if (windows_build_number != build) - { - return windows_build_number > build; - } - return !ubr.has_value() || windows_update_build_revision_number >= *ubr; - } - - bool is_build_after(uint32_t build, std::optional ubr = std::nullopt) const - { - if (windows_build_number != build) - { - return windows_build_number > build; - } - return ubr.has_value() && windows_update_build_revision_number > *ubr; - } - - bool is_build_within(uint32_t start_build, uint32_t end_build, std::optional start_ubr = std::nullopt, - std::optional end_ubr = std::nullopt) const - { - return is_build_after_or_equal(start_build, start_ubr) && is_build_before(end_build, end_ubr); - } - - uint64_t get_system_dll_init_block_size() const - { - if (is_build_after_or_equal(WINDOWS_VERSION::WINDOWS_11_24H2)) - { - return PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V3; - } - if (is_build_after_or_equal(WINDOWS_VERSION::WINDOWS_10_2004)) - { - return PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V3_2004; - } - if (is_build_after_or_equal(WINDOWS_VERSION::WINDOWS_10_1709)) - { - return PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V2; - } - if (is_build_after_or_equal(WINDOWS_VERSION::WINDOWS_10_1703)) - { - return PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V2_1703; - } - return PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V1; - } - callbacks* callbacks_{}; uint64_t shared_section_address{0}; diff --git a/src/windows-emulator/version/windows_version_manager.cpp b/src/windows-emulator/version/windows_version_manager.cpp new file mode 100644 index 00000000..928366f9 --- /dev/null +++ b/src/windows-emulator/version/windows_version_manager.cpp @@ -0,0 +1,138 @@ +#include "../std_include.hpp" +#include "windows_version_manager.hpp" +#include "../registry/registry_manager.hpp" +#include "../logger.hpp" +#include + +void windows_version_manager::load_from_registry(registry_manager& registry, const logger& logger) +{ + constexpr auto version_key_path = R"(\Registry\Machine\Software\Microsoft\Windows NT\CurrentVersion)"; + + const auto version_key = registry.get_key({version_key_path}); + if (!version_key) + { + throw std::runtime_error("Failed to get CurrentVersion registry key"); + } + + for (size_t i = 0; const auto value = registry.get_value(*version_key, i); ++i) + { + if (value->name == "SystemRoot" && value->type == REG_SZ && !value->data.empty()) + { + const auto* data_ptr = reinterpret_cast(value->data.data()); + const auto char_count = value->data.size() / sizeof(char16_t); + std::u16string system_root(data_ptr, char_count > 0 && data_ptr[char_count - 1] == u'\0' ? char_count - 1 : char_count); + info_.system_root = windows_path{system_root}; + } + else if ((value->name == "CurrentBuildNumber" || value->name == "CurrentBuild") && value->type == REG_SZ) + { + const auto* s = reinterpret_cast(value->data.data()); + info_.windows_build_number = static_cast(std::strtoul(u16_to_u8(s).c_str(), nullptr, 10)); + } + else if (value->name == "UBR" && value->type == REG_DWORD && value->data.size() >= sizeof(uint32_t)) + { + info_.windows_update_build_revision = *reinterpret_cast(value->data.data()); + } + else if (value->name == "CurrentMajorVersionNumber" && value->type == REG_DWORD && value->data.size() >= sizeof(uint32_t)) + { + info_.major_version = *reinterpret_cast(value->data.data()); + } + else if (value->name == "CurrentMinorVersionNumber" && value->type == REG_DWORD && value->data.size() >= sizeof(uint32_t)) + { + info_.minor_version = *reinterpret_cast(value->data.data()); + } + } + + if (info_.system_root.u16string().empty()) + { + throw std::runtime_error("SystemRoot not found in registry"); + } + + if (info_.windows_build_number == 0) + { + logger.error("Failed to get CurrentBuildNumber from registry\n"); + } + + if (info_.windows_update_build_revision == 0) + { + logger.error("Failed to get UBR from registry\n"); + } +} + +bool windows_version_manager::is_build_before(uint32_t build, std::optional ubr) const +{ + if (info_.windows_build_number != build) + { + return info_.windows_build_number < build; + } + return ubr.has_value() && info_.windows_update_build_revision < *ubr; +} + +bool windows_version_manager::is_build_before_or_equal(uint32_t build, std::optional ubr) const +{ + if (info_.windows_build_number != build) + { + return info_.windows_build_number < build; + } + return !ubr.has_value() || info_.windows_update_build_revision <= *ubr; +} + +bool windows_version_manager::is_build_after_or_equal(uint32_t build, std::optional ubr) const +{ + if (info_.windows_build_number != build) + { + return info_.windows_build_number > build; + } + return !ubr.has_value() || info_.windows_update_build_revision >= *ubr; +} + +bool windows_version_manager::is_build_after(uint32_t build, std::optional ubr) const +{ + if (info_.windows_build_number != build) + { + return info_.windows_build_number > build; + } + return ubr.has_value() && info_.windows_update_build_revision > *ubr; +} + +bool windows_version_manager::is_build_within(uint32_t start_build, uint32_t end_build, std::optional start_ubr, + std::optional end_ubr) const +{ + return is_build_after_or_equal(start_build, start_ubr) && is_build_before(end_build, end_ubr); +} + +uint64_t windows_version_manager::get_system_dll_init_block_size() const +{ + if (is_build_after_or_equal(WINDOWS_VERSION::WINDOWS_11_24H2)) + { + return PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V3; + } + if (is_build_after_or_equal(WINDOWS_VERSION::WINDOWS_10_2004)) + { + return PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V3_2004; + } + if (is_build_after_or_equal(WINDOWS_VERSION::WINDOWS_10_1709)) + { + return PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V2; + } + if (is_build_after_or_equal(WINDOWS_VERSION::WINDOWS_10_1703)) + { + return PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V2_1703; + } + return PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V1; +} + +void windows_version_manager::serialize(utils::buffer_serializer& buffer) const +{ + buffer.write(info_.major_version); + buffer.write(info_.minor_version); + buffer.write(info_.windows_build_number); + buffer.write(info_.windows_update_build_revision); +} + +void windows_version_manager::deserialize(utils::buffer_deserializer& buffer) +{ + buffer.read(info_.major_version); + buffer.read(info_.minor_version); + buffer.read(info_.windows_build_number); + buffer.read(info_.windows_update_build_revision); +} diff --git a/src/windows-emulator/version/windows_version_manager.hpp b/src/windows-emulator/version/windows_version_manager.hpp new file mode 100644 index 00000000..18f65bc3 --- /dev/null +++ b/src/windows-emulator/version/windows_version_manager.hpp @@ -0,0 +1,84 @@ +#pragma once + +#include "../windows_path.hpp" +#include +#include +#include + +class logger; +class registry_manager; + +struct windows_version_info +{ + windows_path system_root{}; + uint32_t major_version{0}; + uint32_t minor_version{0}; + uint32_t windows_build_number{0}; + uint32_t windows_update_build_revision{0}; +}; + +class windows_version_manager +{ + public: + void load_from_registry(registry_manager& registry, const logger& logger); + + bool is_build_before(uint32_t build, std::optional ubr = std::nullopt) const; + bool is_build_before_or_equal(uint32_t build, std::optional ubr = std::nullopt) const; + bool is_build_after_or_equal(uint32_t build, std::optional ubr = std::nullopt) const; + bool is_build_after(uint32_t build, std::optional ubr = std::nullopt) const; + bool is_build_within(uint32_t start_build, uint32_t end_build, std::optional start_ubr = std::nullopt, + std::optional end_ubr = std::nullopt) const; + + uint64_t get_system_dll_init_block_size() const; + + void serialize(utils::buffer_serializer& buffer) const; + void deserialize(utils::buffer_deserializer& buffer); + + const windows_path& get_system_root() const + { + return info_.system_root; + } + void set_system_root(const windows_path& value) + { + info_.system_root = value; + } + + uint32_t get_major_version() const + { + return info_.major_version; + } + void set_major_version(uint32_t value) + { + info_.major_version = value; + } + + uint32_t get_minor_version() const + { + return info_.minor_version; + } + void set_minor_version(uint32_t value) + { + info_.minor_version = value; + } + + uint32_t get_windows_build_number() const + { + return info_.windows_build_number; + } + void set_windows_build_number(uint32_t value) + { + info_.windows_build_number = value; + } + + uint32_t get_windows_update_build_revision() const + { + return info_.windows_update_build_revision; + } + void set_windows_update_build_revision(uint32_t value) + { + info_.windows_update_build_revision = value; + } + + private: + windows_version_info info_{}; +}; diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index 2fc214e2..a65c2230 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -351,7 +351,9 @@ void windows_emulator::setup_process(const application_settings& app_settings) const auto& emu = this->emu(); auto& context = this->process; - this->mod_manager.map_main_modules(app_settings.application, this->registry, context, this->log); + this->version.load_from_registry(this->registry, this->log); + + this->mod_manager.map_main_modules(app_settings.application, this->version, context, this->log); const auto* executable = this->mod_manager.executable; const auto* ntdll = this->mod_manager.ntdll; @@ -359,7 +361,7 @@ void windows_emulator::setup_process(const application_settings& app_settings) const auto apiset_data = apiset::obtain(this->emulation_root); - this->process.setup(this->emu(), this->memory, this->registry, app_settings, *executable, *ntdll, apiset_data, + this->process.setup(this->emu(), this->memory, this->registry, this->version, app_settings, *executable, *ntdll, apiset_data, this->mod_manager.wow64_modules_.ntdll32); const auto ntdll_data = emu.read_memory(ntdll->image_base, static_cast(ntdll->size_of_image)); @@ -627,6 +629,8 @@ void windows_emulator::serialize(utils::buffer_serializer& buffer) const buffer.write(this->switch_thread_); buffer.write(this->use_relative_time_); + this->version.serialize(buffer); + this->emu().serialize_state(buffer, false); this->memory.serialize_memory_state(buffer, false); this->mod_manager.serialize(buffer); @@ -650,6 +654,8 @@ void windows_emulator::deserialize(utils::buffer_deserializer& buffer) throw std::runtime_error("Can not deserialize emulator with different time dimensions"); } + this->version.deserialize(buffer); + this->memory.unmap_all_memory(); this->emu().deserialize_state(buffer, false); @@ -667,6 +673,8 @@ void windows_emulator::save_snapshot() buffer.write(this->executed_instructions_); buffer.write(this->switch_thread_); + this->version.serialize(buffer); + this->emu().serialize_state(buffer, true); this->memory.serialize_memory_state(buffer, true); this->mod_manager.serialize(buffer); @@ -694,6 +702,8 @@ void windows_emulator::restore_snapshot() buffer.read(this->executed_instructions_); buffer.read(this->switch_thread_); + this->version.deserialize(buffer); + this->emu().deserialize_state(buffer, true); this->memory.deserialize_memory_state(buffer, true); this->mod_manager.deserialize(buffer); diff --git a/src/windows-emulator/windows_emulator.hpp b/src/windows-emulator/windows_emulator.hpp index 86e2a0e2..4ba30bda 100644 --- a/src/windows-emulator/windows_emulator.hpp +++ b/src/windows-emulator/windows_emulator.hpp @@ -12,6 +12,7 @@ #include "memory_manager.hpp" #include "module/module_manager.hpp" #include "network/socket_factory.hpp" +#include "version/windows_version_manager.hpp" struct io_device; @@ -94,6 +95,7 @@ class windows_emulator file_system file_sys; memory_manager memory; registry_manager registry{}; + windows_version_manager version{}; module_manager mod_manager; process_context process; syscall_dispatcher dispatcher; From 289306752e8b69af9dd23432465896b866e4c9ff Mon Sep 17 00:00:00 2001 From: brian Date: Mon, 12 Jan 2026 10:34:32 +0800 Subject: [PATCH 4/6] Move get_system_dll_init_block_size to module_manager as free function --- .../module/module_manager.cpp | 26 ++++++++++++++++++- .../version/windows_version_manager.cpp | 21 --------------- .../version/windows_version_manager.hpp | 2 -- 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/windows-emulator/module/module_manager.cpp b/src/windows-emulator/module/module_manager.cpp index b3c251f8..6bfcb15e 100644 --- a/src/windows-emulator/module/module_manager.cpp +++ b/src/windows-emulator/module/module_manager.cpp @@ -13,6 +13,30 @@ #include #include +namespace +{ + uint64_t get_system_dll_init_block_size(const windows_version_manager& version) + { + if (version.is_build_after_or_equal(WINDOWS_VERSION::WINDOWS_11_24H2)) + { + return PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V3; + } + if (version.is_build_after_or_equal(WINDOWS_VERSION::WINDOWS_10_2004)) + { + return PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V3_2004; + } + if (version.is_build_after_or_equal(WINDOWS_VERSION::WINDOWS_10_1709)) + { + return PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V2; + } + if (version.is_build_after_or_equal(WINDOWS_VERSION::WINDOWS_10_1703)) + { + return PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V2_1703; + } + return PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V1; + } +} + namespace utils { static void serialize(buffer_serializer& buffer, const exported_symbol& sym) @@ -282,7 +306,7 @@ void module_manager::load_wow64_modules(const windows_path& executable_path, con } PS_SYSTEM_DLL_INIT_BLOCK init_block = {}; - const auto init_block_size = version.get_system_dll_init_block_size(); + const auto init_block_size = get_system_dll_init_block_size(version); init_block.Size = static_cast(init_block_size); diff --git a/src/windows-emulator/version/windows_version_manager.cpp b/src/windows-emulator/version/windows_version_manager.cpp index 928366f9..cc1c93f8 100644 --- a/src/windows-emulator/version/windows_version_manager.cpp +++ b/src/windows-emulator/version/windows_version_manager.cpp @@ -100,27 +100,6 @@ bool windows_version_manager::is_build_within(uint32_t start_build, uint32_t end return is_build_after_or_equal(start_build, start_ubr) && is_build_before(end_build, end_ubr); } -uint64_t windows_version_manager::get_system_dll_init_block_size() const -{ - if (is_build_after_or_equal(WINDOWS_VERSION::WINDOWS_11_24H2)) - { - return PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V3; - } - if (is_build_after_or_equal(WINDOWS_VERSION::WINDOWS_10_2004)) - { - return PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V3_2004; - } - if (is_build_after_or_equal(WINDOWS_VERSION::WINDOWS_10_1709)) - { - return PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V2; - } - if (is_build_after_or_equal(WINDOWS_VERSION::WINDOWS_10_1703)) - { - return PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V2_1703; - } - return PS_SYSTEM_DLL_INIT_BLOCK_SIZE_V1; -} - void windows_version_manager::serialize(utils::buffer_serializer& buffer) const { buffer.write(info_.major_version); diff --git a/src/windows-emulator/version/windows_version_manager.hpp b/src/windows-emulator/version/windows_version_manager.hpp index 18f65bc3..9f2c6c5d 100644 --- a/src/windows-emulator/version/windows_version_manager.hpp +++ b/src/windows-emulator/version/windows_version_manager.hpp @@ -29,8 +29,6 @@ class windows_version_manager bool is_build_within(uint32_t start_build, uint32_t end_build, std::optional start_ubr = std::nullopt, std::optional end_ubr = std::nullopt) const; - uint64_t get_system_dll_init_block_size() const; - void serialize(utils::buffer_serializer& buffer) const; void deserialize(utils::buffer_deserializer& buffer); From f704be21878c63ccc0cb0191dce1fa296c1e33b0 Mon Sep 17 00:00:00 2001 From: brian Date: Mon, 12 Jan 2026 16:45:15 +0800 Subject: [PATCH 5/6] Fix memory commit allowed on section kind regions --- src/windows-emulator/memory_manager.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/windows-emulator/memory_manager.cpp b/src/windows-emulator/memory_manager.cpp index 16dfaf74..a8cacf3f 100644 --- a/src/windows-emulator/memory_manager.cpp +++ b/src/windows-emulator/memory_manager.cpp @@ -307,6 +307,11 @@ bool memory_manager::commit_memory(const uint64_t address, const size_t size, co return false; } + if (memory_region_policy::is_section_kind(entry->second.kind)) + { + return false; + } + const auto end = address + size; const auto region_end = entry->first + entry->second.length; From 708526c68cbed7b20cc9b0e8a384307944491da5 Mon Sep 17 00:00:00 2001 From: brian Date: Wed, 14 Jan 2026 01:12:49 +0800 Subject: [PATCH 6/6] Add basic_string_view overload for utils::string::copy --- src/common/utils/string.hpp | 15 +++++++++++++++ src/windows-emulator/kusd_mmio.cpp | 5 ++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/common/utils/string.hpp b/src/common/utils/string.hpp index a732217d..c887de7f 100644 --- a/src/common/utils/string.hpp +++ b/src/common/utils/string.hpp @@ -30,6 +30,21 @@ namespace utils::string array[std::min(Size - 1, size)] = {}; } + template > + requires(std::is_trivially_copyable_v) + // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) + void copy(T (&array)[Size], const std::basic_string_view str) + { + if constexpr (Size == 0) + { + return; + } + + const auto size = std::min(Size - 1, str.size()); + memcpy(array, str.data(), size * sizeof(T)); + array[size] = {}; + } + inline char char_to_lower(const char val) { return static_cast(std::tolower(static_cast(val))); diff --git a/src/windows-emulator/kusd_mmio.cpp b/src/windows-emulator/kusd_mmio.cpp index b4ccd5d5..076ce0d9 100644 --- a/src/windows-emulator/kusd_mmio.cpp +++ b/src/windows-emulator/kusd_mmio.cpp @@ -1,6 +1,7 @@ #include "std_include.hpp" #include "kusd_mmio.hpp" #include +#include #include "windows_emulator.hpp" #include "version/windows_version_manager.hpp" @@ -83,9 +84,7 @@ namespace kusd.ProcessorFeatures.arr[PF_RDPID_INSTRUCTION_AVAILABLE] = 0; const auto& system_root = version.get_system_root(); - const auto& root_str = system_root.u16string(); - const auto copy_size = std::min(root_str.size() * sizeof(char16_t), sizeof(kusd.NtSystemRoot.arr) - sizeof(char16_t)); - memcpy(&kusd.NtSystemRoot.arr[0], root_str.data(), copy_size); + utils::string::copy(kusd.NtSystemRoot.arr, std::u16string_view{system_root.u16string()}); kusd.ImageNumberLow = IMAGE_FILE_MACHINE_AMD64; kusd.ImageNumberHigh = IMAGE_FILE_MACHINE_AMD64;