From 933bfcaaf3c0bb2f45868a9fe256421b0ddaa7f3 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Thu, 17 Oct 2024 19:02:14 +0200 Subject: [PATCH] Apply thread attributes --- src/windows-emulator/process_context.hpp | 46 +++++++++-------- src/windows-emulator/syscalls.cpp | 61 ++++++++++++++++++++++- src/windows-emulator/windows_emulator.cpp | 57 ++++++++++----------- 3 files changed, 113 insertions(+), 51 deletions(-) diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index b553db23..f8ba9e18 100644 --- a/src/windows-emulator/process_context.hpp +++ b/src/windows-emulator/process_context.hpp @@ -8,6 +8,19 @@ #include +#define PEB_SEGMENT_SIZE (1 << 20) // 1 MB +#define GS_SEGMENT_SIZE (1 << 20) // 1 MB + +#define IA32_GS_BASE_MSR 0xC0000101 + +#define KUSD_ADDRESS 0x7ffe0000 + +#define STACK_SIZE 0x40000ULL + +#define GDT_ADDR 0x30000 +#define GDT_LIMIT 0x1000 +#define GDT_ENTRY_SIZE 0x8 + struct event { bool signaled{}; @@ -149,16 +162,8 @@ class emulator_thread public: emulator_thread() = default; - emulator_thread(x64_emulator& emu, std::vector default_register_set, const uint64_t start_address, - const uint64_t argument, - const uint64_t stack_size) - : emu_ptr(&emu) - , stack_size(page_align_up(stack_size)) - , start_address(start_address) - , argument(argument) - , last_registers(std::move(default_register_set)) - { - } + emulator_thread(x64_emulator& emu, const process_context& context, uint64_t start_address, uint64_t argument, + uint64_t stack_size, uint32_t id); emulator_thread(const emulator_thread&) = delete; emulator_thread& operator=(const emulator_thread&) = delete; @@ -188,14 +193,14 @@ public: x64_emulator* emu_ptr{}; - uint32_t id{}; - uint64_t stack_base{}; uint64_t stack_size{}; uint64_t start_address{}; uint64_t argument{}; uint64_t executed_instructions{0}; + uint32_t id{}; + std::optional gs_segment; std::optional> teb; @@ -211,11 +216,11 @@ public: emu.restore_registers(this->last_registers); } - void setup_if_necessary(x64_emulator& emu, const process_context& context) + void setup_if_necessary(x64_emulator& emu, const process_context& context) const { - if (!this->teb.has_value()) + if (!this->executed_instructions) { - this->setup(emu, context); + this->setup_registers(emu, context); } } @@ -230,7 +235,7 @@ public: } private: - void setup(x64_emulator& emu, const process_context& context); + void setup_registers(x64_emulator& emu, const process_context& context) const; }; struct process_context @@ -276,6 +281,7 @@ struct process_context std::vector default_register_set{}; + uint32_t current_thread_id{0}; handle_store threads{}; emulator_thread* active_thread{nullptr}; @@ -338,11 +344,7 @@ struct process_context handle create_thread(x64_emulator& emu, const uint64_t start_address, const uint64_t argument, const uint64_t stack_size) { - emulator_thread t{emu, default_register_set, start_address, argument, stack_size}; - - const handle h = this->threads.store(std::move(t)); - this->threads.get(h)->id = h.value.id; - - return h; + emulator_thread t{emu, *this, start_address, argument, stack_size, ++this->current_thread_id}; + return this->threads.store(std::move(t)); } }; diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index f954595e..0ebdda8c 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -161,6 +161,20 @@ namespace }; } + template + void write_attribute(emulator& emu, const PS_ATTRIBUTE& attribute, const T& value) + { + if (attribute.ReturnLength) + { + emulator_object{emu, attribute.ReturnLength}.write(sizeof(T)); + } + + if (attribute.Size >= sizeof(T)) + { + emulator_object{emu, attribute.Value}.write(value); + } + } + NTSTATUS handle_NtQueryPerformanceCounter(const syscall_context&, const emulator_object performance_counter, const emulator_object performance_frequency) @@ -866,6 +880,7 @@ namespace { if (info_class == SystemFlushInformation || info_class == SystemFeatureConfigurationInformation + || info_class == SystemSupportedProcessorArchitectures2 || info_class == SystemFeatureConfigurationSectionInformation) { //printf("Unsupported, but allowed system info class: %X\n", info_class); @@ -1195,6 +1210,7 @@ namespace || info_class == ProcessTlsInformation || info_class == ProcessConsoleHostProcess || info_class == ProcessFaultInformation + || info_class == ProcessDefaultHardErrorMode || info_class == ProcessRaiseUMExceptionOnInvalidHandleClose) { return STATUS_SUCCESS; @@ -1908,7 +1924,8 @@ namespace const emulator_object object_attributes, const uint64_t process_handle, const uint64_t start_routine, const uint64_t argument, const ULONG create_flags, const SIZE_T zero_bits, - const SIZE_T stack_size, const SIZE_T maximum_stack_size) + const SIZE_T stack_size, const SIZE_T maximum_stack_size, + const emulator_object attribute_list) { if (process_handle != ~0ULL) { @@ -1917,8 +1934,49 @@ namespace const auto h = c.proc.create_thread(c.emu, start_routine, argument, stack_size); thread_handle.write(h.bits); + + if (!attribute_list) + { + return STATUS_SUCCESS; + } + + const auto* thread = c.proc.threads.get(h); + + const emulator_object attributes{ + c.emu, attribute_list.value() + offsetof(PS_ATTRIBUTE_LIST, Attributes) + }; + + const auto total_length = attribute_list.read().TotalLength; + + constexpr auto entry_size = sizeof(PS_ATTRIBUTE); + constexpr auto header_size = sizeof(PS_ATTRIBUTE_LIST) - entry_size; + const auto attribute_count = (total_length - header_size) / entry_size; + + for (size_t i = 0; i < attribute_count; ++i) + { + attributes.access([&](const PS_ATTRIBUTE& attribute) + { + const auto type = attribute.Attribute & ~PS_ATTRIBUTE_THREAD; + + if (type == PsAttributeClientId) + { + const auto client_id = thread->teb->read().ClientId; + write_attribute(c.emu, attribute, client_id); + } + else if (type == PsAttributeTebAddress) + { + write_attribute(c.emu, attribute, thread->teb->ptr()); + } + }, i); + } + return STATUS_SUCCESS; } + + NTSTATUS handle_NtQueryDebugFilterState() + { + return FALSE; + } } void syscall_dispatcher::setup(const exported_symbols& ntdll_exports, const exported_symbols& win32u_exports) @@ -2018,6 +2076,7 @@ void syscall_dispatcher::add_handlers() add_handler(NtSetSystemInformation); add_handler(NtQueryInformationFile); add_handler(NtCreateThreadEx); + add_handler(NtQueryDebugFilterState); #undef add_handler diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index e5b09a0c..1307bb06 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -4,18 +4,6 @@ #include -#define PEB_SEGMENT_SIZE (1 << 20) // 1 MB - -#define GS_SEGMENT_SIZE (1 << 20) // 1 MB - -#define IA32_GS_BASE_MSR 0xC0000101 - -#define KUSD_ADDRESS 0x7ffe0000 - -#define GDT_ADDR 0x30000 -#define GDT_LIMIT 0x1000 -#define GDT_ENTRY_SIZE 0x8 - namespace { template @@ -36,16 +24,13 @@ namespace emu.reg(x64_register::rsp, sp); } - uint64_t setup_stack(x64_emulator& emu, const size_t stack_size) + void setup_stack(x64_emulator& emu, const uint64_t stack_base, const size_t stack_size) { - const auto stack_base = emu.allocate_memory(stack_size, memory_permission::read_write); - const uint64_t stack_end = stack_base + stack_size; emu.reg(x64_register::rsp, stack_end); - return stack_base; } - emulator_allocator setup_gs_segment(x64_emulator& emu, const uint64_t size) + void setup_gs_segment(x64_emulator& emu, const emulator_allocator& allocator) { struct msr_value { @@ -53,16 +38,12 @@ namespace uint64_t value; }; - const auto segment_base = emu.allocate_memory(size, memory_permission::read_write); - const msr_value value{ IA32_GS_BASE_MSR, - segment_base + allocator.get_base() }; emu.write_register(x64_register::msr, &value, sizeof(value)); - - return {emu, segment_base, size}; } emulator_object setup_kusd(x64_emulator& emu) @@ -218,7 +199,7 @@ namespace context.peb = allocator.reserve(); /* Values of the following fields must be - * allocated relative to the process_params themselves. + * allocated relative to the process_params themselves * and included in the length: * * CurrentDirectory @@ -329,7 +310,6 @@ namespace case memory_operation::read: return 0; case memory_operation::write: - return 1; case memory_operation::exec: return 1; } @@ -460,10 +440,24 @@ namespace } } -void emulator_thread::setup(x64_emulator& emu, const process_context& context) +emulator_thread::emulator_thread(x64_emulator& emu, const process_context& context, + const uint64_t start_address, + const uint64_t argument, + const uint64_t stack_size, const uint32_t id) + : emu_ptr(&emu) + , stack_size(page_align_up(std::max(stack_size, STACK_SIZE))) + , start_address(start_address) + , argument(argument) + , last_registers(context.default_register_set) + , id(id) { - this->stack_base = setup_stack(emu, this->stack_size); - this->gs_segment = setup_gs_segment(emu, GS_SEGMENT_SIZE); + this->stack_base = emu.allocate_memory(this->stack_size, memory_permission::read_write); + + this->gs_segment = emulator_allocator{ + emu, + emu.allocate_memory(GS_SEGMENT_SIZE, memory_permission::read_write), + GS_SEGMENT_SIZE, + }; this->teb = this->gs_segment->reserve(); @@ -476,6 +470,12 @@ void emulator_thread::setup(x64_emulator& emu, const process_context& context) teb_obj.NtTib.Self = &this->teb->ptr()->NtTib; teb_obj.ProcessEnvironmentBlock = context.peb.ptr(); }); +} + +void emulator_thread::setup_registers(x64_emulator& emu, const process_context& context) const +{ + setup_stack(emu, this->stack_base, this->stack_size); + setup_gs_segment(emu, *this->gs_segment); CONTEXT ctx{}; ctx.ContextFlags = CONTEXT_ALL; @@ -485,6 +485,7 @@ void emulator_thread::setup(x64_emulator& emu, const process_context& context) ctx.Rip = context.rtl_user_thread_start; ctx.Rcx = this->start_address; + ctx.Rdx = this->argument; const auto ctx_obj = allocate_object_on_stack(emu); ctx_obj.write(ctx); @@ -543,7 +544,7 @@ void windows_emulator::setup_process(const std::filesystem::path& application, context.default_register_set = emu.save_registers(); - const auto main_thread_id = context.create_thread(emu, context.executable->entry_point, 0, 0x4000); + const auto main_thread_id = context.create_thread(emu, context.executable->entry_point, 0, 0); switch_to_thread(emu, context, main_thread_id); }