From 022ed7280795d87f9f52b2fa728f556f3be351e8 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Thu, 2 Jan 2025 12:13:53 +0100 Subject: [PATCH 1/5] Fix syscall mappings --- src/windows-emulator/syscall_dispatcher.cpp | 17 ++--- src/windows-emulator/syscall_dispatcher.hpp | 6 +- src/windows-emulator/syscall_utils.hpp | 73 ++++++++++++++------- src/windows-emulator/syscalls.cpp | 10 ++- src/windows-emulator/windows_emulator.cpp | 5 +- 5 files changed, 74 insertions(+), 37 deletions(-) diff --git a/src/windows-emulator/syscall_dispatcher.cpp b/src/windows-emulator/syscall_dispatcher.cpp index 0b8ab978..bb73546e 100644 --- a/src/windows-emulator/syscall_dispatcher.cpp +++ b/src/windows-emulator/syscall_dispatcher.cpp @@ -24,15 +24,16 @@ void syscall_dispatcher::deserialize(utils::buffer_deserializer& buffer) } -void syscall_dispatcher::setup(const exported_symbols& ntdll_exports, const exported_symbols& win32u_exports) +void syscall_dispatcher::setup(const exported_symbols& ntdll_exports, std::span ntdll_data, + const exported_symbols& win32u_exports, std::span win32u_data) { this->handlers_ = {}; - const auto ntdll_syscalls = find_syscalls(ntdll_exports); - const auto win32u_syscalls = find_syscalls(win32u_exports); + const auto ntdll_syscalls = find_syscalls(ntdll_exports, ntdll_data); + const auto win32u_syscalls = find_syscalls(win32u_exports, win32u_data); - map_syscalls(this->handlers_, ntdll_syscalls, 0); - map_syscalls(this->handlers_, win32u_syscalls, 0x1000); + map_syscalls(this->handlers_, ntdll_syscalls); + map_syscalls(this->handlers_, win32u_syscalls); this->add_handlers(); } @@ -121,8 +122,8 @@ void syscall_dispatcher::dispatch(windows_emulator& win_emu) } } -syscall_dispatcher::syscall_dispatcher(const exported_symbols& ntdll_exports, - const exported_symbols& win32u_exports) +syscall_dispatcher::syscall_dispatcher(const exported_symbols& ntdll_exports, std::span ntdll_data, + const exported_symbols& win32u_exports, std::span win32u_data) { - this->setup(ntdll_exports, win32u_exports); + this->setup(ntdll_exports, ntdll_data, win32u_exports, win32u_data); } diff --git a/src/windows-emulator/syscall_dispatcher.hpp b/src/windows-emulator/syscall_dispatcher.hpp index ac5fc439..23a5185e 100644 --- a/src/windows-emulator/syscall_dispatcher.hpp +++ b/src/windows-emulator/syscall_dispatcher.hpp @@ -17,14 +17,16 @@ class syscall_dispatcher { public: syscall_dispatcher() = default; - syscall_dispatcher(const exported_symbols& ntdll_exports, const exported_symbols& win32u_exports); + syscall_dispatcher(const exported_symbols& ntdll_exports, std::span ntdll_data, + const exported_symbols& win32u_exports, std::span win32u_data); void dispatch(windows_emulator& win_emu); void serialize(utils::buffer_serializer& buffer) const; void deserialize(utils::buffer_deserializer& buffer); - void setup(const exported_symbols& ntdll_exports, const exported_symbols& win32u_exports); + void setup(const exported_symbols& ntdll_exports, std::span ntdll_data, + const exported_symbols& win32u_exports, std::span win32u_data); std::string get_syscall_name(const uint64_t id) { diff --git a/src/windows-emulator/syscall_utils.hpp b/src/windows-emulator/syscall_utils.hpp index 3f0b5650..902ecebb 100644 --- a/src/windows-emulator/syscall_utils.hpp +++ b/src/windows-emulator/syscall_utils.hpp @@ -38,32 +38,51 @@ inline bool is_syscall(const std::string_view name) return name.starts_with("Nt") && name.size() > 3 && is_uppercase(name[2]); } -inline std::vector find_syscalls(const exported_symbols& exports) +inline std::optional extract_syscall_id(const exported_symbol& symbol, std::span data) { - // Makes use of the fact that order of Nt* function addresses - // is equal to the order of syscall IDs. - // So first Nt* function is the first syscall with ID 0 + if (!is_syscall(symbol.name)) + { + return std::nullopt; + } - std::map reference_count{}; - std::map ordered_syscalls{}; + constexpr auto instruction_size = 5; + constexpr auto instruction_offset = 3; + constexpr auto instruction_operand_offset = 1; + constexpr auto instruction_opcode = static_cast(0xB8); + + const auto instruction_rva = symbol.rva + instruction_offset; + + if (data.size() < (instruction_rva + instruction_size) || data[instruction_rva] != instruction_opcode) + { + return std::nullopt; + } + + uint32_t syscall_id{0}; + static_assert(sizeof(syscall_id) <= (instruction_size - instruction_operand_offset)); + memcpy(&syscall_id, data.data() + instruction_rva + instruction_operand_offset, sizeof(syscall_id)); + + return syscall_id; +} + +inline std::map find_syscalls(const exported_symbols& exports, std::span data) +{ + std::map syscalls{}; for (const auto& symbol : exports) { - if (is_syscall(symbol.name)) + const auto id = extract_syscall_id(symbol, data); + if (id) { - ++reference_count[symbol.address]; - ordered_syscalls[symbol.address] = symbol.name; - } - } + auto& entry = syscalls[*id]; - std::vector syscalls{}; - syscalls.reserve(ordered_syscalls.size()); + if (!entry.empty()) + { + throw std::runtime_error( + "Syscall with id " + std::to_string(*id) + ", which is mapping to " + symbol.name + + ", was already mapped to " + entry); + } - for (auto& syscall : ordered_syscalls) - { - if (reference_count[syscall.first] == 1) - { - syscalls.push_back(std::move(syscall.second)); + entry = symbol.name; } } @@ -71,14 +90,20 @@ inline std::vector find_syscalls(const exported_symbols& exports) } inline void map_syscalls(std::map& handlers, - const std::vector& syscalls, const uint64_t base_index) + std::map syscalls) { - for (size_t i = 0; i < syscalls.size(); ++i) + for (auto& [id, name] : syscalls) { - const auto& syscall = syscalls[i]; + auto& entry = handlers[id]; - auto& entry = handlers[base_index + i]; - entry.name = syscall; + if (!entry.name.empty()) + { + throw std::runtime_error( + "Syscall with id " + std::to_string(id) + ", which is mapping to " + name + + ", was previously mapped to " + entry.name); + } + + entry.name = std::move(name); entry.handler = nullptr; } } @@ -249,4 +274,4 @@ inline LARGE_INTEGER convert_unix_to_windows_time(const __time64_t unix_time) LARGE_INTEGER windows_time{}; windows_time.QuadPart = (unix_time + EPOCH_DIFFERENCE_1601_TO_1970_SECONDS) * HUNDRED_NANOSECONDS_IN_ONE_SECOND; return windows_time; -} \ No newline at end of file +} diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 18650957..5602dcc2 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -2462,7 +2462,7 @@ namespace return STATUS_NOT_SUPPORTED; } - NTSTATUS handle_NtGdiInit2(const syscall_context& c) + NTSTATUS handle_NtGdiInit(const syscall_context& c) { c.proc.peb.access([&](PEB& peb) { @@ -2472,7 +2472,12 @@ namespace } }); - return STATUS_NOT_SUPPORTED; + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtGdiInit2(const syscall_context& c) + { + return handle_NtGdiInit(c); } NTSTATUS handle_NtGetMUIRegistryInfo() @@ -3402,6 +3407,7 @@ void syscall_dispatcher::add_handlers(std::map& ha add_handler(NtQueryInformationThread); add_handler(NtQueryWnfStateNameInformation); add_handler(NtAlpcSendWaitReceivePort); + add_handler(NtGdiInit); add_handler(NtGdiInit2); add_handler(NtUserGetThreadState); add_handler(NtOpenKeyEx); diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index 2591bf30..15192570 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -753,7 +753,10 @@ void windows_emulator::setup_process(const emulator_settings& settings) context.ntdll = context.module_manager.map_module(R"(C:\Windows\System32\ntdll.dll)", this->logger); context.win32u = context.module_manager.map_module(R"(C:\Windows\System32\win32u.dll)", this->logger); - this->dispatcher_.setup(context.ntdll->exports, context.win32u->exports); + const auto ntdll_data = emu.read_memory(context.ntdll->image_base, context.ntdll->size_of_image); + const auto win32u_data = emu.read_memory(context.win32u->image_base, context.win32u->size_of_image); + + this->dispatcher_.setup(context.ntdll->exports, ntdll_data, context.win32u->exports, win32u_data); context.ldr_initialize_thunk = context.ntdll->find_export("LdrInitializeThunk"); context.rtl_user_thread_start = context.ntdll->find_export("RtlUserThreadStart"); From 39398750c376180686fdfc6cbee7505741897025 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Thu, 2 Jan 2025 13:36:21 +0100 Subject: [PATCH 2/5] Log caller for syscalls --- src/windows-emulator/syscall_dispatcher.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/windows-emulator/syscall_dispatcher.cpp b/src/windows-emulator/syscall_dispatcher.cpp index bb73546e..2ad6bd54 100644 --- a/src/windows-emulator/syscall_dispatcher.cpp +++ b/src/windows-emulator/syscall_dispatcher.cpp @@ -100,10 +100,13 @@ void syscall_dispatcher::dispatch(windows_emulator& win_emu) } else { - win_emu.logger.print(color::dark_gray, "Executing syscall: %s (0x%X) at 0x%llX\n", + const auto rsp = c.emu.read_stack_pointer(); + const auto return_address = c.emu.read_memory(rsp); + const auto* mod_name = context.module_manager.find_name(return_address); + + win_emu.logger.print(color::dark_gray, "Executing syscall: %s (0x%X) at 0x%llX via %llX (%s)\n", entry->second.name.c_str(), - syscall_id, - address); + syscall_id, address, return_address, mod_name); } entry->second.handler(c); From 300bdaa7e23213c4dee626be3150245d43649d86 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Thu, 2 Jan 2025 13:50:07 +0100 Subject: [PATCH 3/5] Fix error status --- src/windows-emulator/syscalls.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 5602dcc2..bdc73726 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -2937,7 +2937,7 @@ namespace response.write(ResponseAbort); } - printf("Hard error: %X\n", static_cast(error_status)); + c.proc.exit_status = error_status; c.proc.exception_rip = c.emu.read_instruction_pointer(); c.emu.stop(); From ce38a393ab272c0b5db9ba68fe95dad1c2e355ac Mon Sep 17 00:00:00 2001 From: momo5502 Date: Thu, 2 Jan 2025 13:50:16 +0100 Subject: [PATCH 4/5] Fix gdi init stati --- src/windows-emulator/syscalls.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index bdc73726..0f0e4458 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -2472,12 +2472,13 @@ namespace } }); - return STATUS_SUCCESS; + return STATUS_WAIT_1; } NTSTATUS handle_NtGdiInit2(const syscall_context& c) { - return handle_NtGdiInit(c); + handle_NtGdiInit(c); + return STATUS_NOT_SUPPORTED; } NTSTATUS handle_NtGetMUIRegistryInfo() From 95df4a9c593779229bdad54e17d89e392738a3c6 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Thu, 2 Jan 2025 13:50:30 +0100 Subject: [PATCH 5/5] Fix TLS vector updates --- src/windows-emulator/syscalls.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 0f0e4458..1e2cffd0 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -1761,9 +1761,8 @@ namespace { const auto new_tls_vector = entry.TlsVector; - for (uint32_t j = 1; j < tls_info.TlsVectorLength; ++j) + for (uint32_t index = 0; index < tls_info.TlsVectorLength; ++index) { - const auto index = j - 1; const auto old_entry = c.emu.read_memory(tls_vector + index); c.emu.write_memory(new_tls_vector + index, old_entry); }