From da658e51784f1af0e2a84de65d36fc1ff20be131 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 1 Jun 2025 13:30:10 +0200 Subject: [PATCH] Prepare timer support --- src/emulator/memory_permission.hpp | 19 +++++++++++ src/windows-emulator/handles.hpp | 1 + src/windows-emulator/process_context.cpp | 2 ++ src/windows-emulator/process_context.hpp | 1 + src/windows-emulator/syscalls.cpp | 19 +++++------ src/windows-emulator/syscalls/event.cpp | 1 + src/windows-emulator/syscalls/memory.cpp | 10 +++--- src/windows-emulator/syscalls/mutant.cpp | 3 +- src/windows-emulator/syscalls/timer.cpp | 41 ++++++++++++++++++++++- src/windows-emulator/windows_emulator.cpp | 17 ++++++++-- src/windows-emulator/windows_emulator.hpp | 2 +- src/windows-emulator/windows_objects.hpp | 15 +++++++++ 12 files changed, 110 insertions(+), 21 deletions(-) diff --git a/src/emulator/memory_permission.hpp b/src/emulator/memory_permission.hpp index 00e7628b..05af391e 100644 --- a/src/emulator/memory_permission.hpp +++ b/src/emulator/memory_permission.hpp @@ -52,3 +52,22 @@ inline memory_permission& operator^=(memory_permission& x, const memory_permissi x = x ^ y; return x; } + +/***************************************************************************** + * + ****************************************************************************/ + +inline bool is_executable(const memory_permission permission) +{ + return (permission & memory_permission::exec) != memory_permission::none; +} + +inline bool is_readable(const memory_permission permission) +{ + return (permission & memory_permission::read) != memory_permission::none; +} + +inline bool is_writable(const memory_permission permission) +{ + return (permission & memory_permission::write) != memory_permission::none; +} diff --git a/src/windows-emulator/handles.hpp b/src/windows-emulator/handles.hpp index 10fee2d2..a5430973 100644 --- a/src/windows-emulator/handles.hpp +++ b/src/windows-emulator/handles.hpp @@ -20,6 +20,7 @@ struct handle_types mutant, token, window, + timer, }; }; diff --git a/src/windows-emulator/process_context.cpp b/src/windows-emulator/process_context.cpp index d8aaf239..936ec373 100644 --- a/src/windows-emulator/process_context.cpp +++ b/src/windows-emulator/process_context.cpp @@ -272,6 +272,7 @@ void process_context::serialize(utils::buffer_serializer& buffer) const buffer.write(this->ports); buffer.write(this->mutants); buffer.write(this->windows); + buffer.write(this->timers); buffer.write(this->registry_keys); buffer.write_map(this->atoms); @@ -311,6 +312,7 @@ void process_context::deserialize(utils::buffer_deserializer& buffer) buffer.read(this->ports); buffer.read(this->mutants); buffer.read(this->windows); + buffer.read(this->timers); buffer.read(this->registry_keys); buffer.read_map(this->atoms); diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index 390fccab..6fad5508 100644 --- a/src/windows-emulator/process_context.hpp +++ b/src/windows-emulator/process_context.hpp @@ -115,6 +115,7 @@ struct process_context handle_store ports{}; handle_store mutants{}; handle_store windows{}; + handle_store timers{}; handle_store registry_keys{}; std::map atoms{}; diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 66547708..b8e5ec76 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -358,14 +358,16 @@ namespace syscalls emulator_object minimum_time, emulator_object current_time); NTSTATUS handle_NtSetTimerResolution(const syscall_context&, ULONG /*desired_resolution*/, BOOLEAN set_resolution, emulator_object current_resolution); + NTSTATUS handle_NtCreateTimer2(const syscall_context& c, emulator_object timer_handle, uint64_t reserved, + emulator_object>> object_attributes, + ULONG attributes, ACCESS_MASK desired_access); // syscalls/token.cpp: - NTSTATUS handle_NtDuplicateToken(const syscall_context&, handle existing_token_handle, - ACCESS_MASK /*desired_access*/, - emulator_object>> - /*object_attributes*/, - BOOLEAN /*effective_only*/, TOKEN_TYPE type, - emulator_object new_token_handle); + NTSTATUS + handle_NtDuplicateToken(const syscall_context&, handle existing_token_handle, ACCESS_MASK /*desired_access*/, + emulator_object>> + /*object_attributes*/, + BOOLEAN /*effective_only*/, TOKEN_TYPE type, emulator_object new_token_handle); NTSTATUS handle_NtQueryInformationToken(const syscall_context& c, handle token_handle, TOKEN_INFORMATION_CLASS token_information_class, uint64_t token_information, ULONG token_information_length, emulator_object return_length); @@ -758,11 +760,6 @@ namespace syscalls return STATUS_NOT_SUPPORTED; } - NTSTATUS handle_NtCreateTimer2() - { - return STATUS_NOT_SUPPORTED; - } - NTSTATUS handle_NtUserMapVirtualKeyEx() { return 0; diff --git a/src/windows-emulator/syscalls/event.cpp b/src/windows-emulator/syscalls/event.cpp index a9c4d39b..c2f6b757 100644 --- a/src/windows-emulator/syscalls/event.cpp +++ b/src/windows-emulator/syscalls/event.cpp @@ -63,6 +63,7 @@ namespace syscalls if (attributes.ObjectName) { name = read_unicode_string(c.emu, attributes.ObjectName); + c.win_emu.log.print(color::dark_gray, "--> Event name: %s\n", u16_to_u8(name).c_str()); } } diff --git a/src/windows-emulator/syscalls/memory.cpp b/src/windows-emulator/syscalls/memory.cpp index c0f81684..be5af2fb 100644 --- a/src/windows-emulator/syscalls/memory.cpp +++ b/src/windows-emulator/syscalls/memory.cpp @@ -210,14 +210,16 @@ namespace syscalls if (commit && !reserve && c.win_emu.memory.commit_memory(potential_base, static_cast(allocation_bytes), protection)) { - c.win_emu.log.print(color::dark_gray, "--> Committed 0x%" PRIx64 " - 0x%" PRIx64 "\n", potential_base, - potential_base + allocation_bytes); + c.win_emu.log.print(is_executable(protection) ? color::gray : color::dark_gray, + "--> Committed 0x%" PRIx64 " - 0x%" PRIx64 " (%s)\n", potential_base, + potential_base + allocation_bytes, get_permission_string(protection).c_str()); return STATUS_SUCCESS; } - c.win_emu.log.print(color::dark_gray, "--> Allocated 0x%" PRIx64 " - 0x%" PRIx64 "\n", potential_base, - potential_base + allocation_bytes); + c.win_emu.log.print(is_executable(protection) ? color::gray : color::dark_gray, + "--> Allocated 0x%" PRIx64 " - 0x%" PRIx64 " (%s)\n", potential_base, + potential_base + allocation_bytes, get_permission_string(protection).c_str()); return c.win_emu.memory.allocate_memory(potential_base, static_cast(allocation_bytes), protection, !commit) diff --git a/src/windows-emulator/syscalls/mutant.cpp b/src/windows-emulator/syscalls/mutant.cpp index 5a86cfbe..1adb21d2 100644 --- a/src/windows-emulator/syscalls/mutant.cpp +++ b/src/windows-emulator/syscalls/mutant.cpp @@ -77,8 +77,7 @@ namespace syscalls const auto attributes = object_attributes.read(); if (attributes.ObjectName) { - name = read_unicode_string( - c.emu, emulator_object>>{c.emu, attributes.ObjectName}); + name = read_unicode_string(c.emu, attributes.ObjectName); c.win_emu.log.print(color::dark_gray, "--> Mutant name: %s\n", u16_to_u8(name).c_str()); } } diff --git a/src/windows-emulator/syscalls/timer.cpp b/src/windows-emulator/syscalls/timer.cpp index 1cd5b7c7..329a3ab2 100644 --- a/src/windows-emulator/syscalls/timer.cpp +++ b/src/windows-emulator/syscalls/timer.cpp @@ -30,4 +30,43 @@ namespace syscalls return STATUS_SUCCESS; } -} \ No newline at end of file + + NTSTATUS handle_NtCreateTimer2(const syscall_context& c, const emulator_object timer_handle, + uint64_t /*reserved*/, + const emulator_object>> object_attributes, + ULONG /*attributes*/, ACCESS_MASK /*desired_access*/) + { + std::u16string name{}; + if (object_attributes) + { + const auto attributes = object_attributes.read(); + if (attributes.ObjectName) + { + name = read_unicode_string(c.emu, attributes.ObjectName); + c.win_emu.log.print(color::dark_gray, "--> Timer name: %s\n", u16_to_u8(name).c_str()); + } + } + + if (!name.empty()) + { + for (auto& entry : c.proc.timers) + { + if (entry.second.name == name) + { + ++entry.second.ref_count; + timer_handle.write(c.proc.timers.make_handle(entry.first)); + return STATUS_OBJECT_NAME_EXISTS; + } + } + } + + timer t{}; + t.name = std::move(name); + + const auto h = c.proc.timers.store(std::move(t)); + timer_handle.write(h); + + return STATUS_SUCCESS; + } + +} diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index 1b518afd..8911a48b 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -346,8 +346,10 @@ void windows_emulator::yield_thread(const bool alertable) this->emu().stop(); } -void windows_emulator::perform_thread_switch() +bool windows_emulator::perform_thread_switch() { + const auto needed_switch = std::exchange(this->switch_thread_, false); + this->switch_thread_ = false; while (!switch_to_next_thread(*this)) { @@ -359,7 +361,15 @@ void windows_emulator::perform_thread_switch() { std::this_thread::sleep_for(1ms); } + + if (this->should_stop) + { + this->switch_thread_ = needed_switch; + return false; + } } + + return true; } bool windows_emulator::activate_thread(const uint32_t id) @@ -597,7 +607,10 @@ void windows_emulator::start(size_t count) { if (this->switch_thread_ || !this->current_thread().is_thread_ready(this->process, this->clock())) { - this->perform_thread_switch(); + if (!this->perform_thread_switch()) + { + break; + } } this->emu().start(count); diff --git a/src/windows-emulator/windows_emulator.hpp b/src/windows-emulator/windows_emulator.hpp index ac0f20c6..a1fae00e 100644 --- a/src/windows-emulator/windows_emulator.hpp +++ b/src/windows-emulator/windows_emulator.hpp @@ -182,7 +182,7 @@ class windows_emulator bool fuzzing{false}; void yield_thread(bool alertable = false); - void perform_thread_switch(); + bool perform_thread_switch(); bool activate_thread(uint32_t id); private: diff --git a/src/windows-emulator/windows_objects.hpp b/src/windows-emulator/windows_objects.hpp index 4db28449..912bfb46 100644 --- a/src/windows-emulator/windows_objects.hpp +++ b/src/windows-emulator/windows_objects.hpp @@ -6,6 +6,21 @@ #include #include +struct timer : ref_counted_object +{ + std::u16string name{}; + + void serialize_object(utils::buffer_serializer& buffer) const override + { + buffer.write(this->name); + } + + void deserialize_object(utils::buffer_deserializer& buffer) override + { + buffer.read(this->name); + } +}; + struct event : ref_counted_object { bool signaled{};