From 3686625fb1c92a2c5bd7d56acfa3a2fb173ba21a Mon Sep 17 00:00:00 2001 From: ssvine <79405160+ssvine@users.noreply.github.com> Date: Thu, 25 Dec 2025 13:40:16 +0300 Subject: [PATCH] Fix PEB32 --- src/windows-emulator/emulator_utils.hpp | 40 ++----- src/windows-emulator/process_context.cpp | 132 +++++++++-------------- src/windows-emulator/process_context.hpp | 19 ++-- 3 files changed, 65 insertions(+), 126 deletions(-) diff --git a/src/windows-emulator/emulator_utils.hpp b/src/windows-emulator/emulator_utils.hpp index 549ea72a..f8737ff6 100644 --- a/src/windows-emulator/emulator_utils.hpp +++ b/src/windows-emulator/emulator_utils.hpp @@ -245,7 +245,8 @@ class emulator_allocator return uc_str.Buffer; } - void make_unicode_string(UNICODE_STRING>& result, const std::u16string_view str, + template + void make_unicode_string(UNICODE_STRING>& result, const std::u16string_view str, const std::optional maximum_length = std::nullopt) { constexpr auto element_size = sizeof(str[0]); @@ -262,13 +263,14 @@ class emulator_allocator constexpr std::array nullbyte{}; this->memory_->write_memory(string_buffer + total_length, nullbyte.data(), nullbyte.size()); - result.Buffer = string_buffer; + result.Buffer = static_cast::PVOID>(string_buffer); result.Length = static_cast(total_length); result.MaximumLength = static_cast(max_length); } - emulator_object>> make_unicode_string(const std::u16string_view str, - const std::optional maximum_length = std::nullopt) + template + emulator_object>> make_unicode_string(const std::u16string_view str, + const std::optional maximum_length = std::nullopt) { const auto unicode_string = this->reserve>>(); @@ -393,36 +395,6 @@ inline std::u16string read_unicode_string(emulator& emu, const uint64_t uc_strin return read_unicode_string(emu, emulator_object>>{emu, uc_string}); } -inline void copy_unicode_string_64_to_32(memory_interface& memory, UNICODE_STRING>& dest32, - const UNICODE_STRING>& src64, const uint64_t dest_base_address, - uint32_t& offset, const uint32_t max_size) -{ - dest32.Length = static_cast(src64.Length); - dest32.MaximumLength = static_cast(src64.MaximumLength); - - if (!src64.Buffer || src64.Length == 0) - { - dest32.Buffer = 0; - return; - } - - offset = static_cast(align_up(offset, 2)); - - if (offset + src64.Length > max_size) - { - dest32.Buffer = 0; - return; - } - - dest32.Buffer = static_cast(dest_base_address + offset); - - std::vector string_data(src64.Length); - memory.read_memory(src64.Buffer, string_data.data(), src64.Length); - memory.write_memory(dest_base_address + offset, string_data.data(), src64.Length); - - offset += src64.MaximumLength; -} - inline uint64_t get_function_argument(x86_64_emulator& emu, const size_t index, const bool is_syscall = false) { bool use_32bit_stack = false; diff --git a/src/windows-emulator/process_context.cpp b/src/windows-emulator/process_context.cpp index 7863ea06..c48c155c 100644 --- a/src/windows-emulator/process_context.cpp +++ b/src/windows-emulator/process_context.cpp @@ -191,12 +191,6 @@ void process_context::setup(x86_64_emulator& emu, memory_manager& memory, regist this->peb64 = allocator.reserve_page_aligned(); - // Create PEB32 for WOW64 processes - if (this->is_wow64_process) - { - this->peb32 = allocator.reserve_page_aligned(); - } - /* Values of the following fields must be * allocated relative to the process_params themselves * and included in the length: @@ -290,96 +284,72 @@ void process_context::setup(x86_64_emulator& emu, memory_manager& memory, regist p.UnicodeCaseTableData = allocator.reserve().value(); }); - if (this->is_wow64_process && this->peb32.has_value()) + if (this->is_wow64_process) { - // peb32->ProcessParameters : 0x30000 - if (!memory.allocate_memory(WOW64_PEB32_PROCESS_PARA_BASE, WOW64_PEB32_PROCESS_PARA_SIZE, memory_permission::read_write)) - { - throw std::runtime_error("Failed to allocate 32-bit process parameters at 0x30000"); - } + this->peb32 = allocator.reserve_page_aligned(); // Initialize RTL_USER_PROCESS_PARAMETERS32 structure - RTL_USER_PROCESS_PARAMETERS32 params32{}; - params32.MaximumLength = sizeof(RTL_USER_PROCESS_PARAMETERS32); - params32.Length = sizeof(RTL_USER_PROCESS_PARAMETERS32); - params32.Flags = RTL_USER_PROCESS_PARAMETERS_IMAGE_KEY_MISSING | RTL_USER_PROCESS_PARAMETERS_APP_MANIFEST_PRESENT | - RTL_USER_PROCESS_PARAMETERS_NORMALIZED; + this->process_params32 = allocator.reserve(); - params32.ConsoleHandle = static_cast(CONSOLE_HANDLE.h); - params32.StandardOutput = static_cast(STDOUT_HANDLE.h); - params32.StandardInput = static_cast(STDIN_HANDLE.h); - params32.StandardError = params32.StandardOutput; + this->process_params32->access([&](RTL_USER_PROCESS_PARAMETERS32& params32) { + params32.Flags = RTL_USER_PROCESS_PARAMETERS_IMAGE_KEY_MISSING | RTL_USER_PROCESS_PARAMETERS_APP_MANIFEST_PRESENT | + RTL_USER_PROCESS_PARAMETERS_NORMALIZED; - this->process_params64.access([&](const RTL_USER_PROCESS_PARAMETERS64& params64) { - uint32_t string_offset = sizeof(RTL_USER_PROCESS_PARAMETERS32); + params32.ConsoleHandle = static_cast(CONSOLE_HANDLE.h); + params32.StandardOutput = static_cast(STDOUT_HANDLE.h); + params32.StandardInput = static_cast(STDIN_HANDLE.h); + params32.StandardError = params32.StandardOutput; - copy_unicode_string_64_to_32(memory, params32.ImagePathName, params64.ImagePathName, WOW64_PEB32_PROCESS_PARA_BASE, - string_offset, WOW64_PEB32_PROCESS_PARA_SIZE); - copy_unicode_string_64_to_32(memory, params32.CommandLine, params64.CommandLine, WOW64_PEB32_PROCESS_PARA_BASE, string_offset, - WOW64_PEB32_PROCESS_PARA_SIZE); - copy_unicode_string_64_to_32(memory, params32.DllPath, params64.DllPath, WOW64_PEB32_PROCESS_PARA_BASE, string_offset, - WOW64_PEB32_PROCESS_PARA_SIZE); - copy_unicode_string_64_to_32(memory, params32.CurrentDirectory.DosPath, params64.CurrentDirectory.DosPath, - WOW64_PEB32_PROCESS_PARA_BASE, string_offset, WOW64_PEB32_PROCESS_PARA_SIZE); - copy_unicode_string_64_to_32(memory, params32.WindowTitle, params64.WindowTitle, WOW64_PEB32_PROCESS_PARA_BASE, string_offset, - WOW64_PEB32_PROCESS_PARA_SIZE); - copy_unicode_string_64_to_32(memory, params32.DesktopInfo, params64.DesktopInfo, WOW64_PEB32_PROCESS_PARA_BASE, string_offset, - WOW64_PEB32_PROCESS_PARA_SIZE); - copy_unicode_string_64_to_32(memory, params32.ShellInfo, params64.ShellInfo, WOW64_PEB32_PROCESS_PARA_BASE, string_offset, - WOW64_PEB32_PROCESS_PARA_SIZE); - copy_unicode_string_64_to_32(memory, params32.RuntimeData, params64.RuntimeData, WOW64_PEB32_PROCESS_PARA_BASE, string_offset, - WOW64_PEB32_PROCESS_PARA_SIZE); + this->process_params64.access([&](const RTL_USER_PROCESS_PARAMETERS64& params64) { + // Copy strings from params64 + allocator.make_unicode_string(params32.ImagePathName, read_unicode_string(emu, params64.ImagePathName)); + allocator.make_unicode_string(params32.CommandLine, read_unicode_string(emu, params64.CommandLine)); + allocator.make_unicode_string(params32.DllPath, read_unicode_string(emu, params64.DllPath)); + allocator.make_unicode_string(params32.CurrentDirectory.DosPath, + read_unicode_string(emu, params64.CurrentDirectory.DosPath)); + allocator.make_unicode_string(params32.WindowTitle, read_unicode_string(emu, params64.WindowTitle)); + allocator.make_unicode_string(params32.DesktopInfo, read_unicode_string(emu, params64.DesktopInfo)); + allocator.make_unicode_string(params32.ShellInfo, read_unicode_string(emu, params64.ShellInfo)); + allocator.make_unicode_string(params32.RuntimeData, read_unicode_string(emu, params64.RuntimeData)); + allocator.make_unicode_string(params32.RedirectionDllName, read_unicode_string(emu, params64.RedirectionDllName)); - // RedirectionDllName - Initialize to empty but valid string - params32.RedirectionDllName.Length = 0; - params32.RedirectionDllName.MaximumLength = 2; - // Align offset - string_offset = (string_offset + 1) & ~1; - if (string_offset + 2 <= WOW64_PEB32_PROCESS_PARA_SIZE) - { - params32.RedirectionDllName.Buffer = static_cast(WOW64_PEB32_PROCESS_PARA_BASE + string_offset); - uint16_t null_terminator = 0; - memory.write_memory(WOW64_PEB32_PROCESS_PARA_BASE + string_offset, &null_terminator, sizeof(null_terminator)); - } - else - { - params32.RedirectionDllName.Buffer = 0; - } + // Copy other fields + params32.CurrentDirectory.Handle = static_cast(params64.CurrentDirectory.Handle); + params32.ShowWindowFlags = params64.ShowWindowFlags; + params32.ConsoleHandle = static_cast(params64.ConsoleHandle); + params32.ConsoleFlags = params64.ConsoleFlags; + params32.StandardInput = static_cast(params64.StandardInput); + params32.StandardOutput = static_cast(params64.StandardOutput); + params32.StandardError = static_cast(params64.StandardError); + params32.StartingX = params64.StartingX; + params32.StartingY = params64.StartingY; + params32.CountX = params64.CountX; + params32.CountY = params64.CountY; + params32.CountCharsX = params64.CountCharsX; + params32.CountCharsY = params64.CountCharsY; + params32.FillAttribute = params64.FillAttribute; + params32.WindowFlags = params64.WindowFlags; + params32.DebugFlags = params64.DebugFlags; + params32.ProcessGroupId = params64.ProcessGroupId; + params32.LoaderThreads = params64.LoaderThreads; - // Copy other fields - params32.CurrentDirectory.Handle = static_cast(params64.CurrentDirectory.Handle); - params32.ShowWindowFlags = params64.ShowWindowFlags; - params32.ConsoleHandle = static_cast(params64.ConsoleHandle); - params32.ConsoleFlags = params64.ConsoleFlags; - params32.StandardInput = static_cast(params64.StandardInput); - params32.StandardOutput = static_cast(params64.StandardOutput); - params32.StandardError = static_cast(params64.StandardError); - params32.StartingX = params64.StartingX; - params32.StartingY = params64.StartingY; - params32.CountX = params64.CountX; - params32.CountY = params64.CountY; - params32.CountCharsX = params64.CountCharsX; - params32.CountCharsY = params64.CountCharsY; - params32.FillAttribute = params64.FillAttribute; - params32.WindowFlags = params64.WindowFlags; - params32.DebugFlags = params64.DebugFlags; - params32.ProcessGroupId = params64.ProcessGroupId; - params32.LoaderThreads = params64.LoaderThreads; + // Environment - copy the pointer value (both processes share the same environment) + params32.Environment = static_cast(params64.Environment); + params32.EnvironmentSize = static_cast(params64.EnvironmentSize); + params32.EnvironmentVersion = static_cast(params64.EnvironmentVersion); - // Environment - copy the pointer value (both processes share the same environment) - params32.Environment = static_cast(params64.Environment); - params32.EnvironmentSize = static_cast(params64.EnvironmentSize); - params32.EnvironmentVersion = static_cast(params64.EnvironmentVersion); + const auto total_length = allocator.get_next_address() - this->process_params32->value(); + + params32.Length = static_cast(std::max(static_cast(sizeof(params32)), total_length)); + params32.MaximumLength = params32.Length; + }); }); - // Write the RTL_USER_PROCESS_PARAMETERS32 structure to the allocated memory - memory.write_memory(WOW64_PEB32_PROCESS_PARA_BASE, ¶ms32, sizeof(params32)); - // Update PEB32 to point to the ProcessParameters32 this->peb32->access([&](PEB32& p32) { p32.BeingDebugged = 0; p32.ImageBaseAddress = static_cast(executable.image_base); - p32.ProcessParameters = WOW64_PEB32_PROCESS_PARA_BASE; // Fixed address on 0x30000 + p32.ProcessParameters = static_cast(this->process_params32->value()); // Use the dedicated 32-bit ApiSetMap for PEB32 p32.ApiSetMap = static_cast(apiset_map_address_32); diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index 9f420340..634fe3c4 100644 --- a/src/windows-emulator/process_context.hpp +++ b/src/windows-emulator/process_context.hpp @@ -17,21 +17,18 @@ #include "apiset/apiset.hpp" -#define PEB_SEGMENT_SIZE (20 << 20) // 20 MB -#define GS_SEGMENT_SIZE (1 << 20) // 1 MB +#define PEB_SEGMENT_SIZE (20 << 20) // 20 MB +#define GS_SEGMENT_SIZE (1 << 20) // 1 MB -#define STACK_SIZE 0x40000ULL // 256KB +#define STACK_SIZE 0x40000ULL // 256KB -#define GDT_ADDR 0x35000 -#define GDT_LIMIT 0x1000 -#define GDT_ENTRY_SIZE 0x8 +#define GDT_ADDR 0x35000 +#define GDT_LIMIT 0x1000 +#define GDT_ENTRY_SIZE 0x8 // TODO: Get rid of that -#define WOW64_PEB32_PROCESS_PARA_BASE 0x30000 -#define WOW64_PEB32_PROCESS_PARA_SIZE 0x5000 -#define WOW64_NATIVE_STACK_BASE 0x98000 -#define WOW64_NATIVE_STACK_SIZE 0x8000 -#define WOW64_32BIT_STACK_SIZE (1 << 20) +#define WOW64_NATIVE_STACK_SIZE 0x8000 +#define WOW64_32BIT_STACK_SIZE (1 << 20) struct emulator_settings; struct application_settings;