From ecc00216d640bb69015d7b683b33d8db87b58083 Mon Sep 17 00:00:00 2001 From: 66hh <49398720+66hh@users.noreply.github.com> Date: Sat, 27 Dec 2025 13:51:10 +0800 Subject: [PATCH 01/22] Support ProcessInstrumentationCallback --- src/common/platform/process.hpp | 6 ++++++ src/windows-emulator/process_context.cpp | 3 +++ src/windows-emulator/process_context.hpp | 1 + src/windows-emulator/syscall_dispatcher.cpp | 13 +++++++++++++ src/windows-emulator/syscalls/process.cpp | 17 +++++++++++++++++ 5 files changed, 40 insertions(+) diff --git a/src/common/platform/process.hpp b/src/common/platform/process.hpp index a77be9b9..f91e41cf 100644 --- a/src/common/platform/process.hpp +++ b/src/common/platform/process.hpp @@ -1124,4 +1124,10 @@ struct PROCESS_PRIORITY_CLASS UCHAR PriorityClass; }; +struct PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION +{ + ULONG Version; + ULONG Reserved; + PVOID Callback; +}; // NOLINTEND(modernize-use-using,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) diff --git a/src/windows-emulator/process_context.cpp b/src/windows-emulator/process_context.cpp index c48c155c..ea8cfee3 100644 --- a/src/windows-emulator/process_context.cpp +++ b/src/windows-emulator/process_context.cpp @@ -388,6 +388,7 @@ void process_context::setup(x86_64_emulator& emu, memory_manager& memory, regist this->rtl_user_thread_start = ntdll.find_export("RtlUserThreadStart"); this->ki_user_apc_dispatcher = ntdll.find_export("KiUserApcDispatcher"); this->ki_user_exception_dispatcher = ntdll.find_export("KiUserExceptionDispatcher"); + this->instrumentation_callback = 0; this->default_register_set = emu.save_registers(); } @@ -413,6 +414,7 @@ void process_context::serialize(utils::buffer_serializer& buffer) const buffer.write_optional(this->rtl_user_thread_start32); buffer.write(this->ki_user_apc_dispatcher); buffer.write(this->ki_user_exception_dispatcher); + buffer.write(this->instrumentation_callback); buffer.write(this->events); buffer.write(this->files); @@ -467,6 +469,7 @@ void process_context::deserialize(utils::buffer_deserializer& buffer) buffer.read_optional(this->rtl_user_thread_start32); buffer.read(this->ki_user_apc_dispatcher); buffer.read(this->ki_user_exception_dispatcher); + buffer.read(this->instrumentation_callback); buffer.read(this->events); buffer.read(this->files); diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index 634fe3c4..01070a06 100644 --- a/src/windows-emulator/process_context.hpp +++ b/src/windows-emulator/process_context.hpp @@ -110,6 +110,7 @@ struct process_context uint64_t rtl_user_thread_start{}; uint64_t ki_user_apc_dispatcher{}; uint64_t ki_user_exception_dispatcher{}; + uint64_t instrumentation_callback{}; // For WOW64 processes std::optional> peb32; diff --git a/src/windows-emulator/syscall_dispatcher.cpp b/src/windows-emulator/syscall_dispatcher.cpp index 370da9af..4aabed1c 100644 --- a/src/windows-emulator/syscall_dispatcher.cpp +++ b/src/windows-emulator/syscall_dispatcher.cpp @@ -101,6 +101,19 @@ void syscall_dispatcher::dispatch(windows_emulator& win_emu) } entry->second.handler(c); + + if (context.instrumentation_callback != 0 && entry->second.name != "NtContinue") + { + uint64_t rip_old = emu.reg(x86_register::rip); + + // The increase in RIP caused by executing the syscall here has not yet occurred. + // If RIP is set directly, it will lead to an incorrect address, so the length of + // the syscall instruction needs to be subtracted. + emu.reg(x86_register::rip, context.instrumentation_callback - 2); + + emu.reg(x86_register::r10, rip_old); + } + } catch (std::exception& e) { diff --git a/src/windows-emulator/syscalls/process.cpp b/src/windows-emulator/syscalls/process.cpp index 0d9105e6..b3cd0fbc 100644 --- a/src/windows-emulator/syscalls/process.cpp +++ b/src/windows-emulator/syscalls/process.cpp @@ -281,6 +281,23 @@ namespace syscalls return STATUS_SUCCESS; } + if (info_class == ProcessInstrumentationCallback) + { + + if (process_information_length != sizeof(PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION)) + { + return STATUS_BUFFER_OVERFLOW; + } + + PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION info; + + c.emu.read_memory(process_information, &info, sizeof(PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION)); + + c.proc.instrumentation_callback = (uint64_t)info.Callback; + + return STATUS_SUCCESS; + } + c.win_emu.log.error("Unsupported info process class: %X\n", info_class); c.emu.stop(); From 98393c03d2a370529cb10b06b557d29629db2c2a Mon Sep 17 00:00:00 2001 From: 66hh <49398720+66hh@users.noreply.github.com> Date: Sat, 27 Dec 2025 16:56:48 +0800 Subject: [PATCH 02/22] Add a check before the conversion path --- src/windows-emulator/syscalls/file.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/windows-emulator/syscalls/file.cpp b/src/windows-emulator/syscalls/file.cpp index 25bfb3c8..43fe8497 100644 --- a/src/windows-emulator/syscalls/file.cpp +++ b/src/windows-emulator/syscalls/file.cpp @@ -1014,6 +1014,12 @@ namespace syscalls std::error_code ec{}; const windows_path path = f.name; + + if (!path.is_absolute()) + { + return STATUS_OBJECT_NAME_NOT_FOUND; + } + const bool is_directory = std::filesystem::is_directory(c.win_emu.file_sys.translate(path), ec); if (is_directory || create_options & FILE_DIRECTORY_FILE) From 55310c57ac24c37ec1007313806536bc4908f560 Mon Sep 17 00:00:00 2001 From: 66hh <49398720+66hh@users.noreply.github.com> Date: Sat, 27 Dec 2025 16:57:46 +0800 Subject: [PATCH 03/22] Add additional path checks for NtOpenSection --- src/windows-emulator/syscalls/section.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/windows-emulator/syscalls/section.cpp b/src/windows-emulator/syscalls/section.cpp index d54d3298..327f937f 100644 --- a/src/windows-emulator/syscalls/section.cpp +++ b/src/windows-emulator/syscalls/section.cpp @@ -223,7 +223,7 @@ namespace syscalls } if (attributes.RootDirectory != KNOWN_DLLS_DIRECTORY && attributes.RootDirectory != KNOWN_DLLS32_DIRECTORY && - attributes.RootDirectory != BASE_NAMED_OBJECTS_DIRECTORY) + attributes.RootDirectory != BASE_NAMED_OBJECTS_DIRECTORY && !filename.starts_with(u"\\KnownDlls")) { c.win_emu.log.error("Unsupported section\n"); c.emu.stop(); From 02298e2303ce92625b1b67d9da6ea97f34a9808e Mon Sep 17 00:00:00 2001 From: 66hh <49398720+66hh@users.noreply.github.com> Date: Sat, 27 Dec 2025 16:58:28 +0800 Subject: [PATCH 04/22] Fix illegal address write --- src/windows-emulator/syscall_utils.hpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/windows-emulator/syscall_utils.hpp b/src/windows-emulator/syscall_utils.hpp index ad7ce564..67660fa6 100644 --- a/src/windows-emulator/syscall_utils.hpp +++ b/src/windows-emulator/syscall_utils.hpp @@ -232,7 +232,17 @@ NTSTATUS handle_query(x86_64_emulator& emu, const uint64_t buffer, const uint32_ const auto length_setter = [&](const size_t required_size) { if (return_length) { - return_length.write(static_cast(required_size)); + try + { + // VMProtect is trying to pass an incorrect return address. + // This can run on the original version of Windows, but in + // the emulator, this will cause an exception. + return_length.write(static_cast(required_size)); + } + catch (...) + { + + } } }; From 95b17566a0725309814ef4429f0fcdd61f3cc74a Mon Sep 17 00:00:00 2001 From: 66hh <49398720+66hh@users.noreply.github.com> Date: Sat, 27 Dec 2025 17:00:26 +0800 Subject: [PATCH 05/22] Add NtRaiseHardError error message logging --- src/common/platform/status.hpp | 2 ++ src/windows-emulator/syscalls.cpp | 2 +- src/windows-emulator/syscalls/exception.cpp | 18 +++++++++++++++--- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/common/platform/status.hpp b/src/common/platform/status.hpp index 042d9754..23b55e7a 100644 --- a/src/common/platform/status.hpp +++ b/src/common/platform/status.hpp @@ -68,5 +68,7 @@ using NTSTATUS = std::uint32_t; #define STATUS_BUFFER_OVERFLOW ((NTSTATUS)0x80000005L) +#define STATUS_SERVICE_NOTIFICATION ((NTSTATUS)0x40000018L) + #define FILE_DEVICE_NETWORK 0x00000012 #define FSCTL_AFD_BASE FILE_DEVICE_NETWORK diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 15cd7d67..311ec6e9 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -27,7 +27,7 @@ namespace syscalls // syscalls/exception.cpp NTSTATUS handle_NtRaiseHardError(const syscall_context& c, NTSTATUS error_status, ULONG number_of_parameters, emulator_object>> unicode_string_parameter_mask, - emulator_object parameters, HARDERROR_RESPONSE_OPTION valid_response_option, + uint64_t parameters, HARDERROR_RESPONSE_OPTION valid_response_option, emulator_object response); NTSTATUS handle_NtRaiseException(const syscall_context& c, emulator_object>> exception_record, diff --git a/src/windows-emulator/syscalls/exception.cpp b/src/windows-emulator/syscalls/exception.cpp index b18edbf0..fab2d2ee 100644 --- a/src/windows-emulator/syscalls/exception.cpp +++ b/src/windows-emulator/syscalls/exception.cpp @@ -4,10 +4,10 @@ namespace syscalls { - NTSTATUS handle_NtRaiseHardError(const syscall_context& c, const NTSTATUS error_status, const ULONG /*number_of_parameters*/, + NTSTATUS handle_NtRaiseHardError(const syscall_context& c, const NTSTATUS error_status, const ULONG number_of_parameters, const emulator_object>> - /*unicode_string_parameter_mask*/, - const emulator_object /*parameters*/, const HARDERROR_RESPONSE_OPTION /*valid_response_option*/, + /*unicode_string_parameter_mask*/, + const uint64_t parameters, const HARDERROR_RESPONSE_OPTION /*valid_response_option*/, const emulator_object response) { if (response) @@ -15,6 +15,18 @@ namespace syscalls response.write(ResponseAbort); } + if (error_status & STATUS_SERVICE_NOTIFICATION && number_of_parameters >= 3) + { + ULONG_PTR params[3] = {0, 0, 0}; + + if (c.emu.try_read_memory(parameters, ¶ms, sizeof(params))) + { + std::u16string message = + read_unicode_string(c.emu, emulator_object>>{c.emu, params[0]}); + c.win_emu.log.error("Error Message: %s\n", u16_to_u8(message).c_str()); + } + } + c.proc.exit_status = error_status; c.win_emu.callbacks.on_exception(); c.emu.stop(); From 2d24b4189d4c4e8908ef335ff3d9d93c71ce3a42 Mon Sep 17 00:00:00 2001 From: 66hh <49398720+66hh@users.noreply.github.com> Date: Sat, 27 Dec 2025 19:51:29 +0800 Subject: [PATCH 06/22] Fix VMP NtClose detection --- src/windows-emulator/syscalls/object.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/windows-emulator/syscalls/object.cpp b/src/windows-emulator/syscalls/object.cpp index 99b77746..74201e67 100644 --- a/src/windows-emulator/syscalls/object.cpp +++ b/src/windows-emulator/syscalls/object.cpp @@ -6,7 +6,14 @@ namespace syscalls { NTSTATUS handle_NtClose(const syscall_context& c, const handle h) { + const auto value = h.value; + + if (h.h == 0xDEADC0DE) + { + return STATUS_INVALID_HANDLE; + } + if (value.is_pseudo) { return STATUS_SUCCESS; From d83c602f19b4932333887e9bc3e36f247180146b Mon Sep 17 00:00:00 2001 From: 66hh <49398720+66hh@users.noreply.github.com> Date: Sun, 28 Dec 2025 12:40:51 +0800 Subject: [PATCH 07/22] Change data type to fix 32-bit build --- src/common/platform/process.hpp | 2 +- src/windows-emulator/syscalls/process.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/platform/process.hpp b/src/common/platform/process.hpp index f91e41cf..2b8d2c8d 100644 --- a/src/common/platform/process.hpp +++ b/src/common/platform/process.hpp @@ -1128,6 +1128,6 @@ struct PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION { ULONG Version; ULONG Reserved; - PVOID Callback; + uint64_t Callback; }; // NOLINTEND(modernize-use-using,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) diff --git a/src/windows-emulator/syscalls/process.cpp b/src/windows-emulator/syscalls/process.cpp index b3cd0fbc..0f2b7342 100644 --- a/src/windows-emulator/syscalls/process.cpp +++ b/src/windows-emulator/syscalls/process.cpp @@ -293,7 +293,7 @@ namespace syscalls c.emu.read_memory(process_information, &info, sizeof(PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION)); - c.proc.instrumentation_callback = (uint64_t)info.Callback; + c.proc.instrumentation_callback = info.Callback; return STATUS_SUCCESS; } From 020e7ca3f6af6becc16b6044ff08a3dfd4974dc4 Mon Sep 17 00:00:00 2001 From: 66hh <49398720+66hh@users.noreply.github.com> Date: Sun, 28 Dec 2025 19:14:42 +0800 Subject: [PATCH 08/22] Fix the base address alignment issue --- src/windows-emulator/syscalls/memory.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/windows-emulator/syscalls/memory.cpp b/src/windows-emulator/syscalls/memory.cpp index 0b8e45c3..52e95445 100644 --- a/src/windows-emulator/syscalls/memory.cpp +++ b/src/windows-emulator/syscalls/memory.cpp @@ -208,6 +208,16 @@ namespace syscalls { potential_base = c.win_emu.memory.find_free_allocation_base(static_cast(allocation_bytes)); } + else + { + // https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntallocatevirtualmemory + // BaseAddress + // A pointer to a variable that will receive the base address of the allocated region of pages. If the + // initial value of BaseAddress is non-NULL, the region is allocated starting at the specified virtual + // address rounded down to the next host page size address boundary. If the initial value of BaseAddress + // is NULL, the operating system will determine where to allocate the region. + potential_base = page_align_up(potential_base); + } if (!potential_base) { From f95081cb6e505b6c859f45ba46f3c6e1ccbb65f6 Mon Sep 17 00:00:00 2001 From: 66hh <49398720+66hh@users.noreply.github.com> Date: Sun, 28 Dec 2025 19:36:40 +0800 Subject: [PATCH 09/22] Introduce try_write_memory for the memory manager --- src/backends/icicle-emulator/icicle_x86_64_emulator.cpp | 7 ++++++- src/backends/unicorn-emulator/unicorn_x86_64_emulator.cpp | 5 +++++ src/emulator/memory_interface.hpp | 1 + src/windows-emulator/memory_manager.cpp | 5 +++++ src/windows-emulator/memory_manager.hpp | 1 + 5 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/backends/icicle-emulator/icicle_x86_64_emulator.cpp b/src/backends/icicle-emulator/icicle_x86_64_emulator.cpp index d240dc4a..856dc743 100644 --- a/src/backends/icicle-emulator/icicle_x86_64_emulator.cpp +++ b/src/backends/icicle-emulator/icicle_x86_64_emulator.cpp @@ -264,9 +264,14 @@ namespace icicle ice(res, "Failed to read memory"); } + bool try_write_memory(const uint64_t address, const void* data, const size_t size) override + { + return icicle_write_memory(this->emu_, address, data, size); + } + void write_memory(const uint64_t address, const void* data, const size_t size) override { - const auto res = icicle_write_memory(this->emu_, address, data, size); + const auto res = try_write_memory(address, data, size); ice(res, "Failed to write memory"); } diff --git a/src/backends/unicorn-emulator/unicorn_x86_64_emulator.cpp b/src/backends/unicorn-emulator/unicorn_x86_64_emulator.cpp index 31928ae7..e2aaf56a 100644 --- a/src/backends/unicorn-emulator/unicorn_x86_64_emulator.cpp +++ b/src/backends/unicorn-emulator/unicorn_x86_64_emulator.cpp @@ -380,6 +380,11 @@ namespace unicorn uce(uc_mem_read(*this, address, data, size)); } + bool try_write_memory(const uint64_t address, const void* data, const size_t size) override + { + return uc_mem_write(*this, address, data, size) == UC_ERR_OK; + } + void write_memory(const uint64_t address, const void* data, const size_t size) override { uce(uc_mem_write(*this, address, data, size)); diff --git a/src/emulator/memory_interface.hpp b/src/emulator/memory_interface.hpp index 2f735e9a..41145b24 100644 --- a/src/emulator/memory_interface.hpp +++ b/src/emulator/memory_interface.hpp @@ -19,6 +19,7 @@ class memory_interface virtual void read_memory(uint64_t address, void* data, size_t size) const = 0; virtual bool try_read_memory(uint64_t address, void* data, size_t size) const = 0; virtual void write_memory(uint64_t address, const void* data, size_t size) = 0; + virtual bool try_write_memory(uint64_t address, const void* data, size_t size) = 0; private: virtual void map_mmio(uint64_t address, size_t size, mmio_read_callback read_cb, mmio_write_callback write_cb) = 0; diff --git a/src/windows-emulator/memory_manager.cpp b/src/windows-emulator/memory_manager.cpp index 2b91105f..76422e02 100644 --- a/src/windows-emulator/memory_manager.cpp +++ b/src/windows-emulator/memory_manager.cpp @@ -649,6 +649,11 @@ void memory_manager::write_memory(const uint64_t address, const void* data, cons this->memory_->write_memory(address, data, size); } +bool memory_manager::try_write_memory(const uint64_t address, const void* data, const size_t size) +{ + return this->memory_->try_write_memory(address, data, size); +} + void memory_manager::map_mmio(const uint64_t address, const size_t size, mmio_read_callback read_cb, mmio_write_callback write_cb) { this->memory_->map_mmio(address, size, std::move(read_cb), std::move(write_cb)); diff --git a/src/windows-emulator/memory_manager.hpp b/src/windows-emulator/memory_manager.hpp index 44900aba..c7c3ea8f 100644 --- a/src/windows-emulator/memory_manager.hpp +++ b/src/windows-emulator/memory_manager.hpp @@ -65,6 +65,7 @@ class memory_manager : public memory_interface void read_memory(uint64_t address, void* data, size_t size) const final; bool try_read_memory(uint64_t address, void* data, size_t size) const final; void write_memory(uint64_t address, const void* data, size_t size) final; + bool try_write_memory(uint64_t address, const void* data, size_t size) final; bool protect_memory(uint64_t address, size_t size, nt_memory_permission permissions, nt_memory_permission* old_permissions = nullptr); From c3464dd5c3dc6dce9818964d40e6e1e86a3f1859 Mon Sep 17 00:00:00 2001 From: 66hh <49398720+66hh@users.noreply.github.com> Date: Sun, 28 Dec 2025 19:40:53 +0800 Subject: [PATCH 10/22] Introduce try_read/try_write for emulator_object --- src/windows-emulator/emulator_utils.hpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/windows-emulator/emulator_utils.hpp b/src/windows-emulator/emulator_utils.hpp index f8737ff6..c1f992fc 100644 --- a/src/windows-emulator/emulator_utils.hpp +++ b/src/windows-emulator/emulator_utils.hpp @@ -104,6 +104,16 @@ class emulator_object return this->address_ != 0; } + std::optional try_read(const size_t index = 0) const + { + T obj{}; + if (this->memory_->try_read_memory(this->address_ + index * this->size(), &obj, sizeof(obj))) + { + return obj; + } + return std::nullopt; + } + T read(const size_t index = 0) const { T obj{}; @@ -111,6 +121,11 @@ class emulator_object return obj; } + bool try_write(const T& value, const size_t index = 0) const + { + return this->memory_->try_write_memory(this->address_ + index * this->size(), &value, sizeof(value)); + } + void write(const T& value, const size_t index = 0) const { this->memory_->write_memory(this->address_ + index * this->size(), &value, sizeof(value)); From 41b86f655b8422218ced906002ee96aea09bb660 Mon Sep 17 00:00:00 2001 From: 66hh <49398720+66hh@users.noreply.github.com> Date: Sun, 28 Dec 2025 19:44:02 +0800 Subject: [PATCH 11/22] Replace write with try_write in the handle_query function --- src/windows-emulator/syscall_utils.hpp | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/windows-emulator/syscall_utils.hpp b/src/windows-emulator/syscall_utils.hpp index 67660fa6..564bea14 100644 --- a/src/windows-emulator/syscall_utils.hpp +++ b/src/windows-emulator/syscall_utils.hpp @@ -232,17 +232,7 @@ NTSTATUS handle_query(x86_64_emulator& emu, const uint64_t buffer, const uint32_ const auto length_setter = [&](const size_t required_size) { if (return_length) { - try - { - // VMProtect is trying to pass an incorrect return address. - // This can run on the original version of Windows, but in - // the emulator, this will cause an exception. - return_length.write(static_cast(required_size)); - } - catch (...) - { - - } + return_length.try_write(static_cast(required_size)); } }; From 418c5abf4919f786dfaad4b9c5974a034af877e9 Mon Sep 17 00:00:00 2001 From: 66hh <49398720+66hh@users.noreply.github.com> Date: Sun, 28 Dec 2025 19:51:45 +0800 Subject: [PATCH 12/22] Extract callback handling into a separate function --- src/windows-emulator/syscall_dispatcher.cpp | 31 +++++++++++++-------- src/windows-emulator/syscall_dispatcher.hpp | 1 + 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/windows-emulator/syscall_dispatcher.cpp b/src/windows-emulator/syscall_dispatcher.cpp index 4aabed1c..21284ca5 100644 --- a/src/windows-emulator/syscall_dispatcher.cpp +++ b/src/windows-emulator/syscall_dispatcher.cpp @@ -102,18 +102,7 @@ void syscall_dispatcher::dispatch(windows_emulator& win_emu) entry->second.handler(c); - if (context.instrumentation_callback != 0 && entry->second.name != "NtContinue") - { - uint64_t rip_old = emu.reg(x86_register::rip); - - // The increase in RIP caused by executing the syscall here has not yet occurred. - // If RIP is set directly, it will lead to an incorrect address, so the length of - // the syscall instruction needs to be subtracted. - emu.reg(x86_register::rip, context.instrumentation_callback - 2); - - emu.reg(x86_register::r10, rip_old); - } - + dispatch_callback(win_emu, entry->second.name); } catch (std::exception& e) { @@ -129,6 +118,24 @@ void syscall_dispatcher::dispatch(windows_emulator& win_emu) } } +void syscall_dispatcher::dispatch_callback(windows_emulator& win_emu, std::string syscall_name) +{ + auto& emu = win_emu.emu(); + auto& context = win_emu.process; + + if (context.instrumentation_callback != 0 && syscall_name != "NtContinue") + { + uint64_t rip_old = emu.reg(x86_register::rip); + + // The increase in RIP caused by executing the syscall here has not yet occurred. + // If RIP is set directly, it will lead to an incorrect address, so the length of + // the syscall instruction needs to be subtracted. + emu.reg(x86_register::rip, context.instrumentation_callback - 2); + + emu.reg(x86_register::r10, rip_old); + } +} + syscall_dispatcher::syscall_dispatcher(const exported_symbols& ntdll_exports, const std::span ntdll_data, const exported_symbols& win32u_exports, const std::span win32u_data) { diff --git a/src/windows-emulator/syscall_dispatcher.hpp b/src/windows-emulator/syscall_dispatcher.hpp index d8c80374..f80f947c 100644 --- a/src/windows-emulator/syscall_dispatcher.hpp +++ b/src/windows-emulator/syscall_dispatcher.hpp @@ -21,6 +21,7 @@ class syscall_dispatcher std::span win32u_data); void dispatch(windows_emulator& win_emu); + void dispatch_callback(windows_emulator& win_emu, std::string syscall_name); void serialize(utils::buffer_serializer& buffer) const; void deserialize(utils::buffer_deserializer& buffer); From 83d4cadf76ee21e9973424be825407e60de21ea0 Mon Sep 17 00:00:00 2001 From: 66hh <49398720+66hh@users.noreply.github.com> Date: Sun, 28 Dec 2025 20:48:26 +0800 Subject: [PATCH 13/22] Modify memory API implementation --- src/windows-emulator/syscalls/memory.cpp | 41 +++++++++++++++++++++--- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/src/windows-emulator/syscalls/memory.cpp b/src/windows-emulator/syscalls/memory.cpp index 52e95445..64e6799b 100644 --- a/src/windows-emulator/syscalls/memory.cpp +++ b/src/windows-emulator/syscalls/memory.cpp @@ -29,7 +29,9 @@ namespace syscalls return STATUS_INVALID_PARAMETER; } - if (info_class == MemoryBasicInformation) + // https://www.exploit-db.com/exploits/44464 + // Both information classes appear to return the same output structure, MEMORY_BASIC_INFORMATION + if (info_class == MemoryBasicInformation || info_class == MemoryPrivilegedBasicInformation) { if (return_length) { @@ -290,7 +292,7 @@ namespace syscalls const emulator_pointer buffer, const ULONG number_of_bytes_to_read, const emulator_object number_of_bytes_read) { - number_of_bytes_read.write(0); + number_of_bytes_read.try_write(0); if (process_handle != CURRENT_PROCESS) { @@ -305,8 +307,39 @@ namespace syscalls return STATUS_INVALID_ADDRESS; } - c.emu.write_memory(buffer, memory.data(), memory.size()); - number_of_bytes_read.write(number_of_bytes_to_read); + if (!c.emu.try_write_memory(buffer, memory.data(), memory.size())) + { + return STATUS_INVALID_ADDRESS; + } + number_of_bytes_read.try_write(number_of_bytes_to_read); + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtWriteVirtualMemory(const syscall_context& c, const handle process_handle, const emulator_pointer base_address, + const emulator_pointer buffer, const ULONG number_of_bytes_to_write, + const emulator_object number_of_bytes_write) + { + number_of_bytes_write.try_write(0); + + if (process_handle != CURRENT_PROCESS) + { + return STATUS_NOT_SUPPORTED; + } + + std::vector memory{}; + memory.resize(number_of_bytes_to_write); + + if (!c.emu.try_read_memory(buffer, &memory, number_of_bytes_to_write)) + { + return STATUS_INVALID_ADDRESS; + } + + if (!c.emu.try_write_memory(base_address, memory.data(), memory.size())) + { + return STATUS_INVALID_ADDRESS; + } + + number_of_bytes_write.try_write(number_of_bytes_to_write); return STATUS_SUCCESS; } From 478fb7b4dd3fdc2aeac4f3451fb564aec06f602e Mon Sep 17 00:00:00 2001 From: 66hh <49398720+66hh@users.noreply.github.com> Date: Sun, 28 Dec 2025 20:52:43 +0800 Subject: [PATCH 14/22] Register NtWriteVirtualMemory --- src/windows-emulator/syscalls.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 311ec6e9..11f36905 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -131,6 +131,9 @@ namespace syscalls NTSTATUS handle_NtReadVirtualMemory(const syscall_context& c, handle process_handle, emulator_pointer base_address, emulator_pointer buffer, ULONG number_of_bytes_to_read, emulator_object number_of_bytes_read); + NTSTATUS handle_NtWriteVirtualMemory(const syscall_context& c, const handle process_handle, const emulator_pointer base_address, + const emulator_pointer buffer, const ULONG number_of_bytes_to_write, + const emulator_object number_of_bytes_write); NTSTATUS handle_NtSetInformationVirtualMemory(); BOOL handle_NtLockVirtualMemory(); @@ -1094,6 +1097,7 @@ void syscall_dispatcher::add_handlers(std::map& ha add_handler(NtCreateSemaphore); add_handler(NtOpenSemaphore); add_handler(NtReadVirtualMemory); + add_handler(NtWriteVirtualMemory); add_handler(NtQueryInformationToken); add_handler(NtDxgkIsFeatureEnabled); add_handler(NtAddAtomEx); From 1c119217011483cab34fa8296888d068d3d21318 Mon Sep 17 00:00:00 2001 From: 66hh <49398720+66hh@users.noreply.github.com> Date: Sun, 28 Dec 2025 23:45:52 +0800 Subject: [PATCH 15/22] Add error handling to prevent the engine from throwing errors --- src/windows-emulator/memory_manager.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/windows-emulator/memory_manager.cpp b/src/windows-emulator/memory_manager.cpp index 76422e02..125a40b9 100644 --- a/src/windows-emulator/memory_manager.cpp +++ b/src/windows-emulator/memory_manager.cpp @@ -641,7 +641,14 @@ void memory_manager::read_memory(const uint64_t address, void* data, const size_ bool memory_manager::try_read_memory(const uint64_t address, void* data, const size_t size) const { - return this->memory_->try_read_memory(address, data, size); + try + { + return this->memory_->try_read_memory(address, data, size); + } + catch (...) + { + return false; + } } void memory_manager::write_memory(const uint64_t address, const void* data, const size_t size) @@ -651,7 +658,14 @@ void memory_manager::write_memory(const uint64_t address, const void* data, cons bool memory_manager::try_write_memory(const uint64_t address, const void* data, const size_t size) { - return this->memory_->try_write_memory(address, data, size); + try + { + return this->memory_->try_write_memory(address, data, size); + } + catch (...) + { + return false; + } } void memory_manager::map_mmio(const uint64_t address, const size_t size, mmio_read_callback read_cb, mmio_write_callback write_cb) From 12e96c89215af211995135f27093aa1cd5a04700 Mon Sep 17 00:00:00 2001 From: 66hh <49398720+66hh@users.noreply.github.com> Date: Mon, 29 Dec 2025 00:31:49 +0800 Subject: [PATCH 16/22] Adjust memory allocation method --- src/windows-emulator/syscalls/memory.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/windows-emulator/syscalls/memory.cpp b/src/windows-emulator/syscalls/memory.cpp index 64e6799b..ee1b5460 100644 --- a/src/windows-emulator/syscalls/memory.cpp +++ b/src/windows-emulator/syscalls/memory.cpp @@ -299,18 +299,20 @@ namespace syscalls return STATUS_NOT_SUPPORTED; } - std::vector memory{}; - memory.resize(number_of_bytes_to_read); + uint8_t* memory = new uint8_t[number_of_bytes_to_read]; - if (!c.emu.try_read_memory(base_address, memory.data(), memory.size())) + if (!c.emu.try_read_memory(base_address, memory, number_of_bytes_to_read)) { return STATUS_INVALID_ADDRESS; } - if (!c.emu.try_write_memory(buffer, memory.data(), memory.size())) + if (!c.emu.try_write_memory(buffer, memory, number_of_bytes_to_read)) { return STATUS_INVALID_ADDRESS; } + + delete[] memory; + number_of_bytes_read.try_write(number_of_bytes_to_read); return STATUS_SUCCESS; } @@ -326,19 +328,20 @@ namespace syscalls return STATUS_NOT_SUPPORTED; } - std::vector memory{}; - memory.resize(number_of_bytes_to_write); + uint8_t* memory = new uint8_t[number_of_bytes_to_write]; - if (!c.emu.try_read_memory(buffer, &memory, number_of_bytes_to_write)) + if (!c.emu.try_read_memory(buffer, memory, number_of_bytes_to_write)) { return STATUS_INVALID_ADDRESS; } - if (!c.emu.try_write_memory(base_address, memory.data(), memory.size())) + if (!c.emu.try_write_memory(base_address, memory, number_of_bytes_to_write)) { return STATUS_INVALID_ADDRESS; } + delete[] memory; + number_of_bytes_write.try_write(number_of_bytes_to_write); return STATUS_SUCCESS; } From 3cd461e2abe643143aa5466d204a70719b0ad53b Mon Sep 17 00:00:00 2001 From: 66hh <49398720+66hh@users.noreply.github.com> Date: Mon, 29 Dec 2025 00:52:59 +0800 Subject: [PATCH 17/22] Add the debugger_hide attribute to emulator_thread --- src/windows-emulator/emulator_thread.hpp | 6 ++++++ src/windows-emulator/syscalls/thread.cpp | 5 ++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/windows-emulator/emulator_thread.hpp b/src/windows-emulator/emulator_thread.hpp index 4f14aa7a..d80f2556 100644 --- a/src/windows-emulator/emulator_thread.hpp +++ b/src/windows-emulator/emulator_thread.hpp @@ -102,6 +102,8 @@ class emulator_thread : public ref_counted_object std::vector last_registers{}; + bool debugger_hide{false}; + void mark_as_ready(NTSTATUS status); bool is_await_time_over(utils::clock& clock) const @@ -180,6 +182,8 @@ class emulator_thread : public ref_counted_object buffer.write_optional(this->wow64_cpu_reserved); buffer.write_vector(this->last_registers); + + buffer.write(this->debugger_hide); } void deserialize_object(utils::buffer_deserializer& buffer) override @@ -225,6 +229,8 @@ class emulator_thread : public ref_counted_object buffer.read_optional(this->wow64_cpu_reserved, [this] { return emulator_object(*this->memory_ptr); }); buffer.read_vector(this->last_registers); + + buffer.read(this->debugger_hide); } void leak_memory() diff --git a/src/windows-emulator/syscalls/thread.cpp b/src/windows-emulator/syscalls/thread.cpp index ffd9120b..e4991bdc 100644 --- a/src/windows-emulator/syscalls/thread.cpp +++ b/src/windows-emulator/syscalls/thread.cpp @@ -58,6 +58,7 @@ namespace syscalls if (info_class == ThreadHideFromDebugger) { + c.win_emu.current_thread().debugger_hide = true; c.win_emu.callbacks.on_suspicious_activity("Hiding thread from debugger"); return STATUS_SUCCESS; } @@ -276,8 +277,10 @@ namespace syscalls return STATUS_BUFFER_OVERFLOW; } + emulator_thread& thread = c.win_emu.current_thread(); + const emulator_object info{c.emu, thread_information}; - info.write(0); + info.write(thread.debugger_hide); return STATUS_SUCCESS; } From 536f2ce883a03d5d18444e91dd15245cae978798 Mon Sep 17 00:00:00 2001 From: 66hh <49398720+66hh@users.noreply.github.com> Date: Mon, 29 Dec 2025 00:54:31 +0800 Subject: [PATCH 18/22] Adjust variable order --- src/windows-emulator/syscalls/thread.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/windows-emulator/syscalls/thread.cpp b/src/windows-emulator/syscalls/thread.cpp index e4991bdc..49d8c4dc 100644 --- a/src/windows-emulator/syscalls/thread.cpp +++ b/src/windows-emulator/syscalls/thread.cpp @@ -135,6 +135,8 @@ namespace syscalls return STATUS_INVALID_HANDLE; } + emulator_thread& cur_emulator_thread = c.win_emu.current_thread(); + if (info_class == ThreadWow64Context) { // ThreadWow64Context is only valid for WOW64 processes @@ -277,10 +279,8 @@ namespace syscalls return STATUS_BUFFER_OVERFLOW; } - emulator_thread& thread = c.win_emu.current_thread(); - const emulator_object info{c.emu, thread_information}; - info.write(thread.debugger_hide); + info.write(cur_emulator_thread.debugger_hide); return STATUS_SUCCESS; } From c144f2f43899da5d8941cfc55af25fcda51b05e1 Mon Sep 17 00:00:00 2001 From: 66hh <49398720+66hh@users.noreply.github.com> Date: Tue, 30 Dec 2025 17:05:08 +0800 Subject: [PATCH 19/22] Adjust memory allocation method --- src/windows-emulator/syscalls/memory.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/windows-emulator/syscalls/memory.cpp b/src/windows-emulator/syscalls/memory.cpp index ee1b5460..705c2efd 100644 --- a/src/windows-emulator/syscalls/memory.cpp +++ b/src/windows-emulator/syscalls/memory.cpp @@ -299,20 +299,18 @@ namespace syscalls return STATUS_NOT_SUPPORTED; } - uint8_t* memory = new uint8_t[number_of_bytes_to_read]; + std::vector memory(number_of_bytes_to_read, 0); - if (!c.emu.try_read_memory(base_address, memory, number_of_bytes_to_read)) + if (!c.emu.try_read_memory(base_address, memory.data(), number_of_bytes_to_read)) { return STATUS_INVALID_ADDRESS; } - if (!c.emu.try_write_memory(buffer, memory, number_of_bytes_to_read)) + if (!c.emu.try_write_memory(buffer, memory.data(), number_of_bytes_to_read)) { return STATUS_INVALID_ADDRESS; } - delete[] memory; - number_of_bytes_read.try_write(number_of_bytes_to_read); return STATUS_SUCCESS; } @@ -328,20 +326,18 @@ namespace syscalls return STATUS_NOT_SUPPORTED; } - uint8_t* memory = new uint8_t[number_of_bytes_to_write]; + std::vector memory(number_of_bytes_to_write, 0); - if (!c.emu.try_read_memory(buffer, memory, number_of_bytes_to_write)) + if (!c.emu.try_read_memory(buffer, memory.data(), number_of_bytes_to_write)) { return STATUS_INVALID_ADDRESS; } - if (!c.emu.try_write_memory(base_address, memory, number_of_bytes_to_write)) + if (!c.emu.try_write_memory(base_address, memory.data(), number_of_bytes_to_write)) { return STATUS_INVALID_ADDRESS; } - delete[] memory; - number_of_bytes_write.try_write(number_of_bytes_to_write); return STATUS_SUCCESS; } From d830bea3c5ad3ceffbb41af9327b72eb85a95524 Mon Sep 17 00:00:00 2001 From: 66hh <49398720+66hh@users.noreply.github.com> Date: Tue, 30 Dec 2025 17:40:16 +0800 Subject: [PATCH 20/22] Try to fix the build --- src/windows-emulator/syscalls/exception.cpp | 5 ++--- src/windows-emulator/syscalls/object.cpp | 1 - src/windows-emulator/syscalls/process.cpp | 1 - 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/windows-emulator/syscalls/exception.cpp b/src/windows-emulator/syscalls/exception.cpp index fab2d2ee..eb652179 100644 --- a/src/windows-emulator/syscalls/exception.cpp +++ b/src/windows-emulator/syscalls/exception.cpp @@ -5,8 +5,7 @@ namespace syscalls { NTSTATUS handle_NtRaiseHardError(const syscall_context& c, const NTSTATUS error_status, const ULONG number_of_parameters, - const emulator_object>> - /*unicode_string_parameter_mask*/, + const emulator_object>> /*unicode_string_parameter_mask*/, const uint64_t parameters, const HARDERROR_RESPONSE_OPTION /*valid_response_option*/, const emulator_object response) { @@ -17,7 +16,7 @@ namespace syscalls if (error_status & STATUS_SERVICE_NOTIFICATION && number_of_parameters >= 3) { - ULONG_PTR params[3] = {0, 0, 0}; + uint64_t params[3] = {0, 0, 0}; if (c.emu.try_read_memory(parameters, ¶ms, sizeof(params))) { diff --git a/src/windows-emulator/syscalls/object.cpp b/src/windows-emulator/syscalls/object.cpp index 74201e67..1d474ffe 100644 --- a/src/windows-emulator/syscalls/object.cpp +++ b/src/windows-emulator/syscalls/object.cpp @@ -6,7 +6,6 @@ namespace syscalls { NTSTATUS handle_NtClose(const syscall_context& c, const handle h) { - const auto value = h.value; if (h.h == 0xDEADC0DE) diff --git a/src/windows-emulator/syscalls/process.cpp b/src/windows-emulator/syscalls/process.cpp index 0f2b7342..edb18355 100644 --- a/src/windows-emulator/syscalls/process.cpp +++ b/src/windows-emulator/syscalls/process.cpp @@ -283,7 +283,6 @@ namespace syscalls if (info_class == ProcessInstrumentationCallback) { - if (process_information_length != sizeof(PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION)) { return STATUS_BUFFER_OVERFLOW; From 0521fdef7d1315688a033f9b973f87843bf5720b Mon Sep 17 00:00:00 2001 From: 66hh <49398720+66hh@users.noreply.github.com> Date: Tue, 30 Dec 2025 18:50:59 +0800 Subject: [PATCH 21/22] Fix code formatting issues --- src/windows-emulator/syscall_dispatcher.cpp | 4 ++-- src/windows-emulator/syscall_dispatcher.hpp | 2 +- src/windows-emulator/syscalls/exception.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/windows-emulator/syscall_dispatcher.cpp b/src/windows-emulator/syscall_dispatcher.cpp index 21284ca5..31489191 100644 --- a/src/windows-emulator/syscall_dispatcher.cpp +++ b/src/windows-emulator/syscall_dispatcher.cpp @@ -118,14 +118,14 @@ void syscall_dispatcher::dispatch(windows_emulator& win_emu) } } -void syscall_dispatcher::dispatch_callback(windows_emulator& win_emu, std::string syscall_name) +void syscall_dispatcher::dispatch_callback(windows_emulator& win_emu, std::string& syscall_name) { auto& emu = win_emu.emu(); auto& context = win_emu.process; if (context.instrumentation_callback != 0 && syscall_name != "NtContinue") { - uint64_t rip_old = emu.reg(x86_register::rip); + auto rip_old = emu.reg(x86_register::rip); // The increase in RIP caused by executing the syscall here has not yet occurred. // If RIP is set directly, it will lead to an incorrect address, so the length of diff --git a/src/windows-emulator/syscall_dispatcher.hpp b/src/windows-emulator/syscall_dispatcher.hpp index f80f947c..3078eb34 100644 --- a/src/windows-emulator/syscall_dispatcher.hpp +++ b/src/windows-emulator/syscall_dispatcher.hpp @@ -21,7 +21,7 @@ class syscall_dispatcher std::span win32u_data); void dispatch(windows_emulator& win_emu); - void dispatch_callback(windows_emulator& win_emu, std::string syscall_name); + static void dispatch_callback(windows_emulator& win_emu, std::string& syscall_name); void serialize(utils::buffer_serializer& buffer) const; void deserialize(utils::buffer_deserializer& buffer); diff --git a/src/windows-emulator/syscalls/exception.cpp b/src/windows-emulator/syscalls/exception.cpp index eb652179..e2f2847d 100644 --- a/src/windows-emulator/syscalls/exception.cpp +++ b/src/windows-emulator/syscalls/exception.cpp @@ -16,7 +16,7 @@ namespace syscalls if (error_status & STATUS_SERVICE_NOTIFICATION && number_of_parameters >= 3) { - uint64_t params[3] = {0, 0, 0}; + std::array params = {0, 0, 0}; if (c.emu.try_read_memory(parameters, ¶ms, sizeof(params))) { From 82dff75f642c262aaf0bc191fbe05b0b4112fbf9 Mon Sep 17 00:00:00 2001 From: 66hh <49398720+66hh@users.noreply.github.com> Date: Tue, 30 Dec 2025 19:22:10 +0800 Subject: [PATCH 22/22] Fix the formatting again --- src/windows-emulator/syscalls.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 11f36905..9ee433c0 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -131,9 +131,9 @@ namespace syscalls NTSTATUS handle_NtReadVirtualMemory(const syscall_context& c, handle process_handle, emulator_pointer base_address, emulator_pointer buffer, ULONG number_of_bytes_to_read, emulator_object number_of_bytes_read); - NTSTATUS handle_NtWriteVirtualMemory(const syscall_context& c, const handle process_handle, const emulator_pointer base_address, - const emulator_pointer buffer, const ULONG number_of_bytes_to_write, - const emulator_object number_of_bytes_write); + NTSTATUS handle_NtWriteVirtualMemory(const syscall_context& c, handle process_handle, emulator_pointer base_address, + emulator_pointer buffer, ULONG number_of_bytes_to_write, + emulator_object number_of_bytes_write); NTSTATUS handle_NtSetInformationVirtualMemory(); BOOL handle_NtLockVirtualMemory();