From 24bebc4ee24e28129ca69f796320dba3619dbec9 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Tue, 21 Jan 2025 18:00:11 +0100 Subject: [PATCH] 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, logger& logger) +mapped_module* module_manager::map_module(const std::filesystem::path& file, const logger& logger) { - auto canonical_file = canonicalize_module_path(file); + return this->map_local_module(this->file_sys_->translate(file), logger); +} - for (auto& mod : this->modules_) +mapped_module* module_manager::map_local_module(const std::filesystem::path& file, const logger& logger) +{ + auto local_file = canonical(absolute(file)); + + 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_{};