From 55557006c7f7894dc8bb07366194258435dbe54e Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 8 Feb 2025 14:06:59 +0100 Subject: [PATCH 01/10] Add std::filesystem tests --- src/samples/test-sample/test.cpp | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/samples/test-sample/test.cpp b/src/samples/test-sample/test.cpp index 924bf305..480263c9 100644 --- a/src/samples/test-sample/test.cpp +++ b/src/samples/test-sample/test.cpp @@ -127,10 +127,27 @@ bool test_env() bool test_io() { - const auto* filename = "a.txt"; + const std::filesystem::path filename = "a.txt"; + std::error_code ec{}; + const auto absolute_file = std::filesystem::absolute(filename, ec); + + if (ec) + { + puts("Getting absolute path failed"); + return false; + } + + const auto canonical_file = std::filesystem::canonical(filename, ec); + (void)canonical_file; + + if (ec) + { + puts("Getting canonical path failed"); + return false; + } FILE* fp{}; - (void)fopen_s(&fp, filename, "wb"); + (void)fopen_s(&fp, filename.string().c_str(), "wb"); if (!fp) { From b5a0f731132dc6f3b5916ecd3c07a9b0dbf829ab Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 8 Feb 2025 12:47:20 +0100 Subject: [PATCH 02/10] Fix path syscalls --- src/common/platform/unicode.hpp | 5 + .../devices/mount_point_manager.cpp | 69 +++++++++ .../devices/mount_point_manager.hpp | 4 + src/windows-emulator/io_device.cpp | 6 + src/windows-emulator/syscalls.cpp | 137 ++++++++++++------ src/windows-emulator/windows_path.hpp | 29 ++++ 6 files changed, 206 insertions(+), 44 deletions(-) create mode 100644 src/windows-emulator/devices/mount_point_manager.cpp create mode 100644 src/windows-emulator/devices/mount_point_manager.hpp diff --git a/src/common/platform/unicode.hpp b/src/common/platform/unicode.hpp index b5a895e1..e232958a 100644 --- a/src/common/platform/unicode.hpp +++ b/src/common/platform/unicode.hpp @@ -11,6 +11,11 @@ struct UNICODE_STRING EMULATOR_CAST(typename Traits::PVOID, char16_t*) Buffer; }; +inline std::u16string u8_to_u16(const std::string_view view) +{ + return std::u16string(view.begin(), view.end()); +} + inline std::string u16_to_u8(const std::u16string_view u16_view) { std::string utf8_str; diff --git a/src/windows-emulator/devices/mount_point_manager.cpp b/src/windows-emulator/devices/mount_point_manager.cpp new file mode 100644 index 00000000..918ff081 --- /dev/null +++ b/src/windows-emulator/devices/mount_point_manager.cpp @@ -0,0 +1,69 @@ +#include "mount_point_manager.hpp" + +#include "../windows_emulator.hpp" + +namespace +{ + struct mount_point_manager : stateless_device + { + NTSTATUS io_control(windows_emulator& win_emu, const io_device_context& c) override + { + if (c.io_control_code != 0x6D0030) + { + return STATUS_NOT_SUPPORTED; + } + + if (c.input_buffer_length < 2) + { + return STATUS_NOT_SUPPORTED; + } + + const auto data = win_emu.emu().read_memory(c.input_buffer, c.input_buffer_length); + + const std::u16string_view file(reinterpret_cast(data.data()), (data.size() / 2) - 1); + + constexpr std::u16string_view volume_prefix = u".\\Device\\HarddiskVolume"; + if (!file.starts_with(volume_prefix)) + { + return STATUS_NOT_SUPPORTED; + } + + const auto drive_number = file.substr(volume_prefix.size()); + const auto drive_number_u8 = u16_to_u8(drive_number); + const auto drive_letter = static_cast('A' + atoi(drive_number_u8.c_str()) - 1); + + std::string response{}; + response.push_back(drive_letter); + response.push_back(':'); + response.push_back(0); + response.push_back(0); + + const auto u16_response = u8_to_u16(response); + + const auto length = static_cast(u16_response.size() * 2); + const auto total_length = sizeof(length) + length; + + if (c.io_status_block) + { + IO_STATUS_BLOCK> block{}; + block.Information = total_length; + c.io_status_block.write(block); + } + + if (c.output_buffer_length < total_length) + { + return STATUS_BUFFER_OVERFLOW; + } + + win_emu.emu().write_memory(c.output_buffer, length); + win_emu.emu().write_memory(c.output_buffer + sizeof(length), u16_response.data(), length); + + return STATUS_SUCCESS; + } + }; +} + +std::unique_ptr create_mount_point_manager() +{ + return std::make_unique(); +} diff --git a/src/windows-emulator/devices/mount_point_manager.hpp b/src/windows-emulator/devices/mount_point_manager.hpp new file mode 100644 index 00000000..9df80805 --- /dev/null +++ b/src/windows-emulator/devices/mount_point_manager.hpp @@ -0,0 +1,4 @@ +#pragma once +#include "../io_device.hpp" + +std::unique_ptr create_mount_point_manager(); diff --git a/src/windows-emulator/io_device.cpp b/src/windows-emulator/io_device.cpp index 363bfed4..2cc9e87a 100644 --- a/src/windows-emulator/io_device.cpp +++ b/src/windows-emulator/io_device.cpp @@ -1,5 +1,6 @@ #include "io_device.hpp" #include "devices/afd_endpoint.hpp" +#include "devices/mount_point_manager.hpp" namespace { @@ -28,5 +29,10 @@ std::unique_ptr create_device(const std::u16string_view device) return create_afd_endpoint(); } + if (device == u"MountPointManager") + { + return create_mount_point_manager(); + } + throw std::runtime_error("Unsupported device: " + u16_to_u8(device)); } diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 622298fa..c7a93a79 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -1749,51 +1749,58 @@ namespace const emulator_object>> io_status_block, const uint64_t file_information, const uint32_t length, const uint32_t info_class) { + IO_STATUS_BLOCK> block{}; + block.Status = STATUS_SUCCESS; + block.Information = 0; + + const auto _ = utils::finally([&] { + if (io_status_block) + { + io_status_block.write(block); + } + }); + + const auto ret = [&](const NTSTATUS status) { + block.Status = status; + return status; + }; + const auto* f = c.proc.files.get(file_handle); if (!f) { - return STATUS_INVALID_HANDLE; + return ret(STATUS_INVALID_HANDLE); } - if (info_class == FileNameInformation) + if (info_class == FileNameInformation || info_class == FileNormalizedNameInformation) { - const auto required_length = sizeof(FILE_NAME_INFORMATION) + (f->name.size() * 2); + const auto relative_path = u"\\" + windows_path(f->name).without_drive().u16string(); + const auto required_length = sizeof(FILE_NAME_INFORMATION) + (relative_path.size() * 2); - if (io_status_block) - { - IO_STATUS_BLOCK> block{}; - block.Information = sizeof(FILE_NAME_INFORMATION) + required_length; - io_status_block.write(block); - } + block.Information = required_length; - if (length != required_length) + if (length < block.Information) { - return STATUS_BUFFER_OVERFLOW; + return ret(STATUS_BUFFER_OVERFLOW); } c.emu.write_memory(file_information, FILE_NAME_INFORMATION{ - .FileNameLength = static_cast(f->name.size() * 2), + .FileNameLength = static_cast(relative_path.size() * 2), .FileName = {}, }); - c.emu.write_memory(file_information + offsetof(FILE_NAME_INFORMATION, FileName), f->name.c_str(), - (f->name.size() + 1) * 2); + c.emu.write_memory(file_information + offsetof(FILE_NAME_INFORMATION, FileName), relative_path.c_str(), + (relative_path.size() + 1) * 2); - return STATUS_SUCCESS; + return ret(STATUS_SUCCESS); } if (info_class == FileStandardInformation) { - if (io_status_block) - { - IO_STATUS_BLOCK> block{}; - block.Information = sizeof(FILE_STANDARD_INFORMATION); - io_status_block.write(block); - } + block.Information = sizeof(FILE_STANDARD_INFORMATION); - if (length != sizeof(FILE_STANDARD_INFORMATION)) + if (length < block.Information) { - return STATUS_BUFFER_OVERFLOW; + return ret(STATUS_BUFFER_OVERFLOW); } const emulator_object info{c.emu, file_information}; @@ -1807,26 +1814,21 @@ namespace info.write(i); - return STATUS_SUCCESS; + return ret(STATUS_SUCCESS); } if (info_class == FilePositionInformation) { if (!f->handle) { - return STATUS_NOT_SUPPORTED; + return ret(STATUS_NOT_SUPPORTED); } - if (io_status_block) - { - IO_STATUS_BLOCK> block{}; - block.Information = sizeof(FILE_POSITION_INFORMATION); - io_status_block.write(block); - } + block.Information = sizeof(FILE_POSITION_INFORMATION); - if (length != sizeof(FILE_POSITION_INFORMATION)) + if (length < block.Information) { - return STATUS_BUFFER_OVERFLOW; + return ret(STATUS_BUFFER_OVERFLOW); } const emulator_object info{c.emu, file_information}; @@ -1836,13 +1838,13 @@ namespace info.write(i); - return STATUS_SUCCESS; + return ret(STATUS_SUCCESS); } c.win_emu.log.error("Unsupported query file info class: %X\n", info_class); c.emu.stop(); - return STATUS_NOT_SUPPORTED; + return ret(STATUS_NOT_SUPPORTED); } NTSTATUS handle_NtSetInformationProcess(const syscall_context& c, const handle process_handle, @@ -2868,6 +2870,22 @@ namespace return mode; } + std::optional get_io_device_name(const std::u16string_view filename) + { + constexpr std::u16string_view device_prefix = u"\\Device\\"; + if (filename.starts_with(device_prefix)) + { + return filename.substr(device_prefix.size()); + } + + if (filename.starts_with(u"\\??\\MountPointManager")) + { + return u"MountPointManager"; + } + + return std::nullopt; + } + NTSTATUS handle_NtCreateFile(const syscall_context& c, const emulator_object file_handle, ACCESS_MASK desired_access, const emulator_object>> object_attributes, @@ -2883,16 +2901,15 @@ namespace auto printer = utils::finally( [&] { c.win_emu.log.print(color::dark_gray, "--> Opening file: %s\n", u16_to_u8(filename).c_str()); }); - constexpr std::u16string_view device_prefix = u"\\Device\\"; - if (filename.starts_with(device_prefix)) + const auto io_device_name = get_io_device_name(filename); + if (io_device_name.has_value()) { const io_device_creation_data data{ .buffer = ea_buffer, .length = ea_length, }; - auto device_name = filename.substr(device_prefix.size()); - io_device_container container{std::move(device_name), c.win_emu, data}; + io_device_container container{std::u16string(*io_device_name), c.win_emu, data}; const auto handle = c.proc.devices.store(std::move(container)); file_handle.write(handle); @@ -3034,12 +3051,44 @@ namespace share_access, FILE_OPEN, open_options, 0, 0); } - NTSTATUS handle_NtQueryObject(const syscall_context&, const handle /*handle*/, - const OBJECT_INFORMATION_CLASS /*object_information_class*/, - const emulator_pointer /*object_information*/, - const ULONG /*object_information_length*/, - const emulator_object /*return_length*/) + NTSTATUS handle_NtQueryObject(const syscall_context& c, const handle handle, + const OBJECT_INFORMATION_CLASS object_information_class, + const emulator_pointer object_information, const ULONG object_information_length, + const emulator_object return_length) { + if (object_information_class == ObjectNameInformation) + { + if (handle.value.type != handle_types::file) + { + c.win_emu.log.error("Unsupported handle type for name information query: %X\n", handle.value.type); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + const auto file = c.proc.files.get(handle); + if (!file) + { + return STATUS_INVALID_HANDLE; + } + + const auto device_path = windows_path(file->name).to_device_path(); + + const auto required_size = sizeof(UNICODE_STRING>) + (device_path.size() + 1) * 2; + return_length.write(static_cast(required_size)); + + if (required_size > object_information_length) + { + return STATUS_BUFFER_TOO_SMALL; + } + + emulator_allocator allocator(c.emu, object_information, object_information_length); + allocator.make_unicode_string(device_path); + + return STATUS_SUCCESS; + } + + c.win_emu.log.error("Unsupported object info class: %X\n", object_information_class); + c.emu.stop(); return STATUS_NOT_SUPPORTED; } diff --git a/src/windows-emulator/windows_path.hpp b/src/windows-emulator/windows_path.hpp index 869d5027..d0b8471e 100644 --- a/src/windows-emulator/windows_path.hpp +++ b/src/windows-emulator/windows_path.hpp @@ -155,6 +155,35 @@ class windows_path return path; } + std::u16string to_device_path() const + { + if (is_relative()) + { + throw std::runtime_error("Device path can not be computed for relative paths!"); + } + + const auto drive_index = *this->drive_ - 'a'; + const auto drive_number = std::to_string(drive_index + 1); + const std::u16string number(drive_number.begin(), drive_number.end()); + + std::u16string path = u"\\Device\\HarddiskVolume"; + path.append(number); + path.push_back(u'\\'); + path.append(this->without_drive().u16string()); + + return path; + } + + std::optional get_drive() const + { + return this->drive_; + } + + windows_path without_drive() const + { + return windows_path{std::nullopt, this->folders_}; + } + windows_path operator/(const windows_path& path) const { if (path.is_absolute()) From 72e88d30d47d33e8c5f7c2d808d5d85b22d8115d Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 8 Feb 2025 17:05:02 +0100 Subject: [PATCH 03/10] Use working directory provider --- src/windows-emulator/file_system.hpp | 40 +++++++------------ src/windows-emulator/windows_emulator.cpp | 47 ++++++++++++++++------- src/windows-emulator/windows_emulator.hpp | 8 ++-- 3 files changed, 51 insertions(+), 44 deletions(-) diff --git a/src/windows-emulator/file_system.hpp b/src/windows-emulator/file_system.hpp index 4161bf3e..159cf311 100644 --- a/src/windows-emulator/file_system.hpp +++ b/src/windows-emulator/file_system.hpp @@ -4,20 +4,26 @@ #include +struct working_directory_provider +{ + virtual windows_path get_working_directory() = 0; +}; + class file_system { public: - file_system(std::filesystem::path root, windows_path working_dir = "C:\\") - : root_(std::move(root)) + file_system(std::filesystem::path root, working_directory_provider& working_dir_provider) + : root_(std::move(root)), + working_dir_provider_(&working_dir_provider) { - this->set_working_directory(std::move(working_dir)); } std::filesystem::path translate(const windows_path& win_path) const { + assert(win_path.is_absolute() && "Path should always be absolute"); const auto& full_path = win_path.is_absolute() // ? win_path - : (this->working_dir_ / win_path); + : (this->working_dir_provider_->get_working_directory() / win_path); const auto mapping = this->mappings_.find(full_path); if (mapping != this->mappings_.end()) @@ -36,20 +42,10 @@ class file_system return this->root_ / full_path.to_portable_path(); } - void set_working_directory(windows_path working_dir) - { - if (!working_dir.is_absolute()) - { - throw std::runtime_error("Working directory is not an absolute path: " + working_dir.string()); - } - - this->working_dir_ = std::move(working_dir); - } - - const windows_path& get_working_directory() const + /*const windows_path& get_working_directory() const { return this->working_dir_; - } + }*/ windows_path local_to_windows_path(const std::filesystem::path& local_path) const { @@ -81,16 +77,6 @@ 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_); - } - void map(windows_path src, std::filesystem::path dest) { this->mappings_[std::move(src)] = std::move(dest); @@ -98,6 +84,6 @@ class file_system private: std::filesystem::path root_{}; - windows_path working_dir_{}; + working_directory_provider* working_dir_provider_{}; std::unordered_map mappings_{}; }; diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index a5e11bb2..b41e0cf6 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -209,7 +209,8 @@ namespace emu.reg(x64_register::ss, 0x2B); } - void setup_context(windows_emulator& win_emu, const emulator_settings& settings) + void setup_context(windows_emulator& win_emu, const emulator_settings& settings, + const windows_path& working_directory) { auto& emu = win_emu.emu(); auto& context = win_emu.process(); @@ -269,8 +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()); + allocator.make_unicode_string(proc_params.CurrentDirectory.DosPath, working_directory.u16string() + u"\\"); allocator.make_unicode_string(proc_params.ImagePathName, application_str); const auto total_length = allocator.get_next_address() - context.process_params.value(); @@ -829,19 +829,21 @@ windows_emulator::windows_emulator(const emulator_settings& settings, emulator_c std::unique_ptr emu) : windows_emulator(settings.emulation_root, std::move(emu)) { + windows_path working_dir{}; + if (!settings.working_directory.empty()) { - this->file_sys().set_working_directory(settings.working_directory); + working_dir = settings.working_directory; } #ifdef OS_WINDOWS else if (settings.application.is_relative()) { - this->file_sys().set_working_directory(std::filesystem::current_path()); + working_dir = std::filesystem::current_path(); } #endif else { - this->file_sys().set_working_directory(settings.application.parent()); + working_dir = settings.application.parent(); } for (const auto& mapping : settings.path_mappings) @@ -859,12 +861,12 @@ windows_emulator::windows_emulator(const emulator_settings& settings, emulator_c this->use_relative_time_ = settings.use_relative_time; this->log.disable_output(settings.disable_logging || this->silent_until_main_); this->callbacks_ = std::move(callbacks); - this->setup_process(settings); + this->setup_process(settings, working_dir); } 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"), + file_sys_(emulation_root_.empty() ? emulation_root_ : emulation_root_ / "filesys", *this), emu_(std::move(emu)), process_(*emu_, file_sys_) { @@ -878,14 +880,16 @@ windows_emulator::windows_emulator(const std::filesystem::path& emulation_root, this->setup_hooks(); } -void windows_emulator::setup_process(const emulator_settings& settings) +windows_emulator::~windows_emulator() = default; + +void windows_emulator::setup_process(const emulator_settings& settings, const windows_path& working_directory) { auto& emu = this->emu(); auto& context = this->process(); context.mod_manager = module_manager(emu, this->file_sys()); // TODO: Cleanup module manager - setup_context(*this, settings); + setup_context(*this, settings, working_directory); context.executable = context.mod_manager.map_module(settings.application, this->log, true); @@ -938,6 +942,25 @@ bool windows_emulator::activate_thread(const uint32_t id) return switch_to_thread(*this, *thread, true); } +windows_path windows_emulator::get_working_directory() +{ + if (!this->process_.peb) + { + return {}; + } + + const auto peb = this->process_.peb.read(); + if (!peb.ProcessParameters) + { + return {}; + } + + const auto& emu = this->emu(); + + const auto process_params = emu.read_memory(peb.ProcessParameters); + return read_unicode_string(emu, process_params.CurrentDirectory.DosPath); +} + void windows_emulator::on_instruction_execution(const uint64_t address) { auto& process = this->process(); @@ -1154,7 +1177,6 @@ void windows_emulator::serialize(utils::buffer_serializer& buffer) const { buffer.write(this->switch_thread_); buffer.write(this->use_relative_time_); - this->file_sys().serialize(buffer); this->emu().serialize(buffer); this->process_.serialize(buffer); this->dispatcher_.serialize(buffer); @@ -1172,7 +1194,6 @@ void windows_emulator::deserialize(utils::buffer_deserializer& buffer) buffer.read(this->switch_thread_); buffer.read(this->use_relative_time_); - this->file_sys().deserialize(buffer); this->emu().deserialize(buffer); this->process_.deserialize(buffer); @@ -1184,7 +1205,6 @@ 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(); @@ -1204,7 +1224,6 @@ 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_; } diff --git a/src/windows-emulator/windows_emulator.hpp b/src/windows-emulator/windows_emulator.hpp index 29b3f5ca..fe95dc71 100644 --- a/src/windows-emulator/windows_emulator.hpp +++ b/src/windows-emulator/windows_emulator.hpp @@ -48,7 +48,7 @@ enum class apiset_location : uint8_t default_windows_11 }; -class windows_emulator +class windows_emulator : working_directory_provider { public: windows_emulator(const std::filesystem::path& emulation_root, @@ -61,7 +61,7 @@ class windows_emulator windows_emulator& operator=(windows_emulator&&) = delete; windows_emulator& operator=(const windows_emulator&) = delete; - ~windows_emulator() = default; + ~windows_emulator(); x64_emulator& emu() { @@ -190,6 +190,8 @@ class windows_emulator return this->emulation_root_; } + windows_path get_working_directory() override; + private: std::filesystem::path emulation_root_{}; file_system file_sys_; @@ -211,6 +213,6 @@ class windows_emulator // std::optional process_snapshot_{}; void setup_hooks(); - void setup_process(const emulator_settings& settings); + void setup_process(const emulator_settings& settings, const windows_path& working_directory); void on_instruction_execution(uint64_t address); }; From 7efe75ba97205042bf011b202fea192036efed97 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 8 Feb 2025 17:31:53 +0100 Subject: [PATCH 04/10] Remove working directory translations --- src/windows-emulator/file_system.hpp | 30 +++++++---------------- src/windows-emulator/windows_emulator.cpp | 21 +--------------- src/windows-emulator/windows_emulator.hpp | 4 +-- 3 files changed, 11 insertions(+), 44 deletions(-) diff --git a/src/windows-emulator/file_system.hpp b/src/windows-emulator/file_system.hpp index 159cf311..f0ffa98d 100644 --- a/src/windows-emulator/file_system.hpp +++ b/src/windows-emulator/file_system.hpp @@ -4,28 +4,22 @@ #include -struct working_directory_provider -{ - virtual windows_path get_working_directory() = 0; -}; - class file_system { public: - file_system(std::filesystem::path root, working_directory_provider& working_dir_provider) - : root_(std::move(root)), - working_dir_provider_(&working_dir_provider) + file_system(std::filesystem::path root) + : root_(std::move(root)) { } std::filesystem::path translate(const windows_path& win_path) const { - assert(win_path.is_absolute() && "Path should always be absolute"); - const auto& full_path = win_path.is_absolute() // - ? win_path - : (this->working_dir_provider_->get_working_directory() / win_path); + if (!win_path.is_absolute()) + { + throw std::runtime_error("Only absolute paths can be translated!"); + } - const auto mapping = this->mappings_.find(full_path); + const auto mapping = this->mappings_.find(win_path); if (mapping != this->mappings_.end()) { return mapping->second; @@ -34,19 +28,14 @@ class file_system #ifdef OS_WINDOWS if (this->root_.empty()) { - return full_path.u16string(); + return win_path.u16string(); } #endif // TODO: Sanitize path to prevent traversal! - return this->root_ / full_path.to_portable_path(); + return this->root_ / win_path.to_portable_path(); } - /*const windows_path& get_working_directory() const - { - return this->working_dir_; - }*/ - windows_path local_to_windows_path(const std::filesystem::path& local_path) const { const auto absolute_local_path = absolute(local_path); @@ -84,6 +73,5 @@ class file_system private: std::filesystem::path root_{}; - working_directory_provider* working_dir_provider_{}; std::unordered_map mappings_{}; }; diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index b41e0cf6..f5c70926 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -866,7 +866,7 @@ windows_emulator::windows_emulator(const emulator_settings& settings, emulator_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", *this), + file_sys_(emulation_root_.empty() ? emulation_root_ : emulation_root_ / "filesys"), emu_(std::move(emu)), process_(*emu_, file_sys_) { @@ -942,25 +942,6 @@ bool windows_emulator::activate_thread(const uint32_t id) return switch_to_thread(*this, *thread, true); } -windows_path windows_emulator::get_working_directory() -{ - if (!this->process_.peb) - { - return {}; - } - - const auto peb = this->process_.peb.read(); - if (!peb.ProcessParameters) - { - return {}; - } - - const auto& emu = this->emu(); - - const auto process_params = emu.read_memory(peb.ProcessParameters); - return read_unicode_string(emu, process_params.CurrentDirectory.DosPath); -} - void windows_emulator::on_instruction_execution(const uint64_t address) { auto& process = this->process(); diff --git a/src/windows-emulator/windows_emulator.hpp b/src/windows-emulator/windows_emulator.hpp index fe95dc71..69a17497 100644 --- a/src/windows-emulator/windows_emulator.hpp +++ b/src/windows-emulator/windows_emulator.hpp @@ -48,7 +48,7 @@ enum class apiset_location : uint8_t default_windows_11 }; -class windows_emulator : working_directory_provider +class windows_emulator { public: windows_emulator(const std::filesystem::path& emulation_root, @@ -190,8 +190,6 @@ class windows_emulator : working_directory_provider return this->emulation_root_; } - windows_path get_working_directory() override; - private: std::filesystem::path emulation_root_{}; file_system file_sys_; From 9f4a80b42ec7b15bfe7965decb43d365d8847318 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 8 Feb 2025 17:52:11 +0100 Subject: [PATCH 05/10] Fix running relative applications --- src/windows-emulator/windows_emulator.cpp | 12 ++++++++---- src/windows-emulator/windows_path.hpp | 3 ++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index f5c70926..e09a32b8 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -209,7 +209,7 @@ namespace emu.reg(x64_register::ss, 0x2B); } - void setup_context(windows_emulator& win_emu, const emulator_settings& settings, + void setup_context(windows_emulator& win_emu, const emulator_settings& settings, const windows_path& application, const windows_path& working_directory) { auto& emu = win_emu.emu(); @@ -259,7 +259,7 @@ namespace allocator.copy_string(u"SystemRoot=C:\\WINDOWS"); allocator.copy_string(u""); - const auto application_str = settings.application.u16string(); + const auto application_str = application.u16string(); std::u16string command_line = u"\"" + application_str + u"\""; @@ -889,9 +889,13 @@ void windows_emulator::setup_process(const emulator_settings& settings, const wi auto& context = this->process(); context.mod_manager = module_manager(emu, this->file_sys()); // TODO: Cleanup module manager - setup_context(*this, settings, working_directory); + const auto application = settings.application.is_absolute() // + ? settings.application + : (working_directory / settings.application); - context.executable = context.mod_manager.map_module(settings.application, this->log, true); + setup_context(*this, settings, application, working_directory); + + context.executable = context.mod_manager.map_module(application, this->log, true); context.peb.access([&](PEB64& peb) { peb.ImageBaseAddress = reinterpret_cast(context.executable->image_base); // diff --git a/src/windows-emulator/windows_path.hpp b/src/windows-emulator/windows_path.hpp index d0b8471e..d909aae3 100644 --- a/src/windows-emulator/windows_path.hpp +++ b/src/windows-emulator/windows_path.hpp @@ -74,7 +74,8 @@ class windows_path } template - requires(!std::is_same_v && !std::is_same_v) + requires(!std::is_same_v, windows_path> && + !std::is_same_v, std::filesystem::path>) windows_path(T&& path_like) : windows_path(std::filesystem::path(std::forward(path_like))) { From edcc0901813712e38b4a0f5d689024d36d60ab98 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 8 Feb 2025 18:05:47 +0100 Subject: [PATCH 06/10] Support silencing logging in analyzer --- src/analyzer/main.cpp | 14 ++++++++++++++ src/common/utils/function.hpp | 7 +++++++ 2 files changed, 21 insertions(+) diff --git a/src/analyzer/main.cpp b/src/analyzer/main.cpp index ec1e2a00..1ecdf4d2 100644 --- a/src/analyzer/main.cpp +++ b/src/analyzer/main.cpp @@ -12,6 +12,7 @@ namespace bool use_gdb{false}; bool concise_logging{false}; bool verbose_logging{false}; + bool silent{false}; std::string registry_path{"./registry"}; std::string emulation_root{}; }; @@ -113,6 +114,7 @@ namespace .emulation_root = options.emulation_root, .arguments = parse_arguments(args), .verbose_calls = options.verbose_logging, + .disable_logging = options.silent, .silent_until_main = options.concise_logging, }; @@ -122,6 +124,14 @@ namespace watch_system_objects(win_emu, options.concise_logging); win_emu.buffer_stdout = true; + if (options.silent) + { + win_emu.buffer_stdout = false; + win_emu.callbacks().stdout_callback = [](const std::string_view data) { + (void)fwrite(data.data(), 1, data.size(), stdout); + }; + } + const auto& exe = *win_emu.process().executable; const auto concise_logging = options.concise_logging; @@ -204,6 +214,10 @@ namespace { options.use_gdb = true; } + else if (arg == "-s") + { + options.silent = true; + } else if (arg == "-v") { options.verbose_logging = true; diff --git a/src/common/utils/function.hpp b/src/common/utils/function.hpp index f7905232..242e9e08 100644 --- a/src/common/utils/function.hpp +++ b/src/common/utils/function.hpp @@ -33,6 +33,13 @@ namespace utils return *this; } + template + requires(!std::is_same_v, std::function>) + optional_function& operator=(T&& t) + { + return this->operator=(std::function(std::forward(t))); + } + Ret operator()(Args... args) const { if (func) From 2da494a370efd9587d5d7a249b5dea6d78c88973 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 8 Feb 2025 18:35:51 +0100 Subject: [PATCH 07/10] Fix path concatenation --- src/windows-emulator/syscalls.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index c7a93a79..722ba92a 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -2936,7 +2936,8 @@ namespace return STATUS_INVALID_HANDLE; } - f.name = root->name + f.name; + const auto has_separator = root->name.ends_with(u"\\") || root->name.ends_with(u"/"); + f.name = root->name + (has_separator ? u"" : u"\\") + f.name; } printer.cancel(); From fe84448bf5a33572acee2014c4526bb45339aed4 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 8 Feb 2025 18:52:13 +0100 Subject: [PATCH 08/10] Reserve space for current directory --- src/windows-emulator/emulator_utils.hpp | 18 ++++++++++++------ src/windows-emulator/windows_emulator.cpp | 4 ++-- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/windows-emulator/emulator_utils.hpp b/src/windows-emulator/emulator_utils.hpp index ae3cf9b1..fdab413b 100644 --- a/src/windows-emulator/emulator_utils.hpp +++ b/src/windows-emulator/emulator_utils.hpp @@ -187,13 +187,17 @@ class emulator_allocator return reinterpret_cast(uc_str.Buffer); } - void make_unicode_string(UNICODE_STRING>& result, const std::u16string_view str) + void make_unicode_string(UNICODE_STRING>& result, const std::u16string_view str, + const std::optional maximum_length = std::nullopt) { constexpr auto element_size = sizeof(str[0]); constexpr auto required_alignment = alignof(decltype(str[0])); const auto total_length = str.size() * element_size; + const auto total_buffer_length = total_length + element_size; - const auto string_buffer = this->reserve(total_length + element_size, required_alignment); + const auto max_length = std::max(maximum_length.value_or(total_buffer_length), total_buffer_length); + + const auto string_buffer = this->reserve(max_length, required_alignment); this->emu_->write_memory(string_buffer, str.data(), total_length); @@ -202,15 +206,17 @@ class emulator_allocator result.Buffer = string_buffer; result.Length = static_cast(total_length); - result.MaximumLength = static_cast(total_length + element_size); + result.MaximumLength = static_cast(max_length); } - emulator_object>> make_unicode_string(const std::u16string_view str) + emulator_object>> make_unicode_string( + const std::u16string_view str, const std::optional maximum_length = std::nullopt) { const auto unicode_string = this->reserve>>(); - unicode_string.access( - [&](UNICODE_STRING>& unicode_str) { this->make_unicode_string(unicode_str, str); }); + unicode_string.access([&](UNICODE_STRING>& unicode_str) { + this->make_unicode_string(unicode_str, str, maximum_length); // + }); return unicode_string; } diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index e09a32b8..72d5f5e2 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -210,7 +210,7 @@ namespace } void setup_context(windows_emulator& win_emu, const emulator_settings& settings, const windows_path& application, - const windows_path& working_directory) + const windows_path& working_dir) { auto& emu = win_emu.emu(); auto& context = win_emu.process(); @@ -270,7 +270,7 @@ namespace } allocator.make_unicode_string(proc_params.CommandLine, command_line); - allocator.make_unicode_string(proc_params.CurrentDirectory.DosPath, working_directory.u16string() + u"\\"); + allocator.make_unicode_string(proc_params.CurrentDirectory.DosPath, working_dir.u16string() + u"\\", 1024); allocator.make_unicode_string(proc_params.ImagePathName, application_str); const auto total_length = allocator.get_next_address() - context.process_params.value(); From 0bcb18f52bf3d80913ef2c2a5e19541966df9a29 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 8 Feb 2025 18:56:46 +0100 Subject: [PATCH 09/10] Add working directory tests --- src/samples/test-sample/test.cpp | 53 ++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/src/samples/test-sample/test.cpp b/src/samples/test-sample/test.cpp index 480263c9..707e332c 100644 --- a/src/samples/test-sample/test.cpp +++ b/src/samples/test-sample/test.cpp @@ -125,9 +125,8 @@ bool test_env() return !computername.empty() && blub == "LUL"; } -bool test_io() +bool test_file_path_io(const std::filesystem::path& filename) { - const std::filesystem::path filename = "a.txt"; std::error_code ec{}; const auto absolute_file = std::filesystem::absolute(filename, ec); @@ -146,6 +145,18 @@ bool test_io() return false; } + return true; +} + +bool test_io() +{ + const std::filesystem::path filename = "a.txt"; + + if (!test_file_path_io(filename)) + { + return false; + } + FILE* fp{}; (void)fopen_s(&fp, filename.string().c_str(), "wb"); @@ -170,6 +181,43 @@ bool test_io() return text == buffer; } +bool test_working_directory() +{ + std::error_code ec{}; + + const auto current_dir = std::filesystem::current_path(ec); + if (ec) + { + puts("Failed to get current path"); + return false; + } + + const std::filesystem::path sys32 = "C:/windows/system32"; + current_path(sys32, ec); + + if (ec) + { + puts("Failed to update working directory"); + return false; + } + + const auto new_current_dir = std::filesystem::current_path(); + if (sys32 != new_current_dir) + { + puts("Updated directory is wrong!"); + return false; + } + + if (!std::ifstream("ntdll.dll")) + { + puts("Working directory is not active!"); + return false; + } + + std::filesystem::current_path(current_dir); + return std::filesystem::current_path() == current_dir; +} + bool test_dir_io() { size_t count = 0; @@ -367,6 +415,7 @@ int main(const int argc, const char* argv[]) RUN_TEST(test_io, "I/O") RUN_TEST(test_dir_io, "Dir I/O") + RUN_TEST(test_working_directory, "Working Directory") RUN_TEST(test_registry, "Registry") RUN_TEST(test_threads, "Threads") RUN_TEST(test_env, "Environment") From 40bcb097b1fe9d3dd4306c41064f5d8902f324cf Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 8 Feb 2025 19:06:14 +0100 Subject: [PATCH 10/10] Fix filepath I/O test --- src/samples/test-sample/test.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/samples/test-sample/test.cpp b/src/samples/test-sample/test.cpp index 707e332c..7c1d5b60 100644 --- a/src/samples/test-sample/test.cpp +++ b/src/samples/test-sample/test.cpp @@ -152,11 +152,6 @@ bool test_io() { const std::filesystem::path filename = "a.txt"; - if (!test_file_path_io(filename)) - { - return false; - } - FILE* fp{}; (void)fopen_s(&fp, filename.string().c_str(), "wb"); @@ -171,6 +166,11 @@ bool test_io() (void)fwrite(text.data(), 1, text.size(), fp); (void)fclose(fp); + if (!test_file_path_io(filename)) + { + return false; + } + std::ifstream t(filename); t.seekg(0, std::ios::end); const size_t size = t.tellg();