From 5160bacd1e84269b4c164010bb69709603746f74 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Fri, 24 Jan 2025 11:58:35 +0100 Subject: [PATCH 01/32] Correctly handle existing objects --- src/windows-emulator/syscalls.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 69448eff..c4c5d4e5 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -477,10 +477,12 @@ namespace if (!name.empty()) { - for (const auto& mutant : c.proc.mutants | std::views::values) + for (auto& entry : c.proc.mutants) { - if (mutant.name == name) + if (entry.second.name == name) { + ++entry.second.ref_count; + mutant_handle.write(c.proc.mutants.make_handle(entry.first)); return STATUS_OBJECT_NAME_EXISTS; } } @@ -518,10 +520,12 @@ namespace if (!name.empty()) { - for (const auto& event : c.proc.events | std::views::values) + for (auto& entry : c.proc.events) { - if (event.name == name) + if (entry.second.name == name) { + ++entry.second.ref_count; + event_handle.write(c.proc.events.make_handle(entry.first)); return STATUS_OBJECT_NAME_EXISTS; } } @@ -3037,10 +3041,12 @@ namespace if (!s.name.empty()) { - for (const auto& semaphore : c.proc.semaphores | std::views::values) + for (auto& entry : c.proc.semaphores) { - if (semaphore.name == s.name) + if (entry.second.name == s.name) { + ++entry.second.ref_count; + semaphore_handle.write(c.proc.semaphores.make_handle(entry.first)); return STATUS_OBJECT_NAME_EXISTS; } } From 32d91bd1394ef7e3312e9630f64d225de0b47dd7 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Fri, 24 Jan 2025 13:00:06 +0100 Subject: [PATCH 02/32] Fix semaphores and mutexes --- src/common/platform/status.hpp | 2 ++ src/windows-emulator/handles.hpp | 2 ++ src/windows-emulator/process_context.hpp | 35 ++++++++++++++++--- src/windows-emulator/syscalls.cpp | 42 ++++++++++++++++++++--- src/windows-emulator/windows_emulator.cpp | 15 ++++++++ 5 files changed, 87 insertions(+), 9 deletions(-) diff --git a/src/common/platform/status.hpp b/src/common/platform/status.hpp index 9469bce4..59fbd48a 100644 --- a/src/common/platform/status.hpp +++ b/src/common/platform/status.hpp @@ -31,6 +31,8 @@ using NTSTATUS = std::uint32_t; #define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L) #define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L) #define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS)0xC0000034L) +#define STATUS_MUTANT_NOT_OWNED ((NTSTATUS)0xC0000046L) +#define STATUS_SEMAPHORE_LIMIT_EXCEEDED ((NTSTATUS)0xC0000047L) #define STATUS_NO_TOKEN ((NTSTATUS)0xC000007CL) #define STATUS_FILE_INVALID ((NTSTATUS)0xC0000098L) #define STATUS_MEMORY_NOT_ALLOCATED ((NTSTATUS)0xC00000A0L) diff --git a/src/windows-emulator/handles.hpp b/src/windows-emulator/handles.hpp index cc99ac0d..87b5045d 100644 --- a/src/windows-emulator/handles.hpp +++ b/src/windows-emulator/handles.hpp @@ -354,6 +354,8 @@ constexpr auto BASE_NAMED_OBJECTS_DIRECTORY = make_pseudo_handle(0x2, handle_typ constexpr auto KNOWN_DLLS_SYMLINK = make_pseudo_handle(0x1, handle_types::symlink); constexpr auto SHARED_SECTION = make_pseudo_handle(0x1, handle_types::section); +constexpr auto WER_PORT_READY = make_pseudo_handle(0x1, handle_types::event); + constexpr auto CONSOLE_HANDLE = make_pseudo_handle(0x1, handle_types::file); constexpr auto STDOUT_HANDLE = make_pseudo_handle(0x2, handle_types::file); constexpr auto STDIN_HANDLE = make_pseudo_handle(0x3, handle_types::file); diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index 52002de2..ac236691 100644 --- a/src/windows-emulator/process_context.hpp +++ b/src/windows-emulator/process_context.hpp @@ -108,17 +108,17 @@ struct mutant : ref_counted_object return true; } - uint32_t release() + std::pair release(const uint32_t thread_id) { const auto old_count = this->locked_count; - if (this->locked_count <= 0) + if (this->locked_count <= 0 || this->owning_thread_id != thread_id) { - return old_count; + return {old_count, false}; } --this->locked_count; - return old_count; + return {old_count, true}; } void serialize(utils::buffer_serializer& buffer) const @@ -239,9 +239,34 @@ struct section struct semaphore : ref_counted_object { std::u16string name{}; - volatile uint32_t current_count{}; + uint32_t current_count{}; uint32_t max_count{}; + bool try_lock() + { + if (this->current_count > 0) + { + --this->current_count; + return true; + } + + return false; + } + + std::pair release(const uint32_t release_count) + { + const auto old_count = this->current_count; + + if (this->current_count + release_count > this->max_count) + { + return {old_count, false}; + } + + this->current_count += release_count; + + return {old_count, true}; + } + void serialize(utils::buffer_serializer& buffer) const { buffer.write(this->name); diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index c4c5d4e5..a171cc7e 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -449,14 +449,14 @@ namespace return STATUS_INVALID_HANDLE; } - const auto old_count = mutant->release(); + const auto [old_count, succeeded] = mutant->release(c.proc.current_thread_id); if (previous_count) { previous_count.write(static_cast(old_count)); } - return STATUS_SUCCESS; + return succeeded ? STATUS_SUCCESS : STATUS_MUTANT_NOT_OWNED; } NTSTATUS handle_NtCreateMutant(const syscall_context& c, const emulator_object mutant_handle, @@ -553,6 +553,12 @@ namespace const auto name = read_unicode_string(c.emu, reinterpret_cast>*>(attributes.ObjectName)); + if (name == u"\\KernelObjects\\SystemErrorPortReady") + { + event_handle.write(WER_PORT_READY.bits); + return STATUS_SUCCESS; + } + for (auto& entry : c.proc.events) { if (entry.second.name == name) @@ -3020,6 +3026,32 @@ namespace return STATUS_OBJECT_NAME_NOT_FOUND; } + NTSTATUS handle_NtReleaseSemaphore(const syscall_context& c, const handle semaphore_handle, + const ULONG release_count, const emulator_object previous_count) + { + if (semaphore_handle.value.type != handle_types::semaphore) + { + c.win_emu.log.error("Bad handle type for NtReleaseSemaphore\n"); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + auto* mutant = c.proc.semaphores.get(semaphore_handle); + if (!mutant) + { + return STATUS_INVALID_HANDLE; + } + + const auto [old_count, succeeded] = mutant->release(release_count); + + if (previous_count) + { + previous_count.write(static_cast(old_count)); + } + + return succeeded ? STATUS_SUCCESS : STATUS_SEMAPHORE_LIMIT_EXCEEDED; + } + NTSTATUS handle_NtCreateSemaphore(const syscall_context& c, const emulator_object semaphore_handle, const ACCESS_MASK /*desired_access*/, const emulator_object>> object_attributes, @@ -3222,8 +3254,9 @@ namespace bool is_awaitable_object_type(const handle h) { - return h.value.type == handle_types::thread // - || h.value.type == handle_types::mutant // + return h.value.type == handle_types::thread // + || h.value.type == handle_types::mutant // + || h.value.type == handle_types::semaphore // || h.value.type == handle_types::event; } @@ -3537,6 +3570,7 @@ void syscall_dispatcher::add_handlers(std::map& ha add_handler(NtUserModifyUserStartupInfoFlags); add_handler(NtUserGetDCEx); add_handler(NtUserGetDpiForCurrentProcess); + add_handler(NtReleaseSemaphore); #undef add_handler } diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index e7f7500c..8de08a77 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -634,6 +634,11 @@ namespace break; case handle_types::event: { + if (h.value.is_pseudo) + { + return true; + } + auto* e = c.events.get(h); if (e) { @@ -653,6 +658,16 @@ namespace break; } + case handle_types::semaphore: { + auto* s = c.semaphores.get(h); + if (s) + { + return s->try_lock(); + } + + break; + } + case handle_types::thread: { const auto* t = c.threads.get(h); if (t) From f23fe935c16192ed0174b3076703c1f95f5f38d7 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Fri, 24 Jan 2025 13:22:26 +0100 Subject: [PATCH 03/32] Fix handle closing --- src/windows-emulator/handles.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/windows-emulator/handles.hpp b/src/windows-emulator/handles.hpp index 87b5045d..7f0eca2e 100644 --- a/src/windows-emulator/handles.hpp +++ b/src/windows-emulator/handles.hpp @@ -114,7 +114,7 @@ namespace handle_detail struct generic_handle_store { virtual ~generic_handle_store() = default; - virtual bool erase(const handle h) = 0; + virtual bool erase(handle h) = 0; }; template @@ -205,7 +205,7 @@ class handle_store : public generic_handle_store { if (!T::deleter(entry->second)) { - return false; + return true; } } From 0698120c718dc4a76163d543c63c1488e4ce8f35 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Fri, 24 Jan 2025 13:22:33 +0100 Subject: [PATCH 04/32] Log caller --- src/windows-emulator/windows_emulator.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index 8de08a77..9e23500c 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -945,9 +945,13 @@ void windows_emulator::on_instruction_execution(const uint64_t address) const auto export_entry = binary->address_names.find(address); if (export_entry != binary->address_names.end()) { + const auto rsp = this->emu().read_stack_pointer(); + const auto return_address = this->emu().read_memory(rsp); + const auto* mod_name = this->process().mod_manager.find_name(return_address); + log.print(is_interesting_call ? color::yellow : color::dark_gray, - "Executing function: %s - %s (0x%" PRIx64 ")\n", binary->name.c_str(), - export_entry->second.c_str(), address); + "Executing function: %s - %s (0x%" PRIx64 ") via (0x%" PRIx64 ") %s\n", binary->name.c_str(), + export_entry->second.c_str(), address, return_address, mod_name); } else if (address == binary->entry_point) { From e175c83e25e57a6e189ec8a0002672cfc24ee4e2 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Fri, 24 Jan 2025 15:52:34 +0100 Subject: [PATCH 05/32] Support verbose logging --- src/analyzer/main.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/analyzer/main.cpp b/src/analyzer/main.cpp index 9b9adea2..6576e6ee 100644 --- a/src/analyzer/main.cpp +++ b/src/analyzer/main.cpp @@ -11,6 +11,7 @@ namespace { bool use_gdb{false}; bool concise_logging{false}; + bool verbose_logging{false}; std::string registry_path{"./registry"}; }; @@ -200,6 +201,10 @@ namespace { options.use_gdb = true; } + else if (arg == "-v") + { + options.verbose_logging = true; + } else if (arg == "-c") { options.concise_logging = true; From df089e9e086bce09161eb7ab512417eab78cd387 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Fri, 24 Jan 2025 15:52:45 +0100 Subject: [PATCH 06/32] Fix current thread id --- 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 a171cc7e..7e74672b 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -449,7 +449,7 @@ namespace return STATUS_INVALID_HANDLE; } - const auto [old_count, succeeded] = mutant->release(c.proc.current_thread_id); + const auto [old_count, succeeded] = mutant->release(c.win_emu.current_thread().id); if (previous_count) { From 885496825658c7a8f6274dffbda6ecf0078fe348 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Fri, 24 Jan 2025 15:53:01 +0100 Subject: [PATCH 07/32] Rename spawned thread count to prevent confusion --- src/windows-emulator/process_context.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index ac236691..3c58fe38 100644 --- a/src/windows-emulator/process_context.hpp +++ b/src/windows-emulator/process_context.hpp @@ -575,7 +575,7 @@ struct process_context std::vector default_register_set{}; - uint32_t current_thread_id{0}; + uint32_t spawned_thread_count{0}; handle_store threads{}; emulator_thread* active_thread{nullptr}; @@ -612,7 +612,7 @@ struct process_context buffer.write_map(this->atoms); buffer.write_vector(this->default_register_set); - buffer.write(this->current_thread_id); + buffer.write(this->spawned_thread_count); buffer.write(this->threads); buffer.write(this->threads.find_handle(this->active_thread).bits); @@ -655,7 +655,7 @@ struct process_context buffer.read_map(this->atoms); buffer.read_vector(this->default_register_set); - buffer.read(this->current_thread_id); + buffer.read(this->spawned_thread_count); buffer.read(this->threads); @@ -665,7 +665,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, *this, start_address, argument, stack_size, ++this->current_thread_id}; + emulator_thread t{emu, *this, start_address, argument, stack_size, ++this->spawned_thread_count}; return this->threads.store(std::move(t)); } }; From 739cbbf5494e7691d8e362debfc78a1c6ec4bda2 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Fri, 24 Jan 2025 16:16:50 +0100 Subject: [PATCH 08/32] Fix verbose logging --- src/analyzer/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analyzer/main.cpp b/src/analyzer/main.cpp index 6576e6ee..083cbf6b 100644 --- a/src/analyzer/main.cpp +++ b/src/analyzer/main.cpp @@ -117,7 +117,7 @@ namespace (void)&watch_system_objects; watch_system_objects(win_emu, options.concise_logging); win_emu.buffer_stdout = true; - // win_emu.verbose_calls = true; + win_emu.verbose_calls = options.verbose_logging; const auto& exe = *win_emu.process().executable; From 24bebc4ee24e28129ca69f796320dba3619dbec9 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Tue, 21 Jan 2025 18:00:11 +0100 Subject: [PATCH 09/32] Prepare filesystem support --- src/common/platform/unicode.hpp | 9 +- src/common/utils/path_key.hpp | 5 +- src/tools/collect-dlls.bat | 1 + src/windows-emulator/file_system.cpp | 1 + src/windows-emulator/file_system.hpp | 85 +++++++++++++++++++ .../module/module_manager.cpp | 33 +++---- .../module/module_manager.hpp | 10 ++- src/windows-emulator/process_context.hpp | 4 +- src/windows-emulator/syscalls.cpp | 11 +-- src/windows-emulator/windows_emulator.cpp | 34 ++++---- src/windows-emulator/windows_emulator.hpp | 5 +- 11 files changed, 145 insertions(+), 53 deletions(-) create mode 100644 src/windows-emulator/file_system.cpp create mode 100644 src/windows-emulator/file_system.hpp diff --git a/src/common/platform/unicode.hpp b/src/common/platform/unicode.hpp index d506ab6c..b5a895e1 100644 --- a/src/common/platform/unicode.hpp +++ b/src/common/platform/unicode.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include template struct UNICODE_STRING @@ -62,9 +63,9 @@ inline std::string w_to_u8(const std::wstring_view w_view) } #ifndef OS_WINDOWS -inline int open_unicode(FILE** handle, const std::u16string& fileName, const std::u16string& mode) +inline int open_unicode(FILE** handle, const std::filesystem::path& fileName, const std::u16string& mode) { - *handle = fopen(u16_to_u8(fileName).c_str(), u16_to_u8(mode).c_str()); + *handle = fopen(fileName.string().c_str(), u16_to_u8(mode).c_str()); return errno; } #else @@ -73,8 +74,8 @@ inline std::wstring u16_to_w(const std::u16string& u16str) return std::wstring(reinterpret_cast(u16str.data()), u16str.size()); } -inline auto open_unicode(FILE** handle, const std::u16string& fileName, const std::u16string& mode) +inline auto open_unicode(FILE** handle, const std::filesystem::path& fileName, const std::u16string& mode) { - return _wfopen_s(handle, u16_to_w(fileName).c_str(), u16_to_w(mode).c_str()); + return _wfopen_s(handle, fileName.wstring().c_str(), u16_to_w(mode).c_str()); } #endif diff --git a/src/common/utils/path_key.hpp b/src/common/utils/path_key.hpp index 6165393e..b45163f5 100644 --- a/src/common/utils/path_key.hpp +++ b/src/common/utils/path_key.hpp @@ -39,7 +39,10 @@ namespace utils static std::filesystem::path canonicalize_path(const std::filesystem::path& key) { - auto path = key.lexically_normal().wstring(); + auto key_string = key.u16string(); + std::ranges::replace(key_string, u'\\', '/'); + + auto path = std::filesystem::path(key).lexically_normal().wstring(); return utils::string::to_lower_consume(path); } diff --git a/src/tools/collect-dlls.bat b/src/tools/collect-dlls.bat index b4803989..6aa107c9 100644 --- a/src/tools/collect-dlls.bat +++ b/src/tools/collect-dlls.bat @@ -60,6 +60,7 @@ CALL :collect_dll wininet.dll CALL :collect_dll winmm.dll CALL :collect_dll ws2_32.dll CALL :collect_dll wsock32.dll +CALL :collect_dll msvcp140.dll CALL :collect_dll locale.nls diff --git a/src/windows-emulator/file_system.cpp b/src/windows-emulator/file_system.cpp new file mode 100644 index 00000000..e9125080 --- /dev/null +++ b/src/windows-emulator/file_system.cpp @@ -0,0 +1 @@ +#include "std_include.hpp" diff --git a/src/windows-emulator/file_system.hpp b/src/windows-emulator/file_system.hpp new file mode 100644 index 00000000..77d8ba07 --- /dev/null +++ b/src/windows-emulator/file_system.hpp @@ -0,0 +1,85 @@ +#pragma once +#include "std_include.hpp" +#include + +class file_system +{ + public: + static constexpr std::u16string_view nt_prefix = u"\\??\\"; + + file_system(std::filesystem::path root, std::u16string working_dir) + : root_(std::move(root)), + working_dir_(std::move(working_dir)) + { + } + + static std::filesystem::path canonicalize_windows_path(const std::filesystem::path& file) + { + const auto wide_file = file.u16string(); + + if (!wide_file.starts_with(nt_prefix)) + { + return file; + } + + return canonicalize_windows_path(wide_file.substr(nt_prefix.size())); + } + + static std::filesystem::path canonicalize(const std::filesystem::path& path) + { + return utils::path_key::canonicalize_path(canonicalize_windows_path(path)); + } + + static std::filesystem::path canonicalize_drive_letter(const std::filesystem::path& path) + { + auto canonical_path = canonicalize(path); + if (canonical_path.empty() || !path.has_root_path()) + { + return canonical_path; + } + + return adapt_drive_component(canonical_path); + } + + std::filesystem::path translate(const std::filesystem::path& win_path) const + { + const auto absolute_win_dir = make_absolute_windows_path(win_path.u16string()); + return this->root_ / canonicalize_drive_letter(absolute_win_dir); + } + + void set_working_directory(std::u16string working_dir) + { + this->working_dir_ = std::move(working_dir); + } + + const std::u16string& get_working_directory() const + { + return this->working_dir_; + } + + private: + std::filesystem::path root_; + std::u16string working_dir_; + + std::u16string make_absolute_windows_path(const std::u16string& path) const + { + if (!path.starts_with(nt_prefix) && (path.size() < 2 || path[1] != ':')) + { + return this->working_dir_ + u'/' + path; + } + + return path; + } + + static std::filesystem::path adapt_drive_component(const std::filesystem::path& original_path) + { + auto root_name = original_path.root_name().u16string(); + + if (!root_name.empty() && root_name.back() == u':') + { + root_name.pop_back(); + } + + return root_name + original_path.root_directory().u16string() + original_path.relative_path().u16string(); + } +}; diff --git a/src/windows-emulator/module/module_manager.cpp b/src/windows-emulator/module/module_manager.cpp index 71baf230..0f73ae5c 100644 --- a/src/windows-emulator/module/module_manager.cpp +++ b/src/windows-emulator/module/module_manager.cpp @@ -5,18 +5,7 @@ namespace { - std::filesystem::path canonicalize_module_path(const std::filesystem::path& file) - { - constexpr std::u16string_view nt_prefix = u"\\??\\"; - const auto wide_file = file.u16string(); - - if (!wide_file.starts_with(nt_prefix)) - { - return canonical(absolute(file)); - } - return canonicalize_module_path(wide_file.substr(nt_prefix.size())); - } } namespace utils @@ -64,26 +53,32 @@ namespace utils } } -module_manager::module_manager(emulator& emu) - : emu_(&emu) +module_manager::module_manager(emulator& emu, file_system& file_sys) + : emu_(&emu), + file_sys_(&file_sys) +{ +} + +mapped_module* module_manager::map_module(const std::filesystem::path& file, const logger& logger) { + return this->map_local_module(this->file_sys_->translate(file), logger); } -mapped_module* module_manager::map_module(const std::filesystem::path& file, logger& logger) +mapped_module* module_manager::map_local_module(const std::filesystem::path& file, const logger& logger) { - auto canonical_file = canonicalize_module_path(file); + auto local_file = canonical(absolute(file)); - for (auto& mod : this->modules_) + for (auto& mod : this->modules_ | std::views::values) { - if (mod.second.path == canonical_file) + if (mod.path == file) { - return &mod.second; + return &mod; } } try { - auto mod = map_module_from_file(*this->emu_, std::move(canonical_file)); + auto mod = map_module_from_file(*this->emu_, std::move(local_file)); logger.log("Mapped %s at 0x%" PRIx64 "\n", mod.path.generic_string().c_str(), mod.image_base); diff --git a/src/windows-emulator/module/module_manager.hpp b/src/windows-emulator/module/module_manager.hpp index 8fc19377..2f298954 100644 --- a/src/windows-emulator/module/module_manager.hpp +++ b/src/windows-emulator/module/module_manager.hpp @@ -1,16 +1,19 @@ #pragma once -#include "mapped_module.hpp" #include +#include "mapped_module.hpp" +#include "../file_system.hpp" + class logger; class module_manager { public: using module_map = std::map; - module_manager(emulator& emu); + module_manager(emulator& emu, file_system& file_sys); - mapped_module* map_module(const std::filesystem::path& file, logger& logger); + mapped_module* map_module(const std::filesystem::path& file, const logger& logger); + mapped_module* map_local_module(const std::filesystem::path& file, const logger& logger); mapped_module* find_by_address(const uint64_t address) { @@ -45,6 +48,7 @@ class module_manager private: emulator* emu_{}; + file_system* file_sys_{}; module_map modules_{}; diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index 3c58fe38..0a544474 100644 --- a/src/windows-emulator/process_context.hpp +++ b/src/windows-emulator/process_context.hpp @@ -529,12 +529,12 @@ class emulator_thread : ref_counted_object struct process_context { - process_context(x64_emulator& emu) + process_context(x64_emulator& emu, file_system& file_sys) : base_allocator(emu), peb(emu), process_params(emu), kusd(emu, *this), - mod_manager(emu) + mod_manager(emu, file_sys) { } diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 7e74672b..88b4063d 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -1530,7 +1530,7 @@ namespace if (!f->enumeration_state || query_flags & SL_RESTART_SCAN) { f->enumeration_state.emplace(file_enumeration_state{}); - f->enumeration_state->files = scan_directory(f->name); + f->enumeration_state->files = scan_directory(c.win_emu.file_sys.translate(f->name)); } auto& enum_state = *f->enumeration_state; @@ -2585,7 +2585,8 @@ namespace const emulator_object default_locale_id, const emulator_object /*default_casing_table_size*/) { - const auto locale_file = utils::io::read_file(R"(C:\Windows\System32\locale.nls)"); + const auto locale_file = + utils::io::read_file(c.win_emu.file_sys.translate(R"(C:\Windows\System32\locale.nls)")); if (locale_file.empty()) { return STATUS_FILE_INVALID; @@ -2825,14 +2826,14 @@ namespace if (create_disposition & FILE_CREATE) { std::error_code ec{}; - std::filesystem::create_directory(f.name, ec); + std::filesystem::create_directory(c.win_emu.file_sys.translate(f.name), ec); if (ec) { return STATUS_ACCESS_DENIED; } } - else if (!std::filesystem::is_directory(f.name)) + else if (!std::filesystem::is_directory(c.win_emu.file_sys.translate(f.name))) { return STATUS_OBJECT_NAME_NOT_FOUND; } @@ -2854,7 +2855,7 @@ namespace FILE* file{}; - const auto error = open_unicode(&file, f.name, mode); + const auto error = open_unicode(&file, c.win_emu.file_sys.translate(f.name), mode); if (!file) { diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index 9e23500c..3a1eb75e 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -268,18 +268,9 @@ namespace command_line.append(arg); } - std::u16string current_folder{}; - if (!settings.working_directory.empty()) - { - current_folder = canonicalize_path(settings.working_directory).u16string() + u"\\"; - } - else - { - current_folder = canonicalize_path(settings.application).parent_path().u16string() + u"\\"; - } - allocator.make_unicode_string(proc_params.CommandLine, command_line); - allocator.make_unicode_string(proc_params.CurrentDirectory.DosPath, current_folder); + allocator.make_unicode_string(proc_params.CurrentDirectory.DosPath, + win_emu.file_sys.get_working_directory()); allocator.make_unicode_string(proc_params.ImagePathName, canonicalize_path(settings.application).u16string()); @@ -831,10 +822,15 @@ std::unique_ptr create_default_x64_emulator() return unicorn::create_x64_emulator(); } -windows_emulator::windows_emulator(emulator_settings settings, emulator_callbacks callbacks, +windows_emulator::windows_emulator(const emulator_settings& settings, emulator_callbacks callbacks, std::unique_ptr emu) : windows_emulator(std::move(emu)) { + if (!settings.working_directory.empty()) + { + this->file_sys.set_working_directory(settings.working_directory.u16string()); + } + this->silent_until_main_ = settings.silent_until_main && !settings.disable_logging; this->use_relative_time_ = settings.use_relative_time; this->log.disable_output(settings.disable_logging || this->silent_until_main_); @@ -843,8 +839,9 @@ windows_emulator::windows_emulator(emulator_settings settings, emulator_callback } windows_emulator::windows_emulator(std::unique_ptr emu) - : emu_(std::move(emu)), - process_(*emu_) + : file_sys(R"(C:\Users\mahe.WIBU\Desktop\emulator\src\tools\root)", u"C:\\"), + emu_(std::move(emu)), + process_(*emu_, file_sys) { this->setup_hooks(); } @@ -854,14 +851,15 @@ void windows_emulator::setup_process(const emulator_settings& settings) auto& emu = this->emu(); auto& context = this->process(); - context.mod_manager = module_manager(emu); // TODO: Cleanup module manager + context.mod_manager = module_manager(emu, this->file_sys); // TODO: Cleanup module manager setup_context(*this, settings); - context.executable = context.mod_manager.map_module(settings.application, this->log); + context.executable = context.mod_manager.map_local_module(settings.application, this->log); - context.peb.access( - [&](PEB64& peb) { peb.ImageBaseAddress = reinterpret_cast(context.executable->image_base); }); + context.peb.access([&](PEB64& peb) { + peb.ImageBaseAddress = reinterpret_cast(context.executable->image_base); // + }); context.ntdll = context.mod_manager.map_module(R"(C:\Windows\System32\ntdll.dll)", this->log); context.win32u = context.mod_manager.map_module(R"(C:\Windows\System32\win32u.dll)", this->log); diff --git a/src/windows-emulator/windows_emulator.hpp b/src/windows-emulator/windows_emulator.hpp index 2f524a07..0839db3a 100644 --- a/src/windows-emulator/windows_emulator.hpp +++ b/src/windows-emulator/windows_emulator.hpp @@ -8,6 +8,7 @@ #include "syscall_dispatcher.hpp" #include "process_context.hpp" #include "logger.hpp" +#include "file_system.hpp" std::unique_ptr create_default_x64_emulator(); @@ -47,7 +48,7 @@ class windows_emulator { public: windows_emulator(std::unique_ptr emu = create_default_x64_emulator()); - windows_emulator(emulator_settings settings, emulator_callbacks callbacks = {}, + windows_emulator(const emulator_settings& settings, emulator_callbacks callbacks = {}, std::unique_ptr emu = create_default_x64_emulator()); windows_emulator(windows_emulator&&) = delete; @@ -130,6 +131,8 @@ class windows_emulator { return this->callbacks_; } + + file_system file_sys; private: emulator_callbacks callbacks_{}; From 77cb4d18ff9a5c60fa822f9ac45040eb47efece7 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Tue, 21 Jan 2025 19:25:59 +0100 Subject: [PATCH 10/32] Add script to create root folder --- .../{collect-dlls.bat => create-root.bat} | 37 ++++++++++++------- 1 file changed, 24 insertions(+), 13 deletions(-) rename src/tools/{collect-dlls.bat => create-root.bat} (70%) diff --git a/src/tools/collect-dlls.bat b/src/tools/create-root.bat similarity index 70% rename from src/tools/collect-dlls.bat rename to src/tools/create-root.bat index 6aa107c9..65ca8f5d 100644 --- a/src/tools/collect-dlls.bat +++ b/src/tools/create-root.bat @@ -1,16 +1,30 @@ @ECHO OFF -:: Host system directories +NET SESSIONS > NUL 2>&1 +IF %ERRORLEVEL% NEQ 0 ( + ECHO Error: This script requires administrative privileges. + EXIT /B 1 +) + SET SYSDIR="%WINDIR%\System32" :: Qiling rootfs directories -SET QL_WINDIR="Windows" -SET QL_SYSDIR="%QL_WINDIR%\System32" +SET EMU_ROOT=root +SET EMU_FILESYS=%EMU_ROOT%\filesys +SET EMU_WINDIR=%EMU_FILESYS%\c\windows +SET EMU_SYSDIR=%EMU_WINDIR%\system32 +SET EMU_REGDIR=%EMU_ROOT%\registry -MKDIR %QL_WINDIR% -MKDIR %QL_SYSDIR% +MKDIR %EMU_SYSDIR% +MKDIR %EMU_REGDIR% + +REG SAVE HKLM\SYSTEM %EMU_REGDIR%\SYSTEM /Y +REG SAVE HKLM\SECURITY %EMU_REGDIR%\SECURITY /Y +REG SAVE HKLM\SOFTWARE %EMU_REGDIR%\SOFTWARE /Y +REG SAVE HKLM\HARDWARE %EMU_REGDIR%\HARDWARE /Y +REG SAVE HKLM\SAM %EMU_REGDIR%\SAM /Y +COPY /B /Y C:\Users\Default\NTUSER.DAT "%EMU_REGDIR%\NTUSER.DAT" -:: Collect 32-bit DLL files CALL :collect_dll advapi32.dll CALL :collect_dll bcrypt.dll CALL :collect_dll cfgmgr32.dll @@ -25,12 +39,12 @@ CALL :collect_dll hal.dll CALL :collect_dll iphlpapi.dll CALL :collect_dll kdcom.dll CALL :collect_dll kernel32.dll -CALL :collect_dll KernelBase.dll +CALL :collect_dll kernelbase.dll CALL :collect_dll mpr.dll CALL :collect_dll mscoree.dll CALL :collect_dll msvcp_win.dll CALL :collect_dll msvcp60.dll -CALL :collect_dll msvcr120_clr0400.dll, msvcr110.dll +CALL :collect_dll msvcr120_clr0400.dll CALL :collect_dll msvcrt.dll CALL :collect_dll netapi32.dll CALL :collect_dll ntdll.dll @@ -64,9 +78,6 @@ CALL :collect_dll msvcp140.dll CALL :collect_dll locale.nls -:: Collect extras -CALL :collect %SYSDIR64%, ntoskrnl.exe, %QL_SYSDIR32% - :: All done! EXIT /B 0 @@ -77,7 +88,7 @@ EXIT /B :collect CALL :normpath SRC, %~1\%~2 -CALL :normpath DST, %~3\%~4 +CALL :normpath DST, %~3\%~2 IF EXIST %SRC% ( ECHO %SRC% -^> %DST% @@ -86,5 +97,5 @@ IF EXIST %SRC% ( EXIT /B :collect_dll -CALL :collect %SYSDIR%, %~1, %QL_SYSDIR%, %~2 +CALL :collect %SYSDIR%, %~1, %EMU_SYSDIR% EXIT /B From 64e21ff5d28123c7e86c88e4edf488899cd5ce40 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Tue, 21 Jan 2025 19:29:48 +0100 Subject: [PATCH 11/32] Add root dumping to workflow --- .github/workflows/build.yml | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 22422081..3aa8f2ff 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -28,22 +28,40 @@ jobs: clang-format-version: '19' check-path: 'src' - dump-registry: - name: Dump Registry - runs-on: windows-latest + + dump-root: + name: Dump Root FS + runs-on: ${{ matrix.runner }} + strategy: + fail-fast: false + matrix: + platform: + - Windows 2025 + - Windows 2022 + - Windows 2019 + include: + - platform: Windows 2025 + build-platform: Windows + runner: windows-2025 + - platform: Windows 2022 + build-platform: Windows + runner: windows-2022 + - platform: Windows 2019 + build-platform: Windows + runner: windows-2019 steps: - name: Checkout Source uses: actions/checkout@v4 - - name: Dump Registry - run: src/tools/grab-registry.bat + - name: Dump Root FS + run: src/tools/create-root.bat - name: Upload Artifacts uses: actions/upload-artifact@v4 with: - name: Temp Registry Dump + name: Temp ${{ matrix.platform }} Root FS path: | - registry/* + root/* build: name: Build @@ -144,7 +162,7 @@ jobs: test: name: Test runs-on: ${{ matrix.runner }} - needs: [dump-registry, build] + needs: [dump-root, build] strategy: fail-fast: false matrix: @@ -215,7 +233,7 @@ jobs: summary: name: Pipeline Summary runs-on: ubuntu-24.04 - needs: [dump-registry, build, test, verify-formatting] + needs: [dump-root, build, test, verify-formatting] if: always() steps: - uses: geekyeggo/delete-artifact@v5 From e15bb33e10dbc8ba79ee1c4420252db7ce894ed2 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Tue, 21 Jan 2025 19:36:58 +0100 Subject: [PATCH 12/32] Dump API set --- .github/workflows/build.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3aa8f2ff..68fbf6dc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -32,6 +32,7 @@ jobs: dump-root: name: Dump Root FS runs-on: ${{ matrix.runner }} + needs: [build] strategy: fail-fast: false matrix: @@ -53,9 +54,18 @@ jobs: - name: Checkout Source uses: actions/checkout@v4 + - name: Download Windows Artifacts + uses: actions/download-artifact@v4 + with: + name: Windows Release Artifacts + path: build/release/artifacts + - name: Dump Root FS run: src/tools/create-root.bat + - name: Dump API Set + run: cd root && ../build/release/artifacts/dump-apiset.exe + - name: Upload Artifacts uses: actions/upload-artifact@v4 with: From b581d7443353a475dd527b7426f3ae48235eeea2 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Tue, 21 Jan 2025 19:55:57 +0100 Subject: [PATCH 13/32] Fix test matrix --- .github/workflows/build.yml | 35 +++++++++++------------------------ 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 68fbf6dc..2349029f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -42,13 +42,10 @@ jobs: - Windows 2019 include: - platform: Windows 2025 - build-platform: Windows runner: windows-2025 - platform: Windows 2022 - build-platform: Windows runner: windows-2022 - platform: Windows 2019 - build-platform: Windows runner: windows-2019 steps: - name: Checkout Source @@ -176,11 +173,12 @@ jobs: strategy: fail-fast: false matrix: - platform: - # TODO: Move different windows platforms into registry dump matrix + filesystem: - Windows 2025 - Windows 2022 - Windows 2019 + platform: + - Windows - Linux GCC - Linux Clang - macOS @@ -192,53 +190,42 @@ jobs: preset: debug - configuration: Release preset: release - - platform: Windows 2025 - build-platform: Windows - runner: windows-2025 - - platform: Windows 2022 - build-platform: Windows - runner: windows-2022 - - platform: Windows 2019 - build-platform: Windows - runner: windows-2019 + - platform: Windows + runner: windows-latest - platform: Linux GCC - build-platform: Linux GCC runner: ubuntu-24.04 - platform: Linux Clang - build-platform: Linux Clang runner: ubuntu-24.04 - platform: macOS - build-platform: macOS runner: macos-latest steps: - name: Download Test Config uses: actions/download-artifact@v4 with: - name: Temp ${{ matrix.build-platform }} ${{matrix.configuration}} Test Config + name: Temp ${{ matrix.platform }} ${{matrix.configuration}} Test Config path: build/${{matrix.preset}} - name: Download Artifacts uses: actions/download-artifact@v4 with: - name: ${{ matrix.build-platform }} ${{matrix.configuration}} Artifacts + name: ${{ matrix.platform }} ${{matrix.configuration}} Artifacts path: build/${{matrix.preset}}/artifacts - name: Download Windows Artifacts uses: actions/download-artifact@v4 - if: "${{ matrix.build-platform != 'Windows' }}" + if: "${{ matrix.platform != 'Windows' }}" with: name: Windows ${{matrix.configuration}} Artifacts path: build/${{matrix.preset}}/artifacts - - name: Download Registry Dump + - name: Download Root FS uses: actions/download-artifact@v4 with: - name: Temp Registry Dump - path: build/${{matrix.preset}}/artifacts/registry + name: Temp ${{ matrix.filesystem }} Root FS + path: build/${{matrix.preset}}/artifacts/root - name: CMake Test run: cd build/${{matrix.preset}} && ctest --verbose - if: "${{ matrix.build-platform == 'Windows' }}" summary: name: Pipeline Summary From ec1333278b45cd086aa7af03982ec8dde469fe09 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Wed, 22 Jan 2025 06:41:39 +0100 Subject: [PATCH 14/32] Implement root fs handling --- .github/workflows/build.yml | 5 + cmake/compiler-env.cmake | 2 + src/analyzer/main.cpp | 8 +- src/common/network/address.hpp | 2 + src/emulator/serialization.hpp | 32 +++ src/fuzzer/main.cpp | 4 +- .../emulation_test_utils.hpp | 15 +- .../serialization_test.cpp | 4 +- src/windows-emulator/file_system.cpp | 1 - src/windows-emulator/file_system.hpp | 82 +++--- src/windows-emulator/kusd_mmio.cpp | 2 +- .../module/module_manager.cpp | 12 +- .../module/module_manager.hpp | 2 +- src/windows-emulator/syscalls.cpp | 6 +- src/windows-emulator/windows_emulator.cpp | 31 +-- src/windows-emulator/windows_emulator.hpp | 10 +- src/windows-emulator/windows_path.hpp | 236 ++++++++++++++++++ 17 files changed, 364 insertions(+), 90 deletions(-) delete mode 100644 src/windows-emulator/file_system.cpp create mode 100644 src/windows-emulator/windows_path.hpp diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2349029f..61f4810a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -224,8 +224,13 @@ jobs: name: Temp ${{ matrix.filesystem }} Root FS path: build/${{matrix.preset}}/artifacts/root + - name: Copy Test Sample + run: cp build/${{matrix.preset}}/artifacts/test-sample.exe build/${{matrix.preset}}/artifacts/root/filesys/c/ + - name: CMake Test run: cd build/${{matrix.preset}} && ctest --verbose + env: + EMULATOR_ROOT: ${{github.workspace}}/build/${{matrix.preset}}/artifacts/root summary: name: Pipeline Summary diff --git a/cmake/compiler-env.cmake b/cmake/compiler-env.cmake index a0eebc1e..6f5b48a7 100644 --- a/cmake/compiler-env.cmake +++ b/cmake/compiler-env.cmake @@ -91,6 +91,8 @@ if(MSVC) momo_add_release_link_options( #/LTCG ) + + add_compile_definitions(_CRT_SECURE_NO_WARNINGS) endif() ########################################## diff --git a/src/analyzer/main.cpp b/src/analyzer/main.cpp index 083cbf6b..1c9606c6 100644 --- a/src/analyzer/main.cpp +++ b/src/analyzer/main.cpp @@ -12,7 +12,7 @@ namespace bool use_gdb{false}; bool concise_logging{false}; bool verbose_logging{false}; - std::string registry_path{"./registry"}; + std::string root_filesystem{"./root"}; }; void watch_system_objects(windows_emulator& win_emu, const bool cache_logging) @@ -107,7 +107,7 @@ namespace emulator_settings settings{ .application = args[0], - .registry_directory = options.registry_path, + .root_filesystem = options.root_filesystem, .arguments = parse_arguments(args), .silent_until_main = options.concise_logging, }; @@ -213,10 +213,10 @@ namespace { if (args.size() < 2) { - throw std::runtime_error("No registry path provided after -r"); + throw std::runtime_error("No root path provided after -r"); } arg_it = args.erase(arg_it); - options.registry_path = args[0]; + options.root_filesystem = args[0]; } else { diff --git a/src/common/network/address.hpp b/src/common/network/address.hpp index d42604b0..52fe8018 100644 --- a/src/common/network/address.hpp +++ b/src/common/network/address.hpp @@ -1,7 +1,9 @@ #pragma once #if _WIN32 +#ifndef _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS +#endif #define _CRT_NO_POSIX_ERROR_CODES #define NOMINMAX #define WIN32_LEAN_AND_MEAN diff --git a/src/emulator/serialization.hpp b/src/emulator/serialization.hpp index 7f6adf37..10da2567 100644 --- a/src/emulator/serialization.hpp +++ b/src/emulator/serialization.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -205,6 +206,26 @@ namespace utils return result; } + template + void read_list(std::list& result) + { + const auto size = this->read(); + result.clear(); + + for (uint64_t i = 0; i < size; ++i) + { + result.emplace_back(this->read()); + } + } + + template + std::list read_list() + { + std::list result{}; + this->read_list(result); + return result; + } + template void read_map(Map& map) { @@ -397,6 +418,17 @@ namespace utils this->write_span(std::span(vec)); } + template + void write_list(const std::list vec) + { + this->write(static_cast(vec.size())); + + for (const auto& v : vec) + { + this->write(v); + } + } + template void write_string(const std::basic_string_view str) { diff --git a/src/fuzzer/main.cpp b/src/fuzzer/main.cpp index 9f8e7d8c..244b75b9 100644 --- a/src/fuzzer/main.cpp +++ b/src/fuzzer/main.cpp @@ -42,12 +42,12 @@ namespace struct fuzzer_executer : fuzzer::executer { - windows_emulator emu{}; + windows_emulator emu{"./"}; // TODO: Fix root directory std::span emulator_data{}; std::unordered_set visited_blocks{}; const std::function* handler{nullptr}; - fuzzer_executer(std::span data) + fuzzer_executer(const std::span data) : emulator_data(data) { emu.fuzzing = true; diff --git a/src/windows-emulator-test/emulation_test_utils.hpp b/src/windows-emulator-test/emulation_test_utils.hpp index 40fec6ea..b183ccad 100644 --- a/src/windows-emulator-test/emulation_test_utils.hpp +++ b/src/windows-emulator-test/emulation_test_utils.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -20,9 +21,21 @@ namespace test { + inline std::filesystem::path get_emulator_root() + { + auto* env = getenv("EMULATOR_ROOT"); + if (!env) + { + throw std::runtime_error("No EMULATOR_ROOT set!"); + } + + return env; + } + inline windows_emulator create_sample_emulator(emulator_settings settings, emulator_callbacks callbacks = {}) { - settings.application = "./test-sample.exe"; + settings.application = "c:/test-sample.exe"; + settings.root_filesystem = get_emulator_root(); return windows_emulator{std::move(settings), std::move(callbacks)}; } diff --git a/src/windows-emulator-test/serialization_test.cpp b/src/windows-emulator-test/serialization_test.cpp index 835e7857..73ca3e05 100644 --- a/src/windows-emulator-test/serialization_test.cpp +++ b/src/windows-emulator-test/serialization_test.cpp @@ -14,7 +14,7 @@ namespace test utils::buffer_deserializer deserializer{serializer1.get_buffer()}; - windows_emulator new_emu{}; + windows_emulator new_emu{get_emulator_root()}; new_emu.deserialize(deserializer); utils::buffer_serializer serializer2{}; @@ -57,7 +57,7 @@ namespace test utils::buffer_deserializer deserializer{serializer.get_buffer()}; - windows_emulator new_emu{}; + windows_emulator new_emu{get_emulator_root()}; new_emu.log.disable_output(true); new_emu.deserialize(deserializer); diff --git a/src/windows-emulator/file_system.cpp b/src/windows-emulator/file_system.cpp deleted file mode 100644 index e9125080..00000000 --- a/src/windows-emulator/file_system.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "std_include.hpp" diff --git a/src/windows-emulator/file_system.hpp b/src/windows-emulator/file_system.hpp index 77d8ba07..89a1f1f6 100644 --- a/src/windows-emulator/file_system.hpp +++ b/src/windows-emulator/file_system.hpp @@ -1,85 +1,67 @@ #pragma once #include "std_include.hpp" -#include +#include "windows_path.hpp" class file_system { public: - static constexpr std::u16string_view nt_prefix = u"\\??\\"; - - file_system(std::filesystem::path root, std::u16string working_dir) + file_system(std::filesystem::path root, windows_path working_dir) : root_(std::move(root)), working_dir_(std::move(working_dir)) { } - static std::filesystem::path canonicalize_windows_path(const std::filesystem::path& file) - { - const auto wide_file = file.u16string(); - - if (!wide_file.starts_with(nt_prefix)) - { - return file; - } - - return canonicalize_windows_path(wide_file.substr(nt_prefix.size())); - } - - static std::filesystem::path canonicalize(const std::filesystem::path& path) - { - return utils::path_key::canonicalize_path(canonicalize_windows_path(path)); - } - - static std::filesystem::path canonicalize_drive_letter(const std::filesystem::path& path) + std::filesystem::path translate(const windows_path& win_path) const { - auto canonical_path = canonicalize(path); - if (canonical_path.empty() || !path.has_root_path()) + if (win_path.is_absolute()) { - return canonical_path; + return this->root_ / win_path.to_portable_path(); } - return adapt_drive_component(canonical_path); + return this->root_ / (this->working_dir_ / win_path).to_portable_path(); } - std::filesystem::path translate(const std::filesystem::path& win_path) const - { - const auto absolute_win_dir = make_absolute_windows_path(win_path.u16string()); - return this->root_ / canonicalize_drive_letter(absolute_win_dir); - } - - void set_working_directory(std::u16string working_dir) + void set_working_directory(windows_path working_dir) { this->working_dir_ = std::move(working_dir); } - const std::u16string& get_working_directory() const + const windows_path& get_working_directory() const { return this->working_dir_; } - private: - std::filesystem::path root_; - std::u16string working_dir_; - - std::u16string make_absolute_windows_path(const std::u16string& path) const + windows_path local_to_windows_path(const std::filesystem::path& local_path) const { - if (!path.starts_with(nt_prefix) && (path.size() < 2 || path[1] != ':')) + const auto absolute_local_path = absolute(local_path); + const auto relative_path = relative(absolute_local_path, this->root_); + + if (relative_path.empty() || *relative_path.begin() == "..") { - return this->working_dir_ + u'/' + path; + throw std::runtime_error("Path '" + local_path.string() + "' is not within the root filesystem!"); } - return path; - } - - static std::filesystem::path adapt_drive_component(const std::filesystem::path& original_path) - { - auto root_name = original_path.root_name().u16string(); + char drive{}; + std::list folders{}; - if (!root_name.empty() && root_name.back() == u':') + for (auto i = relative_path.begin(); i != relative_path.end(); ++i) { - root_name.pop_back(); + if (i == relative_path.begin()) + { + const auto str = i->string(); + assert(str.size() == 1); + drive = str[0]; + } + else + { + folders.push_back(i->u16string()); + } } - return root_name + original_path.root_directory().u16string() + original_path.relative_path().u16string(); + return windows_path{drive, std::move(folders)}; } + + private: + std::filesystem::path root_{}; + windows_path working_dir_{}; }; diff --git a/src/windows-emulator/kusd_mmio.cpp b/src/windows-emulator/kusd_mmio.cpp index b6575ed6..5494f247 100644 --- a/src/windows-emulator/kusd_mmio.cpp +++ b/src/windows-emulator/kusd_mmio.cpp @@ -80,7 +80,7 @@ namespace kusd.QpcFrequency = std::chrono::steady_clock::period::den; } - constexpr std::wstring_view root_dir{L"C:\\WINDOWS"}; + constexpr std::u16string_view root_dir{u"C:\\WINDOWS"}; memcpy(&kusd.NtSystemRoot.arr[0], root_dir.data(), root_dir.size() * 2); kusd.ImageNumberLow = IMAGE_FILE_MACHINE_I386; diff --git a/src/windows-emulator/module/module_manager.cpp b/src/windows-emulator/module/module_manager.cpp index 0f73ae5c..0721bec5 100644 --- a/src/windows-emulator/module/module_manager.cpp +++ b/src/windows-emulator/module/module_manager.cpp @@ -28,8 +28,8 @@ namespace utils static void serialize(buffer_serializer& buffer, const mapped_module& mod) { - buffer.write_string(mod.name); - buffer.write(mod.path.u16string()); + buffer.write(mod.name); + buffer.write(mod.path); buffer.write(mod.image_base); buffer.write(mod.size_of_image); @@ -41,8 +41,8 @@ namespace utils static void deserialize(buffer_deserializer& buffer, mapped_module& mod) { - mod.name = buffer.read_string(); - mod.path = buffer.read_string(); + buffer.read(mod.name); + buffer.read(mod.path); buffer.read(mod.image_base); buffer.read(mod.size_of_image); @@ -59,7 +59,7 @@ module_manager::module_manager(emulator& emu, file_system& file_sys) { } -mapped_module* module_manager::map_module(const std::filesystem::path& file, const logger& logger) +mapped_module* module_manager::map_module(const windows_path& file, const logger& logger) { return this->map_local_module(this->file_sys_->translate(file), logger); } @@ -70,7 +70,7 @@ mapped_module* module_manager::map_local_module(const std::filesystem::path& fil for (auto& mod : this->modules_ | std::views::values) { - if (mod.path == file) + if (mod.path == local_file) { return &mod; } diff --git a/src/windows-emulator/module/module_manager.hpp b/src/windows-emulator/module/module_manager.hpp index 2f298954..418c3d10 100644 --- a/src/windows-emulator/module/module_manager.hpp +++ b/src/windows-emulator/module/module_manager.hpp @@ -12,7 +12,7 @@ class module_manager using module_map = std::map; module_manager(emulator& emu, file_system& file_sys); - mapped_module* map_module(const std::filesystem::path& file, const logger& logger); + mapped_module* map_module(const windows_path& file, const logger& logger); mapped_module* map_local_module(const std::filesystem::path& file, const logger& logger); mapped_module* find_by_address(const uint64_t address) diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 88b4063d..4f8ecaba 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -192,7 +192,7 @@ namespace return STATUS_OBJECT_NAME_NOT_FOUND; } - const std::wstring original_name(value->name.begin(), value->name.end()); + const std::u16string original_name(value->name.begin(), value->name.end()); if (key_value_information_class == KeyValueBasicInformation) { @@ -2897,10 +2897,10 @@ namespace const auto filename = read_unicode_string( c.emu, emulator_object>>{c.emu, attributes.ObjectName}); - const auto u8_filename = u16_to_u8(filename); + const auto local_filename = c.win_emu.file_sys.translate(filename).string(); struct _stat64 file_stat{}; - if (_stat64(u8_filename.c_str(), &file_stat) != 0) + if (_stat64(local_filename.c_str(), &file_stat) != 0) { return STATUS_OBJECT_NAME_NOT_FOUND; } diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index 3a1eb75e..2af740fe 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -208,11 +208,6 @@ namespace emu.reg(x64_register::ss, 0x2B); } - std::filesystem::path canonicalize_path(const std::filesystem::path& path) - { - return canonical(absolute(path)).make_preferred(); - } - void setup_context(windows_emulator& win_emu, const emulator_settings& settings) { auto& emu = win_emu.emu(); @@ -220,7 +215,7 @@ namespace setup_gdt(emu); - context.registry = registry_manager(settings.registry_directory); + context.registry = registry_manager(win_emu.root_directory / "registry"); context.kusd.setup(settings.use_relative_time); @@ -260,7 +255,9 @@ namespace allocator.copy_string(u"SystemRoot=C:\\WINDOWS"); allocator.copy_string(u""); - std::u16string command_line = u"\"" + settings.application.u16string() + u"\""; + const auto application_str = settings.application.u16string(); + + std::u16string command_line = u"\"" + application_str + u"\""; for (const auto& arg : settings.arguments) { @@ -270,9 +267,8 @@ namespace allocator.make_unicode_string(proc_params.CommandLine, command_line); allocator.make_unicode_string(proc_params.CurrentDirectory.DosPath, - win_emu.file_sys.get_working_directory()); - allocator.make_unicode_string(proc_params.ImagePathName, - canonicalize_path(settings.application).u16string()); + win_emu.file_sys.get_working_directory().u16string()); + allocator.make_unicode_string(proc_params.ImagePathName, application_str); const auto total_length = allocator.get_next_address() - context.process_params.value(); @@ -824,11 +820,15 @@ std::unique_ptr create_default_x64_emulator() windows_emulator::windows_emulator(const emulator_settings& settings, emulator_callbacks callbacks, std::unique_ptr emu) - : windows_emulator(std::move(emu)) + : windows_emulator(settings.root_filesystem, std::move(emu)) { if (!settings.working_directory.empty()) { - this->file_sys.set_working_directory(settings.working_directory.u16string()); + this->file_sys.set_working_directory(settings.working_directory); + } + else + { + this->file_sys.set_working_directory(settings.application.parent()); } this->silent_until_main_ = settings.silent_until_main && !settings.disable_logging; @@ -838,8 +838,9 @@ windows_emulator::windows_emulator(const emulator_settings& settings, emulator_c this->setup_process(settings); } -windows_emulator::windows_emulator(std::unique_ptr emu) - : file_sys(R"(C:\Users\mahe.WIBU\Desktop\emulator\src\tools\root)", u"C:\\"), +windows_emulator::windows_emulator(const std::filesystem::path& root_path, std::unique_ptr emu) + : root_directory{absolute(root_path)}, + file_sys(root_directory / "filesys", u"C:\\"), emu_(std::move(emu)), process_(*emu_, file_sys) { @@ -855,7 +856,7 @@ void windows_emulator::setup_process(const emulator_settings& settings) setup_context(*this, settings); - context.executable = context.mod_manager.map_local_module(settings.application, this->log); + context.executable = context.mod_manager.map_module(settings.application, this->log); context.peb.access([&](PEB64& peb) { peb.ImageBaseAddress = reinterpret_cast(context.executable->image_base); // diff --git a/src/windows-emulator/windows_emulator.hpp b/src/windows-emulator/windows_emulator.hpp index 0839db3a..0ece4b6e 100644 --- a/src/windows-emulator/windows_emulator.hpp +++ b/src/windows-emulator/windows_emulator.hpp @@ -27,9 +27,9 @@ struct emulator_callbacks // TODO: Split up into application and emulator settings struct emulator_settings { - std::filesystem::path application{}; - std::filesystem::path working_directory{}; - std::filesystem::path registry_directory{"./registry"}; + windows_path application{}; + windows_path working_directory{}; + std::filesystem::path root_filesystem{}; std::vector arguments{}; bool disable_logging{false}; bool silent_until_main{false}; @@ -47,7 +47,8 @@ enum class apiset_location class windows_emulator { public: - windows_emulator(std::unique_ptr emu = create_default_x64_emulator()); + windows_emulator(const std::filesystem::path& root_path, + std::unique_ptr emu = create_default_x64_emulator()); windows_emulator(const emulator_settings& settings, emulator_callbacks callbacks = {}, std::unique_ptr emu = create_default_x64_emulator()); @@ -132,6 +133,7 @@ class windows_emulator return this->callbacks_; } + std::filesystem::path root_directory{}; file_system file_sys; private: diff --git a/src/windows-emulator/windows_path.hpp b/src/windows-emulator/windows_path.hpp new file mode 100644 index 00000000..eaf5a940 --- /dev/null +++ b/src/windows-emulator/windows_path.hpp @@ -0,0 +1,236 @@ +#pragma once + +#include +#include +#include +#include + +#include + +namespace windows_path_detail +{ + constexpr std::u16string_view unc_prefix = u"\\??\\"; + + inline std::u16string_view strip_unc_prefix(const std::u16string_view path) + { + if (!path.starts_with(unc_prefix)) + { + return path; + } + + return path.substr(unc_prefix.size()); + } + + inline bool is_slash(const char16_t chr) + { + return chr == u'\\' || chr == u'/'; + } +} + +class windows_path +{ + public: + windows_path() = default; + + windows_path(const std::filesystem::path& path) + { + const auto full_path = path.u16string(); + const auto canonical_path = windows_path_detail::strip_unc_prefix(full_path); + + std::u16string folder{}; + + for (const auto chr : canonical_path) + { + if (chr == u':' && this->folders_.empty() && !this->drive_.has_value() && folder.size() == 1) + { + this->drive_ = static_cast(folder[0]); + folder.clear(); + continue; + } + + if (windows_path_detail::is_slash(chr)) + { + if (folder.empty()) + { + continue; + } + + this->folders_.push_back(std::move(folder)); + folder = {}; + continue; + } + + folder.push_back(chr); + } + + if (!folder.empty()) + { + this->folders_.push_back(folder); + } + + this->canonicalize(); + } + + template + requires(!std::is_same_v && !std::is_same_v) + windows_path(T&& path_like) + : windows_path(std::filesystem::path(std::forward(path_like))) + { + } + + windows_path(const std::optional drive, std::list folders) + : drive_(drive), + folders_(std::move(folders)) + { + this->canonicalize(); + } + + bool is_absolute() const + { + return this->drive_.has_value(); + } + + bool is_relative() const + { + return !this->is_absolute(); + } + + std::u16string u16string() const + { + std::u16string path{}; + if (this->drive_) + { + path.push_back(static_cast(*this->drive_)); + path.push_back(u':'); + } + + for (const auto& folder : this->folders_) + { + if (!path.empty()) + { + path.push_back(u'\\'); + } + + path.append(folder); + } + + return path; + } + + std::string string() const + { + return u16_to_u8(this->u16string()); + } + + std::u16string to_unc_path() const + { + if (this->is_relative()) + { + return this->u16string(); + } + + return std::u16string(windows_path_detail::unc_prefix) + this->u16string(); + } + + std::filesystem::path to_portable_path() const + { + std::u16string path{}; + if (this->drive_) + { + path.push_back(static_cast(*this->drive_)); + } + + for (const auto& folder : this->folders_) + { + if (!path.empty()) + { + path.push_back(u'/'); + } + + path.append(folder); + } + + return path; + } + + windows_path operator/(const windows_path& path) const + { + if (path.is_absolute()) + { + return path; + } + + auto folders = this->folders_; + + for (const auto& folder : path.folders_) + { + folders.push_back(folder); + } + + return {this->drive_, std::move(folders)}; + } + + windows_path& operator/=(const windows_path& path) + { + *this = *this / path; + return *this; + } + + windows_path parent() const + { + auto folders = this->folders_; + if (!folders.empty()) + { + folders.pop_back(); + } + + return {this->drive_, std::move(folders)}; + } + + void serialize(utils::buffer_serializer& buffer) const + { + buffer.write_optional(this->drive_); + buffer.write_list(this->folders_); + } + + void deserialize(utils::buffer_deserializer& buffer) + { + buffer.read_optional(this->drive_); + buffer.read_list(this->folders_); + } + + bool operator==(const windows_path& other) const + { + return this->drive_ == other.drive_ && this->folders_ == other.folders_; + } + + bool operator!=(const windows_path& other) const + { + return !this->operator==(other); + } + + bool empty() const + { + return !this->is_relative() && this->folders_.empty(); + } + + private: + std::optional drive_{}; + std::list folders_{}; + + void canonicalize() + { + if (this->drive_.has_value()) + { + this->drive_ = utils::string::char_to_lower(*this->drive_); + } + + for (auto& folder : this->folders_) + { + for (auto& chr : folder) + { + chr = utils::string::char_to_lower(chr); + } + } + } +}; From d836567db1f3e278f52e61f88e075db56a0174c9 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Wed, 22 Jan 2025 14:06:07 +0100 Subject: [PATCH 15/32] Fix PE parsing --- src/common/platform/win_pefile.hpp | 2 +- src/common/utils/path_key.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/platform/win_pefile.hpp b/src/common/platform/win_pefile.hpp index 20c1327a..24acb4ab 100644 --- a/src/common/platform/win_pefile.hpp +++ b/src/common/platform/win_pefile.hpp @@ -278,7 +278,7 @@ typedef struct _IMAGE_BASE_RELOCATION { DWORD VirtualAddress; DWORD SizeOfBlock; - WORD TypeOffset[1]; + // WORD TypeOffset[1]; } IMAGE_BASE_RELOCATION, *PIMAGE_BASE_RELOCATION; #endif diff --git a/src/common/utils/path_key.hpp b/src/common/utils/path_key.hpp index b45163f5..617f0993 100644 --- a/src/common/utils/path_key.hpp +++ b/src/common/utils/path_key.hpp @@ -42,7 +42,7 @@ namespace utils auto key_string = key.u16string(); std::ranges::replace(key_string, u'\\', '/'); - auto path = std::filesystem::path(key).lexically_normal().wstring(); + auto path = std::filesystem::path(key_string).lexically_normal().wstring(); return utils::string::to_lower_consume(path); } From 4300422b771f9759aad1affd3ff3753ea57142a6 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Wed, 22 Jan 2025 14:06:20 +0100 Subject: [PATCH 16/32] Fix path key --- .../registry/registry_manager.cpp | 33 +++++++++---------- .../registry/registry_manager.hpp | 12 +++---- src/windows-emulator/syscalls.cpp | 8 ++--- 3 files changed, 26 insertions(+), 27 deletions(-) diff --git a/src/windows-emulator/registry/registry_manager.cpp b/src/windows-emulator/registry/registry_manager.cpp index 62adfe1b..5e942f2d 100644 --- a/src/windows-emulator/registry/registry_manager.cpp +++ b/src/windows-emulator/registry/registry_manager.cpp @@ -7,14 +7,14 @@ namespace { - bool is_subpath(const std::filesystem::path& root, const std::filesystem::path& p) + bool is_subpath(const utils::path_key& root, const utils::path_key& p) { - auto root_it = root.begin(); - auto p_it = p.begin(); + auto root_it = root.get().begin(); + auto p_it = p.get().begin(); - for (; root_it != root.end(); ++root_it, ++p_it) + for (; root_it != root.get().end(); ++root_it, ++p_it) { - if (p_it == p.end() || *root_it != *p_it) + if (p_it == p.get().end() || *root_it != *p_it) { return false; } @@ -23,8 +23,7 @@ namespace return true; } - void register_hive(registry_manager::hive_map& hives, const std::filesystem::path& key, - const std::filesystem::path& file) + void register_hive(registry_manager::hive_map& hives, const utils::path_key& key, const std::filesystem::path& file) { hives[key] = std::make_unique(file); } @@ -72,7 +71,7 @@ void registry_manager::deserialize(utils::buffer_deserializer& buffer) this->setup(); } -std::filesystem::path registry_manager::normalize_path(const std::filesystem::path& path) const +utils::path_key registry_manager::normalize_path(const utils::path_key& path) const { const utils::path_key canonical_path = path; @@ -87,16 +86,16 @@ std::filesystem::path registry_manager::normalize_path(const std::filesystem::pa return canonical_path.get(); } -void registry_manager::add_path_mapping(const std::filesystem::path& key, const std::filesystem::path& value) +void registry_manager::add_path_mapping(const utils::path_key& key, const utils::path_key& value) { this->path_mapping_[key] = value; } -std::optional registry_manager::get_key(const std::filesystem::path& key) +std::optional registry_manager::get_key(const utils::path_key& key) { const auto normal_key = this->normalize_path(key); - if (is_subpath(normal_key, "\\registry\\machine")) + if (is_subpath(normal_key, utils::path_key{"\\registry\\machine"})) { registry_key reg_key{}; reg_key.hive = normal_key; @@ -111,14 +110,14 @@ std::optional registry_manager::get_key(const std::filesystem::pat registry_key reg_key{}; reg_key.hive = iterator->first.get(); - reg_key.path = normal_key.lexically_relative(reg_key.hive); + reg_key.path = normal_key.get().lexically_relative(reg_key.hive.get()); - if (reg_key.path.empty()) + if (reg_key.path.get().empty()) { return {std::move(reg_key)}; } - const auto entry = iterator->second->get_sub_key(reg_key.path); + const auto entry = iterator->second->get_sub_key(reg_key.path.get()); if (!entry) { return std::nullopt; @@ -137,7 +136,7 @@ std::optional registry_manager::get_value(const registry_key& ke return std::nullopt; } - auto* entry = iterator->second->get_value(key.path, name); + auto* entry = iterator->second->get_value(key.path.get(), name); if (!entry) { return std::nullopt; @@ -151,11 +150,11 @@ std::optional registry_manager::get_value(const registry_key& ke return v; } -registry_manager::hive_map::iterator registry_manager::find_hive(const std::filesystem::path& key) +registry_manager::hive_map::iterator registry_manager::find_hive(const utils::path_key& key) { for (auto i = this->hives_.begin(); i != this->hives_.end(); ++i) { - if (is_subpath(i->first.get(), key)) + if (is_subpath(i->first, key)) { return i; } diff --git a/src/windows-emulator/registry/registry_manager.hpp b/src/windows-emulator/registry/registry_manager.hpp index 1e598ac6..7b6f0c55 100644 --- a/src/windows-emulator/registry/registry_manager.hpp +++ b/src/windows-emulator/registry/registry_manager.hpp @@ -6,8 +6,8 @@ struct registry_key { - std::filesystem::path hive{}; - std::filesystem::path path{}; + utils::path_key hive{}; + utils::path_key path{}; void serialize(utils::buffer_serializer& buffer) const { @@ -48,7 +48,7 @@ class registry_manager void serialize(utils::buffer_serializer& buffer) const; void deserialize(utils::buffer_deserializer& buffer); - std::optional get_key(const std::filesystem::path& key); + std::optional get_key(const utils::path_key& key); std::optional get_value(const registry_key& key, std::string name); private: @@ -56,10 +56,10 @@ class registry_manager hive_map hives_{}; std::unordered_map path_mapping_{}; - std::filesystem::path normalize_path(const std::filesystem::path& path) const; - void add_path_mapping(const std::filesystem::path& key, const std::filesystem::path& value); + utils::path_key normalize_path(const utils::path_key& path) const; + void add_path_mapping(const utils::path_key& key, const utils::path_key& value); - hive_map::iterator find_hive(const std::filesystem::path& key); + hive_map::iterator find_hive(const utils::path_key& key); void setup(); }; diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 4f8ecaba..1432e64f 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -77,13 +77,13 @@ namespace return STATUS_INVALID_HANDLE; } - const std::filesystem::path full_path = parent_handle->hive / parent_handle->path / key; + const std::filesystem::path full_path = parent_handle->hive.get() / parent_handle->path.get() / key; key = full_path.u16string(); } c.win_emu.log.print(color::dark_gray, "--> Registry key: %s\n", u16_to_u8(key).c_str()); - auto entry = c.proc.registry.get_key(key); + auto entry = c.proc.registry.get_key({key}); if (!entry.has_value()) { return STATUS_OBJECT_NAME_NOT_FOUND; @@ -115,8 +115,8 @@ namespace if (key_information_class == KeyNameInformation) { - auto key_name = (key->hive / key->path).wstring(); - while (key_name.ends_with('/') || key_name.ends_with('\\')) + auto key_name = (key->hive.get() / key->path.get()).u16string(); + while (key_name.ends_with(u'/') || key_name.ends_with(u'\\')) { key_name.pop_back(); } From 114d87cd5a0953e618d582b30fc7df5feba3f54c Mon Sep 17 00:00:00 2001 From: momo5502 Date: Wed, 22 Jan 2025 15:20:53 +0100 Subject: [PATCH 17/32] Fix test --- src/samples/test-sample/test.cpp | 2 +- src/windows-emulator/module/module_manager.cpp | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/samples/test-sample/test.cpp b/src/samples/test-sample/test.cpp index efa056c8..83282f81 100644 --- a/src/samples/test-sample/test.cpp +++ b/src/samples/test-sample/test.cpp @@ -290,7 +290,7 @@ bool test_native_exceptions() void print_time() { const auto epoch_time = std::chrono::system_clock::now().time_since_epoch(); - printf("Time: %lld\n", epoch_time.count()); + printf("Time: %lld\n", std::chrono::duration_cast(epoch_time).count()); } #define RUN_TEST(func, name) \ diff --git a/src/windows-emulator/module/module_manager.cpp b/src/windows-emulator/module/module_manager.cpp index 0721bec5..935c2a43 100644 --- a/src/windows-emulator/module/module_manager.cpp +++ b/src/windows-emulator/module/module_manager.cpp @@ -3,10 +3,7 @@ #include "module_mapping.hpp" #include "windows-emulator/logger.hpp" -namespace -{ - -} +#include namespace utils { From 795badf8066678cf0554f2e9afad02a629cb6856 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Wed, 22 Jan 2025 15:40:25 +0100 Subject: [PATCH 18/32] Retain permissions when uploading artifacts --- .github/workflows/build.yml | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 61f4810a..3cfe42fd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -52,7 +52,7 @@ jobs: uses: actions/checkout@v4 - name: Download Windows Artifacts - uses: actions/download-artifact@v4 + uses: pyTooling/download-artifact@v4 with: name: Windows Release Artifacts path: build/release/artifacts @@ -64,11 +64,11 @@ jobs: run: cd root && ../build/release/artifacts/dump-apiset.exe - name: Upload Artifacts - uses: actions/upload-artifact@v4 + uses: pyTooling/upload-artifact@v4 with: name: Temp ${{ matrix.platform }} Root FS - path: | - root/* + path: "*" + working-directory: root build: name: Build @@ -152,19 +152,18 @@ jobs: if: ${{ !startsWith(matrix.platform, 'Android') }} - name: Upload Artifacts - uses: actions/upload-artifact@v4 + uses: pyTooling/upload-artifact@v4 with: name: ${{ matrix.platform }} ${{matrix.configuration}} Artifacts - path: | - build/${{matrix.preset}}/artifacts/* + working-directory: build/${{matrix.preset}}/artifacts/ + path: "*" - name: Upload Test Configuration - uses: actions/upload-artifact@v4 + uses: pyTooling/upload-artifact@v4 with: name: Temp ${{ matrix.platform }} ${{matrix.configuration}} Test Config - path: | - build/${{matrix.preset}}/**/CTestTestfile.cmake - + path: "**/CTestTestfile.cmake" + working-directory: build/${{matrix.preset}} test: name: Test @@ -200,26 +199,26 @@ jobs: runner: macos-latest steps: - name: Download Test Config - uses: actions/download-artifact@v4 + uses: pyTooling/download-artifact@v4 with: name: Temp ${{ matrix.platform }} ${{matrix.configuration}} Test Config path: build/${{matrix.preset}} - name: Download Artifacts - uses: actions/download-artifact@v4 + uses: pyTooling/download-artifact@v4 with: name: ${{ matrix.platform }} ${{matrix.configuration}} Artifacts path: build/${{matrix.preset}}/artifacts - name: Download Windows Artifacts - uses: actions/download-artifact@v4 + uses: pyTooling/download-artifact@v4 if: "${{ matrix.platform != 'Windows' }}" with: name: Windows ${{matrix.configuration}} Artifacts path: build/${{matrix.preset}}/artifacts - name: Download Root FS - uses: actions/download-artifact@v4 + uses: pyTooling/download-artifact@v4 with: name: Temp ${{ matrix.filesystem }} Root FS path: build/${{matrix.preset}}/artifacts/root From 22565683a74f7a6f709e6c30fca794752059ef51 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Wed, 22 Jan 2025 15:52:26 +0100 Subject: [PATCH 19/32] Fix casing --- src/windows-emulator/registry/registry_manager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/windows-emulator/registry/registry_manager.cpp b/src/windows-emulator/registry/registry_manager.cpp index 5e942f2d..2b9fb544 100644 --- a/src/windows-emulator/registry/registry_manager.cpp +++ b/src/windows-emulator/registry/registry_manager.cpp @@ -55,7 +55,7 @@ void registry_manager::setup() register_hive(this->hives_, machine / "system", this->hive_path_ / "SYSTEM"); register_hive(this->hives_, machine / "hardware", this->hive_path_ / "HARDWARE"); - register_hive(this->hives_, root / "user", this->hive_path_ / "NTUSER.dat"); + register_hive(this->hives_, root / "user", this->hive_path_ / "NTUSER.DAT"); this->add_path_mapping(machine / "system" / "CurrentControlSet", machine / "system" / "ControlSet001"); } From aa162cc5482f96c413b895bb029c3b2d99848fb5 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Wed, 22 Jan 2025 16:00:05 +0100 Subject: [PATCH 20/32] Fix debug tests --- src/tools/.gitignore | 2 ++ src/tools/create-root.bat | 1 + src/windows-emulator/syscalls.cpp | 3 +++ 3 files changed, 6 insertions(+) create mode 100644 src/tools/.gitignore diff --git a/src/tools/.gitignore b/src/tools/.gitignore new file mode 100644 index 00000000..d484f3b3 --- /dev/null +++ b/src/tools/.gitignore @@ -0,0 +1,2 @@ +root +registry \ No newline at end of file diff --git a/src/tools/create-root.bat b/src/tools/create-root.bat index 65ca8f5d..67abede0 100644 --- a/src/tools/create-root.bat +++ b/src/tools/create-root.bat @@ -75,6 +75,7 @@ CALL :collect_dll winmm.dll CALL :collect_dll ws2_32.dll CALL :collect_dll wsock32.dll CALL :collect_dll msvcp140.dll +CALL :collect_dll msvcp140d.dll CALL :collect_dll locale.nls diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 1432e64f..3509b5d8 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -2897,6 +2897,9 @@ namespace const auto filename = read_unicode_string( c.emu, emulator_object>>{c.emu, attributes.ObjectName}); + + c.win_emu.log.print(color::dark_gray, "--> Querying file attributes: %s\n", u16_to_u8(filename).c_str()); + const auto local_filename = c.win_emu.file_sys.translate(filename).string(); struct _stat64 file_stat{}; From 4d31331b0aa6d512a52c18d6ebed33223691a302 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Wed, 22 Jan 2025 18:52:25 +0100 Subject: [PATCH 21/32] Update unicorn --- deps/unicorn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/unicorn b/deps/unicorn index 270d4716..9a6618ba 160000 --- a/deps/unicorn +++ b/deps/unicorn @@ -1 +1 @@ -Subproject commit 270d4716f4542d7caa6d2da597e5eab451debce7 +Subproject commit 9a6618baf899d515b8eccd22c1eec532bfbc7cd6 From 7d6505915122d102a349725e09e49bf18bd6f1cd Mon Sep 17 00:00:00 2001 From: momo5502 Date: Wed, 22 Jan 2025 18:58:18 +0100 Subject: [PATCH 22/32] Test auto var init --- cmake/compiler-env.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/compiler-env.cmake b/cmake/compiler-env.cmake index 6f5b48a7..3589b59f 100644 --- a/cmake/compiler-env.cmake +++ b/cmake/compiler-env.cmake @@ -45,6 +45,7 @@ if(LINUX) -fdata-sections -fstack-protector-strong -fdiagnostics-color=always + -ftrivial-auto-var-init=zero ) add_compile_definitions( From e9f7051a75c72fd6aaa7fc759356c6c561beae99 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Wed, 22 Jan 2025 19:56:51 +0100 Subject: [PATCH 23/32] Add macOS intel tests --- .github/workflows/build.yml | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3cfe42fd..72259eb4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -180,7 +180,8 @@ jobs: - Windows - Linux GCC - Linux Clang - - macOS + - macOS arm64 + - macOS x86_64 configuration: - Debug - Release @@ -190,29 +191,36 @@ jobs: - configuration: Release preset: release - platform: Windows + build-platform: Windows runner: windows-latest - platform: Linux GCC + build-platform: Linux GCC runner: ubuntu-24.04 - platform: Linux Clang + build-platform: Linux Clang runner: ubuntu-24.04 - - platform: macOS + - platform: macOS arm64 + build-platform: macOS runner: macos-latest + - platform: macOS x86_64 + build-platform: macOS + runner: macos-13 steps: - name: Download Test Config uses: pyTooling/download-artifact@v4 with: - name: Temp ${{ matrix.platform }} ${{matrix.configuration}} Test Config + name: Temp ${{ matrix.build-platform }} ${{matrix.configuration}} Test Config path: build/${{matrix.preset}} - name: Download Artifacts uses: pyTooling/download-artifact@v4 with: - name: ${{ matrix.platform }} ${{matrix.configuration}} Artifacts + name: ${{ matrix.build-platform }} ${{matrix.configuration}} Artifacts path: build/${{matrix.preset}}/artifacts - name: Download Windows Artifacts uses: pyTooling/download-artifact@v4 - if: "${{ matrix.platform != 'Windows' }}" + if: "${{ matrix.build-platform != 'Windows' }}" with: name: Windows ${{matrix.configuration}} Artifacts path: build/${{matrix.preset}}/artifacts From ff51fbcb249eaa7b3f7ee941c62306ee7261085f Mon Sep 17 00:00:00 2001 From: Maurice Heumann Date: Wed, 22 Jan 2025 20:23:41 +0100 Subject: [PATCH 24/32] Update compiler-env.cmake --- cmake/compiler-env.cmake | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cmake/compiler-env.cmake b/cmake/compiler-env.cmake index 3589b59f..2438aa2b 100644 --- a/cmake/compiler-env.cmake +++ b/cmake/compiler-env.cmake @@ -22,11 +22,15 @@ set(CMAKE_POLICY_DEFAULT_CMP0069 NEW) set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON) +set(CMAKE_OSX_DEPLOYMENT_TARGET "11.0") ########################################## if(UNIX) - momo_add_c_and_cxx_compile_options(-fvisibility=hidden) + momo_add_c_and_cxx_compile_options( + -fvisibility=hidden + -ftrivial-auto-var-init=zero + ) endif() ########################################## @@ -45,7 +49,6 @@ if(LINUX) -fdata-sections -fstack-protector-strong -fdiagnostics-color=always - -ftrivial-auto-var-init=zero ) add_compile_definitions( From 6b43e53a6f5806d6b4f12dedabe0aeba06be0b1c Mon Sep 17 00:00:00 2001 From: momo5502 Date: Thu, 23 Jan 2025 18:24:31 +0100 Subject: [PATCH 25/32] Don't build universal binaries on macOS --- .github/workflows/build.yml | 18 ++++++++---------- CMakeLists.txt | 6 +++++- cmake/compiler-env.cmake | 1 - 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 72259eb4..8f06dc8c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -80,7 +80,8 @@ jobs: - Windows - Linux GCC - Linux Clang - - macOS + - macOS arm64 + - macOS x86_64 - Android x86_64 - Android arm64-v8a configuration: @@ -98,8 +99,10 @@ jobs: - platform: Linux Clang runner: ubuntu-24.04 clang-version: 18 - - platform: macOS + - platform: macOS arm64 runner: macos-latest + - platform: macOS x86_64 + runner: macos-13 - platform: Android x86_64 runner: ubuntu-24.04 abi: x86_64 @@ -191,36 +194,31 @@ jobs: - configuration: Release preset: release - platform: Windows - build-platform: Windows runner: windows-latest - platform: Linux GCC - build-platform: Linux GCC runner: ubuntu-24.04 - platform: Linux Clang - build-platform: Linux Clang runner: ubuntu-24.04 - platform: macOS arm64 - build-platform: macOS runner: macos-latest - platform: macOS x86_64 - build-platform: macOS runner: macos-13 steps: - name: Download Test Config uses: pyTooling/download-artifact@v4 with: - name: Temp ${{ matrix.build-platform }} ${{matrix.configuration}} Test Config + name: Temp ${{ matrix.platform }} ${{matrix.configuration}} Test Config path: build/${{matrix.preset}} - name: Download Artifacts uses: pyTooling/download-artifact@v4 with: - name: ${{ matrix.build-platform }} ${{matrix.configuration}} Artifacts + name: ${{ matrix.platform }} ${{matrix.configuration}} Artifacts path: build/${{matrix.preset}}/artifacts - name: Download Windows Artifacts uses: pyTooling/download-artifact@v4 - if: "${{ matrix.build-platform != 'Windows' }}" + if: "${{ matrix.platform != 'Windows' }}" with: name: Windows ${{matrix.configuration}} Artifacts path: build/${{matrix.preset}}/artifacts diff --git a/CMakeLists.txt b/CMakeLists.txt index 92c10865..1c0b8964 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,11 @@ set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_OSX_DEPLOYMENT_TARGET 11.0) -set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64") + +# Prevent unicorn from generating universal binaries on macOS +# It doesn't support it, even if it thinks it does... +set(ENV{ARCHFLAGS} "nope") + ########################################## diff --git a/cmake/compiler-env.cmake b/cmake/compiler-env.cmake index 2438aa2b..7430d2cd 100644 --- a/cmake/compiler-env.cmake +++ b/cmake/compiler-env.cmake @@ -22,7 +22,6 @@ set(CMAKE_POLICY_DEFAULT_CMP0069 NEW) set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON) -set(CMAKE_OSX_DEPLOYMENT_TARGET "11.0") ########################################## From d360a06737b128c55eabbc058f8dcd5fb882838c Mon Sep 17 00:00:00 2001 From: momo5502 Date: Fri, 24 Jan 2025 07:26:00 +0100 Subject: [PATCH 26/32] Archive more DLLs and retain root fs for a day --- .github/workflows/build.yml | 14 ++++++++++++-- src/tools/create-root.bat | 25 +++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8f06dc8c..1562f905 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -51,6 +51,15 @@ jobs: - name: Checkout Source uses: actions/checkout@v4 + - name: Download DirectX Runtime + run: curl -L -o directx_Jun2010_redist.exe https://download.microsoft.com/download/8/4/A/84A35BF1-DAFE-4AE8-82AF-AD2AE20B6B14/directx_Jun2010_redist.exe + + - name: Extract DirectX Runtime + run: ./directx_Jun2010_redist.exe /Q /T:"${{github.workspace}}/dxrt" + + - name: Install DirectX Runtime + run: "cmd /c \"start /wait .\\dxrt\\dxsetup.exe /silent\"" + - name: Download Windows Artifacts uses: pyTooling/download-artifact@v4 with: @@ -66,9 +75,10 @@ jobs: - name: Upload Artifacts uses: pyTooling/upload-artifact@v4 with: - name: Temp ${{ matrix.platform }} Root FS + name: ${{ matrix.platform }} Root FS path: "*" working-directory: root + retention-days: 1 build: name: Build @@ -226,7 +236,7 @@ jobs: - name: Download Root FS uses: pyTooling/download-artifact@v4 with: - name: Temp ${{ matrix.filesystem }} Root FS + name: ${{ matrix.filesystem }} Root FS path: build/${{matrix.preset}}/artifacts/root - name: Copy Test Sample diff --git a/src/tools/create-root.bat b/src/tools/create-root.bat index 67abede0..786628ff 100644 --- a/src/tools/create-root.bat +++ b/src/tools/create-root.bat @@ -76,6 +76,31 @@ CALL :collect_dll ws2_32.dll CALL :collect_dll wsock32.dll CALL :collect_dll msvcp140.dll CALL :collect_dll msvcp140d.dll +CALL :collect_dll d3d11.dll +CALL :collect_dll d3d9.dll +CALL :collect_dll d3dcompiler_47.dll +CALL :collect_dll dxgi.dll +CALL :collect_dll dsound.dll +CALL :collect_dll dwmapi.dll +CALL :collect_dll hid.dll +CALL :collect_dll imm32.dll +CALL :collect_dll uiautomationcore.dll +CALL :collect_dll opengl32.dll +CALL :collect_dll normaliz.dll +CALL :collect_dll wintrust.dll +CALL :collect_dll wldap32.dll +CALL :collect_dll wtsapi32.dll +CALL :collect_dll x3daudio1_7.dll +CALL :collect_dll xapofx1_5.dll +CALL :collect_dll xinput1_3.dll +CALL :collect_dll cryptsp.dll +CALL :collect_dll resampledmo.dll +CALL :collect_dll powrprof.dll +CALL :collect_dll winmmbase.dll +CALL :collect_dll gdi32full.dll +CALL :collect_dll glu32.dll +CALL :collect_dll msdmo.dll +CALL :collect_dll dxcore.dll CALL :collect_dll locale.nls From 2c1e6f10e0dc3a6e678c801b08fca0a0503e94fe Mon Sep 17 00:00:00 2001 From: momo5502 Date: Fri, 24 Jan 2025 09:08:31 +0100 Subject: [PATCH 27/32] Fix formatting --- src/windows-emulator/windows_emulator.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/windows-emulator/windows_emulator.hpp b/src/windows-emulator/windows_emulator.hpp index 0ece4b6e..914b868b 100644 --- a/src/windows-emulator/windows_emulator.hpp +++ b/src/windows-emulator/windows_emulator.hpp @@ -132,7 +132,7 @@ class windows_emulator { return this->callbacks_; } - + std::filesystem::path root_directory{}; file_system file_sys; From c4a02d319032c3005efea7d87f849fdbd454a104 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Fri, 24 Jan 2025 11:55:25 +0100 Subject: [PATCH 28/32] Add more DLLs --- src/tools/create-root.bat | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/tools/create-root.bat b/src/tools/create-root.bat index 786628ff..5a89a64d 100644 --- a/src/tools/create-root.bat +++ b/src/tools/create-root.bat @@ -78,6 +78,7 @@ CALL :collect_dll msvcp140.dll CALL :collect_dll msvcp140d.dll CALL :collect_dll d3d11.dll CALL :collect_dll d3d9.dll +CALL :collect_dll d3d12.dll CALL :collect_dll d3dcompiler_47.dll CALL :collect_dll dxgi.dll CALL :collect_dll dsound.dll @@ -93,6 +94,7 @@ CALL :collect_dll wtsapi32.dll CALL :collect_dll x3daudio1_7.dll CALL :collect_dll xapofx1_5.dll CALL :collect_dll xinput1_3.dll +CALL :collect_dll xinput9_1_0.dll CALL :collect_dll cryptsp.dll CALL :collect_dll resampledmo.dll CALL :collect_dll powrprof.dll @@ -101,6 +103,13 @@ CALL :collect_dll gdi32full.dll CALL :collect_dll glu32.dll CALL :collect_dll msdmo.dll CALL :collect_dll dxcore.dll +CALL :collect_dll mfplat.dll +CALL :collect_dll wer.dll +CALL :collect_dll dbghelp.dll +CALL :collect_dll mscms.dll +CALL :collect_dll ktmw32.dll +CALL :collect_dll shcore.dll +CALL :collect_dll diagnosticdatasettings.dll CALL :collect_dll locale.nls From 376015a84a2bb333f0e943b2c8106e4687d5de7c Mon Sep 17 00:00:00 2001 From: momo5502 Date: Fri, 24 Jan 2025 17:03:27 +0100 Subject: [PATCH 29/32] This fixes #104 --- src/windows-emulator/windows_emulator.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index 2af740fe..ab0cd206 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -145,7 +145,7 @@ namespace return buffer; } - std::vector obtain_api_set(apiset_location location) + std::vector obtain_api_set(const apiset_location location, const std::filesystem::path& root) { switch (location) { @@ -162,7 +162,7 @@ namespace throw std::runtime_error("The APISET host location is not supported on this platform"); #endif case apiset_location::file: { - auto apiset = utils::io::read_file("api-set.bin"); + auto apiset = utils::io::read_file(root / "api-set.bin"); if (apiset.empty()) throw std::runtime_error("Failed to read file api-set.bin"); return decompress_apiset(apiset); @@ -181,10 +181,11 @@ namespace } emulator_object build_api_set_map(x64_emulator& emu, emulator_allocator& allocator, - apiset_location location = apiset_location::host) + const apiset_location location = apiset_location::host, + const std::filesystem::path& root = {}) { return clone_api_set_map(emu, allocator, - reinterpret_cast(*obtain_api_set(location).data())); + reinterpret_cast(*obtain_api_set(location, root).data())); } emulator_allocator create_allocator(emulator& emu, const size_t size) @@ -277,17 +278,13 @@ namespace proc_params.MaximumLength = proc_params.Length; }); -// TODO: make this configurable -#ifdef OS_WINDOWS - apiset_location apiset_loc = apiset_location::host; -#else - apiset_location apiset_loc = apiset_location::default_windows_11; -#endif + // TODO: make this configurable + const apiset_location apiset_loc = apiset_location::file; context.peb.access([&](PEB64& peb) { peb.ImageBaseAddress = nullptr; peb.ProcessParameters = context.process_params.ptr(); - peb.ApiSetMap = build_api_set_map(emu, allocator, apiset_loc).ptr(); + peb.ApiSetMap = build_api_set_map(emu, allocator, apiset_loc, win_emu.root_directory).ptr(); peb.ProcessHeap = nullptr; peb.ProcessHeaps = nullptr; From 0454120f45cb42431434aff64c67fff5eea4da5d Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 25 Jan 2025 07:47:04 +0100 Subject: [PATCH 30/32] Serialize file system This fixes #108 --- src/windows-emulator/file_system.hpp | 10 ++++++++++ src/windows-emulator/windows_emulator.cpp | 12 ++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/windows-emulator/file_system.hpp b/src/windows-emulator/file_system.hpp index 89a1f1f6..a9a1e237 100644 --- a/src/windows-emulator/file_system.hpp +++ b/src/windows-emulator/file_system.hpp @@ -61,6 +61,16 @@ class file_system return windows_path{drive, std::move(folders)}; } + void serialize(utils::buffer_serializer& buffer) const + { + buffer.write(this->working_dir_); + } + + void deserialize(utils::buffer_deserializer& buffer) + { + buffer.read(this->working_dir_); + } + private: std::filesystem::path root_{}; windows_path working_dir_{}; diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index ab0cd206..f944849e 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -1111,6 +1111,7 @@ void windows_emulator::start(std::chrono::nanoseconds timeout, size_t count) void windows_emulator::serialize(utils::buffer_serializer& buffer) const { buffer.write(this->use_relative_time_); + this->file_sys.serialize(buffer); this->emu().serialize(buffer); this->process_.serialize(buffer); this->dispatcher_.serialize(buffer); @@ -1118,11 +1119,16 @@ void windows_emulator::serialize(utils::buffer_serializer& buffer) const void windows_emulator::deserialize(utils::buffer_deserializer& buffer) { - buffer.register_factory([this] { return x64_emulator_wrapper{this->emu()}; }); + buffer.register_factory([this] { + return x64_emulator_wrapper{this->emu()}; // + }); - buffer.register_factory([this] { return windows_emulator_wrapper{*this}; }); + buffer.register_factory([this] { + return windows_emulator_wrapper{*this}; // + }); buffer.read(this->use_relative_time_); + this->file_sys.deserialize(buffer); this->emu().deserialize(buffer); this->process_.deserialize(buffer); @@ -1134,6 +1140,7 @@ void windows_emulator::save_snapshot() this->emu().save_snapshot(); utils::buffer_serializer serializer{}; + this->file_sys.serialize(serializer); this->process_.serialize(serializer); this->process_snapshot_ = serializer.move_buffer(); @@ -1153,6 +1160,7 @@ void windows_emulator::restore_snapshot() this->emu().restore_snapshot(); utils::buffer_deserializer deserializer{this->process_snapshot_}; + this->file_sys.deserialize(deserializer); this->process_.deserialize(deserializer); // this->process_ = *this->process_snapshot_; } From 4cd098626e76c433a2d772d20ab158f108e78b74 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 25 Jan 2025 08:09:00 +0100 Subject: [PATCH 31/32] Support host/default apiset loc and empty emulation root --- src/windows-emulator/file_system.hpp | 14 +++++++++++--- src/windows-emulator/windows_emulator.cpp | 16 ++++++++++++---- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/windows-emulator/file_system.hpp b/src/windows-emulator/file_system.hpp index a9a1e237..8f8e46b0 100644 --- a/src/windows-emulator/file_system.hpp +++ b/src/windows-emulator/file_system.hpp @@ -2,6 +2,8 @@ #include "std_include.hpp" #include "windows_path.hpp" +#include + class file_system { public: @@ -13,12 +15,18 @@ class file_system std::filesystem::path translate(const windows_path& win_path) const { - if (win_path.is_absolute()) + const auto& full_path = win_path.is_absolute() // + ? win_path + : (this->working_dir_ / win_path); + +#ifdef OS_WINDOWS + if (this->root_.empty()) { - return this->root_ / win_path.to_portable_path(); + return full_path.u16string(); } +#endif - return this->root_ / (this->working_dir_ / win_path).to_portable_path(); + return this->root_ / full_path.to_portable_path(); } void set_working_directory(windows_path working_dir) diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index f944849e..168f17a4 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -151,7 +151,7 @@ namespace { #ifdef OS_WINDOWS case apiset_location::host: { - auto apiSetMap = + const auto apiSetMap = reinterpret_cast(NtCurrentTeb64()->ProcessEnvironmentBlock->ApiSetMap); const auto* dataPtr = reinterpret_cast(apiSetMap); std::vector buffer(dataPtr, dataPtr + apiSetMap->Size); @@ -162,7 +162,7 @@ namespace throw std::runtime_error("The APISET host location is not supported on this platform"); #endif case apiset_location::file: { - auto apiset = utils::io::read_file(root / "api-set.bin"); + const auto apiset = utils::io::read_file(root / "api-set.bin"); if (apiset.empty()) throw std::runtime_error("Failed to read file api-set.bin"); return decompress_apiset(apiset); @@ -278,8 +278,16 @@ namespace proc_params.MaximumLength = proc_params.Length; }); - // TODO: make this configurable - const apiset_location apiset_loc = apiset_location::file; + apiset_location apiset_loc = apiset_location::file; + + if (win_emu.root_directory.empty()) + { +#ifdef OS_WINDOWS + apiset_loc = apiset_location::host; +#else + apiset_loc = apiset_location::default_windows_11; +#endif + } context.peb.access([&](PEB64& peb) { peb.ImageBaseAddress = nullptr; From a3c6e9a5c0cf80fea934e2641274705038d7abf2 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 25 Jan 2025 08:30:43 +0100 Subject: [PATCH 32/32] Cleanup emulation root handling This fixes #103 This fixes #105 --- src/analyzer/main.cpp | 19 +++++++-- .../emulation_test_utils.hpp | 2 +- src/windows-emulator/file_system.hpp | 3 +- src/windows-emulator/syscalls.cpp | 12 +++--- src/windows-emulator/windows_emulator.cpp | 41 +++++++++++-------- src/windows-emulator/windows_emulator.hpp | 26 +++++++++--- 6 files changed, 70 insertions(+), 33 deletions(-) diff --git a/src/analyzer/main.cpp b/src/analyzer/main.cpp index 1c9606c6..e4468096 100644 --- a/src/analyzer/main.cpp +++ b/src/analyzer/main.cpp @@ -12,7 +12,8 @@ namespace bool use_gdb{false}; bool concise_logging{false}; bool verbose_logging{false}; - std::string root_filesystem{"./root"}; + std::string registry_path{"./registry"}; + std::string emulation_root{}; }; void watch_system_objects(windows_emulator& win_emu, const bool cache_logging) @@ -107,7 +108,8 @@ namespace emulator_settings settings{ .application = args[0], - .root_filesystem = options.root_filesystem, + .registry_directory = options.registry_path, + .emulation_root = options.emulation_root, .arguments = parse_arguments(args), .silent_until_main = options.concise_logging, }; @@ -209,14 +211,23 @@ namespace { options.concise_logging = true; } + else if (arg == "-e") + { + if (args.size() < 2) + { + throw std::runtime_error("No emulation root path provided after -e"); + } + arg_it = args.erase(arg_it); + options.emulation_root = args[0]; + } else if (arg == "-r") { if (args.size() < 2) { - throw std::runtime_error("No root path provided after -r"); + throw std::runtime_error("No registry path provided after -r"); } arg_it = args.erase(arg_it); - options.root_filesystem = args[0]; + options.registry_path = args[0]; } else { diff --git a/src/windows-emulator-test/emulation_test_utils.hpp b/src/windows-emulator-test/emulation_test_utils.hpp index b183ccad..f36ce716 100644 --- a/src/windows-emulator-test/emulation_test_utils.hpp +++ b/src/windows-emulator-test/emulation_test_utils.hpp @@ -35,7 +35,7 @@ namespace test inline windows_emulator create_sample_emulator(emulator_settings settings, emulator_callbacks callbacks = {}) { settings.application = "c:/test-sample.exe"; - settings.root_filesystem = get_emulator_root(); + settings.emulation_root = get_emulator_root(); return windows_emulator{std::move(settings), std::move(callbacks)}; } diff --git a/src/windows-emulator/file_system.hpp b/src/windows-emulator/file_system.hpp index 8f8e46b0..d76f3a52 100644 --- a/src/windows-emulator/file_system.hpp +++ b/src/windows-emulator/file_system.hpp @@ -7,7 +7,7 @@ class file_system { public: - file_system(std::filesystem::path root, windows_path working_dir) + file_system(std::filesystem::path root, windows_path working_dir = "C:\\") : root_(std::move(root)), working_dir_(std::move(working_dir)) { @@ -26,6 +26,7 @@ class file_system } #endif + // TODO: Sanitize path to prevent traversal! return this->root_ / full_path.to_portable_path(); } diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 3509b5d8..b739123a 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -1530,7 +1530,7 @@ namespace if (!f->enumeration_state || query_flags & SL_RESTART_SCAN) { f->enumeration_state.emplace(file_enumeration_state{}); - f->enumeration_state->files = scan_directory(c.win_emu.file_sys.translate(f->name)); + f->enumeration_state->files = scan_directory(c.win_emu.file_sys().translate(f->name)); } auto& enum_state = *f->enumeration_state; @@ -2586,7 +2586,7 @@ namespace const emulator_object /*default_casing_table_size*/) { const auto locale_file = - utils::io::read_file(c.win_emu.file_sys.translate(R"(C:\Windows\System32\locale.nls)")); + utils::io::read_file(c.win_emu.file_sys().translate(R"(C:\Windows\System32\locale.nls)")); if (locale_file.empty()) { return STATUS_FILE_INVALID; @@ -2826,14 +2826,14 @@ namespace if (create_disposition & FILE_CREATE) { std::error_code ec{}; - std::filesystem::create_directory(c.win_emu.file_sys.translate(f.name), ec); + create_directory(c.win_emu.file_sys().translate(f.name), ec); if (ec) { return STATUS_ACCESS_DENIED; } } - else if (!std::filesystem::is_directory(c.win_emu.file_sys.translate(f.name))) + else if (!std::filesystem::is_directory(c.win_emu.file_sys().translate(f.name))) { return STATUS_OBJECT_NAME_NOT_FOUND; } @@ -2855,7 +2855,7 @@ namespace FILE* file{}; - const auto error = open_unicode(&file, c.win_emu.file_sys.translate(f.name), mode); + const auto error = open_unicode(&file, c.win_emu.file_sys().translate(f.name), mode); if (!file) { @@ -2900,7 +2900,7 @@ namespace c.win_emu.log.print(color::dark_gray, "--> Querying file attributes: %s\n", u16_to_u8(filename).c_str()); - const auto local_filename = c.win_emu.file_sys.translate(filename).string(); + const auto local_filename = c.win_emu.file_sys().translate(filename).string(); struct _stat64 file_stat{}; if (_stat64(local_filename.c_str(), &file_stat) != 0) diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index 168f17a4..479b40a4 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -216,7 +216,9 @@ namespace setup_gdt(emu); - context.registry = registry_manager(win_emu.root_directory / "registry"); + context.registry = + registry_manager(win_emu.get_emulation_root().empty() ? settings.registry_directory + : win_emu.get_emulation_root() / "registry"); context.kusd.setup(settings.use_relative_time); @@ -268,7 +270,7 @@ namespace allocator.make_unicode_string(proc_params.CommandLine, command_line); allocator.make_unicode_string(proc_params.CurrentDirectory.DosPath, - win_emu.file_sys.get_working_directory().u16string()); + win_emu.file_sys().get_working_directory().u16string()); allocator.make_unicode_string(proc_params.ImagePathName, application_str); const auto total_length = allocator.get_next_address() - context.process_params.value(); @@ -280,7 +282,7 @@ namespace apiset_location apiset_loc = apiset_location::file; - if (win_emu.root_directory.empty()) + if (win_emu.get_emulation_root().empty()) { #ifdef OS_WINDOWS apiset_loc = apiset_location::host; @@ -292,7 +294,7 @@ namespace context.peb.access([&](PEB64& peb) { peb.ImageBaseAddress = nullptr; peb.ProcessParameters = context.process_params.ptr(); - peb.ApiSetMap = build_api_set_map(emu, allocator, apiset_loc, win_emu.root_directory).ptr(); + peb.ApiSetMap = build_api_set_map(emu, allocator, apiset_loc, win_emu.get_emulation_root()).ptr(); peb.ProcessHeap = nullptr; peb.ProcessHeaps = nullptr; @@ -825,15 +827,15 @@ std::unique_ptr create_default_x64_emulator() windows_emulator::windows_emulator(const emulator_settings& settings, emulator_callbacks callbacks, std::unique_ptr emu) - : windows_emulator(settings.root_filesystem, std::move(emu)) + : windows_emulator(settings.emulation_root, std::move(emu)) { if (!settings.working_directory.empty()) { - this->file_sys.set_working_directory(settings.working_directory); + this->file_sys().set_working_directory(settings.working_directory); } else { - this->file_sys.set_working_directory(settings.application.parent()); + this->file_sys().set_working_directory(settings.application.parent()); } this->silent_until_main_ = settings.silent_until_main && !settings.disable_logging; @@ -843,12 +845,19 @@ windows_emulator::windows_emulator(const emulator_settings& settings, emulator_c this->setup_process(settings); } -windows_emulator::windows_emulator(const std::filesystem::path& root_path, std::unique_ptr emu) - : root_directory{absolute(root_path)}, - file_sys(root_directory / "filesys", u"C:\\"), +windows_emulator::windows_emulator(const std::filesystem::path& emulation_root, std::unique_ptr emu) + : emulation_root_{emulation_root.empty() ? emulation_root : absolute(emulation_root)}, + file_sys_(emulation_root_.empty() ? emulation_root_ : emulation_root_ / "filesys"), emu_(std::move(emu)), - process_(*emu_, file_sys) + process_(*emu_, file_sys_) { +#ifndef OS_WINDOWS + if (this->get_emulation_root().empty()) + { + throw std::runtime_error("Emulation root directory can not be empty!"); + } +#endif + this->setup_hooks(); } @@ -857,7 +866,7 @@ void windows_emulator::setup_process(const emulator_settings& settings) auto& emu = this->emu(); auto& context = this->process(); - context.mod_manager = module_manager(emu, this->file_sys); // TODO: Cleanup module manager + context.mod_manager = module_manager(emu, this->file_sys()); // TODO: Cleanup module manager setup_context(*this, settings); @@ -1119,7 +1128,7 @@ void windows_emulator::start(std::chrono::nanoseconds timeout, size_t count) void windows_emulator::serialize(utils::buffer_serializer& buffer) const { buffer.write(this->use_relative_time_); - this->file_sys.serialize(buffer); + this->file_sys().serialize(buffer); this->emu().serialize(buffer); this->process_.serialize(buffer); this->dispatcher_.serialize(buffer); @@ -1136,7 +1145,7 @@ void windows_emulator::deserialize(utils::buffer_deserializer& buffer) }); buffer.read(this->use_relative_time_); - this->file_sys.deserialize(buffer); + this->file_sys().deserialize(buffer); this->emu().deserialize(buffer); this->process_.deserialize(buffer); @@ -1148,7 +1157,7 @@ void windows_emulator::save_snapshot() this->emu().save_snapshot(); utils::buffer_serializer serializer{}; - this->file_sys.serialize(serializer); + this->file_sys().serialize(serializer); this->process_.serialize(serializer); this->process_snapshot_ = serializer.move_buffer(); @@ -1168,7 +1177,7 @@ void windows_emulator::restore_snapshot() this->emu().restore_snapshot(); utils::buffer_deserializer deserializer{this->process_snapshot_}; - this->file_sys.deserialize(deserializer); + this->file_sys().deserialize(deserializer); this->process_.deserialize(deserializer); // this->process_ = *this->process_snapshot_; } diff --git a/src/windows-emulator/windows_emulator.hpp b/src/windows-emulator/windows_emulator.hpp index 914b868b..e88a522f 100644 --- a/src/windows-emulator/windows_emulator.hpp +++ b/src/windows-emulator/windows_emulator.hpp @@ -29,14 +29,15 @@ struct emulator_settings { windows_path application{}; windows_path working_directory{}; - std::filesystem::path root_filesystem{}; + std::filesystem::path registry_directory{"./registry"}; + std::filesystem::path emulation_root{}; std::vector arguments{}; bool disable_logging{false}; bool silent_until_main{false}; bool use_relative_time{false}; }; -enum class apiset_location +enum class apiset_location : uint8_t { host, file, @@ -47,7 +48,7 @@ enum class apiset_location class windows_emulator { public: - windows_emulator(const std::filesystem::path& root_path, + windows_emulator(const std::filesystem::path& emulation_root, std::unique_ptr emu = create_default_x64_emulator()); windows_emulator(const emulator_settings& settings, emulator_callbacks callbacks = {}, std::unique_ptr emu = create_default_x64_emulator()); @@ -133,10 +134,25 @@ class windows_emulator return this->callbacks_; } - std::filesystem::path root_directory{}; - file_system file_sys; + file_system& file_sys() + { + return this->file_sys_; + } + + const file_system& file_sys() const + { + return this->file_sys_; + } + + const std::filesystem::path& get_emulation_root() + { + return this->emulation_root_; + } private: + std::filesystem::path emulation_root_{}; + file_system file_sys_; + emulator_callbacks callbacks_{}; bool use_relative_time_{false}; bool silent_until_main_{false};