From 57ad277158a0e22e420d25b878d75a00aba8f884 Mon Sep 17 00:00:00 2001 From: ssvine <79405160+ssvine@users.noreply.github.com> Date: Tue, 30 Dec 2025 15:18:55 +0300 Subject: [PATCH] Fix creating suspended thread and parse create_flags --- src/common/platform/kernel_mapped.hpp | 7 +++++++ src/windows-emulator/emulator_thread.cpp | 15 +++++++++++++-- src/windows-emulator/emulator_thread.hpp | 5 ++++- src/windows-emulator/process_context.cpp | 4 ++-- src/windows-emulator/process_context.hpp | 2 +- src/windows-emulator/syscalls/thread.cpp | 2 +- src/windows-emulator/windows_emulator.cpp | 2 +- 7 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/common/platform/kernel_mapped.hpp b/src/common/platform/kernel_mapped.hpp index da0ebe52..b1d2b714 100644 --- a/src/common/platform/kernel_mapped.hpp +++ b/src/common/platform/kernel_mapped.hpp @@ -971,6 +971,13 @@ union TEB_CROSS_TEB_FLAGS_UNION USHORT SpareCrossTebBits : 16; }; +constexpr auto THREAD_CREATE_FLAGS_CREATE_SUSPENDED = 0x1; +constexpr auto THREAD_CREATE_FLAGS_SKIP_THREAD_ATTACH = 0x2; +constexpr auto THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER = 0x4; +constexpr auto THREAD_CREATE_FLAGS_LOADER_WORKER = 0x10; +constexpr auto THREAD_CREATE_FLAGS_SKIP_LOADER_INIT = 0x20; +constexpr auto THREAD_CREATE_FLAGS_BYPASS_PROCESS_FREEZE = 0x40; + union TEB_SAME_TEB_FLAGS_UNION { USHORT SameTebFlags; diff --git a/src/windows-emulator/emulator_thread.cpp b/src/windows-emulator/emulator_thread.cpp index 42eb9ae8..c11daa9e 100644 --- a/src/windows-emulator/emulator_thread.cpp +++ b/src/windows-emulator/emulator_thread.cpp @@ -116,16 +116,18 @@ namespace } emulator_thread::emulator_thread(memory_manager& memory, const process_context& context, const uint64_t start_address, - const uint64_t argument, const uint64_t stack_size, const bool suspended, const uint32_t id, + const uint64_t argument, const uint64_t stack_size, const uint32_t create_flags, const uint32_t id, const bool initial_thread) : memory_ptr(&memory), // stack_size(page_align_up(std::max(stack_size, static_cast(STACK_SIZE)))), start_address(start_address), argument(argument), id(id), - suspended(suspended), + create_flags(create_flags), last_registers(context.default_register_set) { + this->suspended = create_flags & THREAD_CREATE_FLAGS_CREATE_SUSPENDED; + // native 64-bit if (!context.is_wow64_process) { @@ -154,6 +156,9 @@ emulator_thread::emulator_thread(memory_manager& memory, const process_context& teb_obj.CurrentLocale = 0x409; teb_obj.ProcessEnvironmentBlock = context.peb64.value(); teb_obj.SameTebFlags.InitialThread = initial_thread; + teb_obj.SameTebFlags.SkipThreadAttach = (create_flags & THREAD_CREATE_FLAGS_SKIP_THREAD_ATTACH) ? 1 : 0; + teb_obj.SameTebFlags.LoaderWorker = (create_flags & THREAD_CREATE_FLAGS_LOADER_WORKER) ? 1 : 0; + teb_obj.SameTebFlags.SkipLoaderInit = (create_flags & THREAD_CREATE_FLAGS_SKIP_LOADER_INIT) ? 1 : 0; }); return; @@ -212,6 +217,9 @@ emulator_thread::emulator_thread(memory_manager& memory, const process_context& teb_obj.ProcessEnvironmentBlock = context.peb64.value(); teb_obj.SameTebFlags.InitialThread = initial_thread; + teb_obj.SameTebFlags.SkipThreadAttach = (create_flags & THREAD_CREATE_FLAGS_SKIP_THREAD_ATTACH) ? 1 : 0; + teb_obj.SameTebFlags.LoaderWorker = (create_flags & THREAD_CREATE_FLAGS_LOADER_WORKER) ? 1 : 0; + teb_obj.SameTebFlags.SkipLoaderInit = (create_flags & THREAD_CREATE_FLAGS_SKIP_LOADER_INIT) ? 1 : 0; teb_obj.StaticUnicodeString.MaximumLength = sizeof(teb_obj.StaticUnicodeBuffer); teb_obj.StaticUnicodeString.Buffer = this->teb64->value() + offsetof(TEB64, StaticUnicodeBuffer); @@ -268,6 +276,9 @@ emulator_thread::emulator_thread(memory_manager& memory, const process_context& teb32_obj.WowTebOffset = -0x2000; teb32_obj.InitialThread = initial_thread; + teb32_obj.SkipThreadAttach = (create_flags & THREAD_CREATE_FLAGS_SKIP_THREAD_ATTACH) ? 1 : 0; + teb32_obj.LoaderWorker = (create_flags & THREAD_CREATE_FLAGS_LOADER_WORKER) ? 1 : 0; + teb32_obj.SkipLoaderInit = (create_flags & THREAD_CREATE_FLAGS_SKIP_LOADER_INIT) ? 1 : 0; // Note: CurrentLocale and other fields will be initialized by WOW64 runtime }); diff --git a/src/windows-emulator/emulator_thread.hpp b/src/windows-emulator/emulator_thread.hpp index 95124a0c..78d13ba3 100644 --- a/src/windows-emulator/emulator_thread.hpp +++ b/src/windows-emulator/emulator_thread.hpp @@ -49,7 +49,7 @@ class emulator_thread : public ref_counted_object } emulator_thread(memory_manager& memory, const process_context& context, uint64_t start_address, uint64_t argument, uint64_t stack_size, - bool suspended, uint32_t id, bool initial_thread); + uint32_t create_flags, uint32_t id, bool initial_thread); emulator_thread(const emulator_thread&) = delete; emulator_thread& operator=(const emulator_thread&) = delete; @@ -86,6 +86,7 @@ class emulator_thread : public ref_counted_object bool await_any{false}; bool waiting_for_alert{false}; bool alerted{false}; + uint32_t create_flags{0}; uint32_t suspended{0}; std::optional await_time{}; @@ -164,6 +165,7 @@ class emulator_thread : public ref_counted_object buffer.write(this->waiting_for_alert); buffer.write(this->alerted); + buffer.write(this->create_flags); buffer.write(this->suspended); buffer.write_optional(this->await_time); @@ -209,6 +211,7 @@ class emulator_thread : public ref_counted_object buffer.read(this->waiting_for_alert); buffer.read(this->alerted); + buffer.read(this->create_flags); buffer.read(this->suspended); buffer.read_optional(this->await_time); diff --git a/src/windows-emulator/process_context.cpp b/src/windows-emulator/process_context.cpp index f9e2fdef..98b57568 100644 --- a/src/windows-emulator/process_context.cpp +++ b/src/windows-emulator/process_context.cpp @@ -525,9 +525,9 @@ generic_handle_store* process_context::get_handle_store(const handle handle) } handle process_context::create_thread(memory_manager& memory, const uint64_t start_address, const uint64_t argument, - const uint64_t stack_size, const bool suspended, const bool initial_thread) + const uint64_t stack_size, const uint32_t create_flags, const bool initial_thread) { - emulator_thread t{memory, *this, start_address, argument, stack_size, suspended, ++this->spawned_thread_count, initial_thread}; + emulator_thread t{memory, *this, start_address, argument, stack_size, create_flags, ++this->spawned_thread_count, initial_thread}; auto [h, thr] = this->threads.store_and_get(std::move(t)); this->callbacks_->on_thread_create(h, *thr); return h; diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index 91ffb417..9755ca64 100644 --- a/src/windows-emulator/process_context.hpp +++ b/src/windows-emulator/process_context.hpp @@ -74,7 +74,7 @@ struct process_context 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, bool suspended, + 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); std::optional find_atom(std::u16string_view name); diff --git a/src/windows-emulator/syscalls/thread.cpp b/src/windows-emulator/syscalls/thread.cpp index e19da9d7..ddd4baae 100644 --- a/src/windows-emulator/syscalls/thread.cpp +++ b/src/windows-emulator/syscalls/thread.cpp @@ -625,7 +625,7 @@ namespace syscalls return STATUS_NOT_SUPPORTED; } - const auto h = c.proc.create_thread(c.win_emu.memory, start_routine, argument, stack_size, create_flags & CREATE_SUSPENDED); + const auto h = c.proc.create_thread(c.win_emu.memory, start_routine, argument, stack_size, create_flags); thread_handle.write(h); if (!attribute_list) diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index e751dcbf..e31d245b 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -371,7 +371,7 @@ void windows_emulator::setup_process(const application_settings& app_settings) this->dispatcher.setup(ntdll->exports, ntdll_data, win32u->exports, win32u_data); const auto main_thread_id = context.create_thread(this->memory, this->mod_manager.executable->entry_point, 0, - this->mod_manager.executable->size_of_stack_commit, false, true); + this->mod_manager.executable->size_of_stack_commit, 0, true); switch_to_thread(*this, main_thread_id); }