From 6d84604c825deef0b254b4e0f4c0336047042a25 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Fri, 13 Sep 2024 11:13:35 +0200 Subject: [PATCH] Support serializing syscall handlers --- src/windows_emulator/syscalls.cpp | 117 +++++++++++++++++++++++++----- src/windows_emulator/syscalls.hpp | 5 ++ 2 files changed, 102 insertions(+), 20 deletions(-) diff --git a/src/windows_emulator/syscalls.cpp b/src/windows_emulator/syscalls.cpp index efec9c0..fa76106 100644 --- a/src/windows_emulator/syscalls.cpp +++ b/src/windows_emulator/syscalls.cpp @@ -76,6 +76,19 @@ namespace return syscalls; } + void map_syscalls(std::unordered_map& handlers, + const std::vector& syscalls, const uint64_t base_index) + { + for (size_t i = 0; i < syscalls.size(); ++i) + { + const auto& syscall = syscalls[i]; + + auto& entry = handlers[base_index + i]; + entry.name = syscall; + entry.handler = nullptr; + } + } + uint64_t get_syscall_id(const std::vector& ntdll_syscalls, const std::vector& win32u_syscalls, const std::string_view name) { @@ -156,7 +169,7 @@ namespace } } - void forward(const syscall_context& c, NTSTATUS (*handler)()) + void forward_syscall(const syscall_context& c, NTSTATUS (*handler)()) { const auto ip = c.emu.read_instruction_pointer(); @@ -165,7 +178,7 @@ namespace } template - void forward(const syscall_context& c, NTSTATUS (*handler)(const syscall_context&, Args...)) + void forward_syscall(const syscall_context& c, NTSTATUS (*handler)(const syscall_context&, Args...)) { const auto ip = c.emu.read_instruction_pointer(); @@ -180,6 +193,15 @@ namespace write_status(c, ret, ip); } + template + syscall_handler make_syscall_handler() + { + return +[](const syscall_context& c) + { + forward_syscall(c, Handler); + }; + } + NTSTATUS handle_NtQueryPerformanceCounter(const syscall_context&, const emulator_object performance_counter, const emulator_object performance_frequency) @@ -1560,22 +1582,26 @@ syscall_dispatcher::syscall_dispatcher(const exported_symbols& ntdll_exports, co const auto ntdll_syscalls = find_syscalls(ntdll_exports); const auto win32u_syscalls = find_syscalls(win32u_exports); -#define add_handler(syscall) do \ - { \ - std::string name = #syscall; \ - const auto id = get_syscall_id(ntdll_syscalls, win32u_syscalls, name); \ - auto handler = +[](const syscall_context& c) \ - { \ - forward(c, handle_ ## syscall); \ - }; \ - \ - syscall_handler_entry entry{}; \ - entry.handler = handler; \ - entry.name = std::move(name); \ - this->handlers_[id] = std::move(entry); \ + map_syscalls(this->handlers_, ntdll_syscalls, 0); + map_syscalls(this->handlers_, win32u_syscalls, 0x1000); + + this->add_handlers(); +} + +void syscall_dispatcher::add_handlers() +{ + std::unordered_map handler_mapping{}; + handler_mapping.reserve(this->handlers_.size()); + + make_syscall_handler(); + +#define add_handler(syscall) \ + do \ + { \ + handler_mapping[#syscall] = make_syscall_handler(); \ } while(0) - add_handler(NtSetInformationThread); + add_handler(NtSetInformationThread) ; add_handler(NtSetEvent); add_handler(NtClose); add_handler(NtOpenKey); @@ -1630,6 +1656,50 @@ syscall_dispatcher::syscall_dispatcher(const exported_symbols& ntdll_exports, co add_handler(NtAlpcSendWaitReceivePort); #undef add_handler + + for (auto& entry : this->handlers_) + { + const auto handler = handler_mapping.find(entry.second.name); + if (handler == handler_mapping.end()) + { + continue; + } + + entry.second.handler = handler->second; + +#ifndef NDEBUG + handler_mapping.erase(handler); +#endif + } + +#ifndef NDEBUG + if(!handler_mapping.empty()) + { + throw std::runtime_error("Unmapped handlers!"); + } +#endif +} + +static void serialize(utils::buffer_serializer& buffer, const syscall_handler_entry& obj) +{ + buffer.write(obj.name); +} + +static void deserialize(utils::buffer_deserializer& buffer, syscall_handler_entry& obj) +{ + buffer.read(obj.name); + obj.handler = nullptr; +} + +void syscall_dispatcher::serialize(utils::buffer_serializer& buffer) const +{ + buffer.write_map(this->handlers_); +} + +void syscall_dispatcher::deserialize(utils::buffer_deserializer& buffer) +{ + buffer.read_map(this->handlers_); + this->add_handlers(); } void syscall_dispatcher::dispatch(x64_emulator& emu, process_context& context) @@ -1645,15 +1715,22 @@ void syscall_dispatcher::dispatch(x64_emulator& emu, process_context& context) const auto entry = this->handlers_.find(syscall_id); if (entry == this->handlers_.end()) { - printf("Unhandled syscall: %X\n", syscall_id); + printf("Unknown syscall: %X\n", syscall_id); c.emu.reg(x64_register::rax, STATUS_NOT_SUPPORTED); c.emu.stop(); + return; } - else + + if (!entry->second.handler) { - printf("Handling syscall: %s with id %X at %llX \n", entry->second.name.c_str(), syscall_id, address); - entry->second.handler(c); + printf("Unimplemented syscall: %s - %X\n", entry->second.name.c_str(), syscall_id); + c.emu.reg(x64_register::rax, STATUS_NOT_SUPPORTED); + c.emu.stop(); + return; } + + printf("Handling syscall: %s with id %X at %llX \n", entry->second.name.c_str(), syscall_id, address); + entry->second.handler(c); } catch (std::exception& e) { diff --git a/src/windows_emulator/syscalls.hpp b/src/windows_emulator/syscalls.hpp index 543703f..0b29050 100644 --- a/src/windows_emulator/syscalls.hpp +++ b/src/windows_emulator/syscalls.hpp @@ -20,6 +20,11 @@ class syscall_dispatcher void dispatch(x64_emulator& emu, process_context& context); + void serialize(utils::buffer_serializer& buffer) const; + void deserialize(utils::buffer_deserializer& buffer); + private: std::unordered_map handlers_{}; + + void add_handlers(); };