From 12c80f159e17d0bceb5fd0eff6c03ddb3a8fac67 Mon Sep 17 00:00:00 2001 From: robert-yates Date: Sat, 23 Nov 2024 18:52:45 +0100 Subject: [PATCH] add explicit 16bit unicode --- src/analyzer/main.cpp | 4 +- src/emulator/serialization.hpp | 12 ++++ src/emulator/serialization_helper.hpp | 4 +- src/windows-emulator-test/time_test.cpp | 2 +- src/windows-emulator/emulator_utils.hpp | 42 ++++++----- src/windows-emulator/io_device.cpp | 12 ++-- src/windows-emulator/process_context.hpp | 10 +-- src/windows-emulator/syscalls.cpp | 86 ++++++++++++----------- src/windows-emulator/windows_emulator.cpp | 22 +++--- src/windows-emulator/windows_emulator.hpp | 2 +- 10 files changed, 108 insertions(+), 88 deletions(-) diff --git a/src/analyzer/main.cpp b/src/analyzer/main.cpp index 8a19b9f6..8ba74aad 100644 --- a/src/analyzer/main.cpp +++ b/src/analyzer/main.cpp @@ -68,9 +68,9 @@ namespace } } - std::vector parse_arguments(char* argv[], const size_t argc) + std::vector parse_arguments(char* argv[], const size_t argc) { - std::vector args{}; + std::vector args{}; args.reserve(argc - 1); for (size_t i = 1; i < argc; ++i) diff --git a/src/emulator/serialization.hpp b/src/emulator/serialization.hpp index d18f5c25..3f501947 100644 --- a/src/emulator/serialization.hpp +++ b/src/emulator/serialization.hpp @@ -465,6 +465,12 @@ namespace utils object = this->read_string(); } + template <> + inline void buffer_deserializer::read(std::u16string& object) + { + object = this->read_string(); + } + template <> inline void buffer_serializer::write(const bool& object) { @@ -482,4 +488,10 @@ namespace utils { this->write_string(object); } + + template <> + inline void buffer_serializer::write(const std::u16string& object) + { + this->write_string(object); + } } diff --git a/src/emulator/serialization_helper.hpp b/src/emulator/serialization_helper.hpp index 6af6e0f0..a1d2d8bd 100644 --- a/src/emulator/serialization_helper.hpp +++ b/src/emulator/serialization_helper.hpp @@ -35,10 +35,10 @@ inline void deserialize(utils::buffer_deserializer& buffer, std::chrono::system_ inline void serialize(utils::buffer_serializer& buffer, const std::filesystem::path& path) { - buffer.write_string(path.wstring()); + buffer.write_string(path.u16string()); } inline void deserialize(utils::buffer_deserializer& buffer, std::filesystem::path& path) { - path = buffer.read_string(); + path = buffer.read_string(); } diff --git a/src/windows-emulator-test/time_test.cpp b/src/windows-emulator-test/time_test.cpp index 6e114205..f168843c 100644 --- a/src/windows-emulator-test/time_test.cpp +++ b/src/windows-emulator-test/time_test.cpp @@ -7,7 +7,7 @@ namespace test std::string output_buffer{}; emulator_settings settings{ - .arguments = {L"-time"}, + .arguments = {u"-time"}, .stdout_callback = [&output_buffer](const std::string_view data) { output_buffer.append(data); diff --git a/src/windows-emulator/emulator_utils.hpp b/src/windows-emulator/emulator_utils.hpp index fdd6b47b..8e561925 100644 --- a/src/windows-emulator/emulator_utils.hpp +++ b/src/windows-emulator/emulator_utils.hpp @@ -127,6 +127,8 @@ private: uint64_t address_{}; }; + +// TODO: warning emulator_utils is hardcoded for 64bit unicode_string usage class emulator_allocator { public: @@ -166,14 +168,15 @@ public: return emulator_object(*this->emu_, potential_start); } - wchar_t* copy_string(const std::wstring_view str) + + char16_t* copy_string(const std::u16string_view str) { - UNICODE_STRING uc_str{}; + UNICODE_STRING> uc_str{}; this->make_unicode_string(uc_str, str); - return uc_str.Buffer; + return reinterpret_cast(uc_str.Buffer); } - void make_unicode_string(UNICODE_STRING& result, const std::wstring_view str) + void make_unicode_string(UNICODE_STRING>& result, const std::u16string_view str) { constexpr auto element_size = sizeof(str[0]); constexpr auto required_alignment = alignof(decltype(str[0])); @@ -186,16 +189,16 @@ public: constexpr std::array nullbyte{}; this->emu_->write_memory(string_buffer + total_length, nullbyte.data(), nullbyte.size()); - result.Buffer = reinterpret_cast(string_buffer); + result.Buffer = string_buffer; result.Length = static_cast(total_length); result.MaximumLength = static_cast(total_length + element_size); } - emulator_object make_unicode_string(const std::wstring_view str) + emulator_object>> make_unicode_string(const std::u16string_view str) { - const auto unicode_string = this->reserve(); + const auto unicode_string = this->reserve>>(); - unicode_string.access([&](UNICODE_STRING& unicode_str) + unicode_string.access([&](UNICODE_STRING>& unicode_str) { this->make_unicode_string(unicode_str, str); }); @@ -254,29 +257,30 @@ private: uint64_t active_address_{0}; }; -inline std::wstring read_unicode_string(const emulator& emu, const UNICODE_STRING ucs) -{ - static_assert(offsetof(UNICODE_STRING, Length) == 0); - static_assert(offsetof(UNICODE_STRING, MaximumLength) == 2); - static_assert(offsetof(UNICODE_STRING, Buffer) == 8); - static_assert(sizeof(UNICODE_STRING) == 16); - std::wstring result{}; +inline std::u16string read_unicode_string(const emulator& emu, const UNICODE_STRING> ucs) +{ + static_assert(offsetof(UNICODE_STRING>, Length) == 0); + static_assert(offsetof(UNICODE_STRING>, MaximumLength) == 2); + static_assert(offsetof(UNICODE_STRING>, Buffer) == 8); + static_assert(sizeof(UNICODE_STRING>) == 16); + + std::u16string result{}; result.resize(ucs.Length / 2); - emu.read_memory(reinterpret_cast(ucs.Buffer), result.data(), ucs.Length); + emu.read_memory(ucs.Buffer, result.data(), ucs.Length); return result; } -inline std::wstring read_unicode_string(const emulator& emu, const emulator_object uc_string) +inline std::u16string read_unicode_string(const emulator& emu, const emulator_object>> uc_string) { const auto ucs = uc_string.read(); return read_unicode_string(emu, ucs); } -inline std::wstring read_unicode_string(emulator& emu, const UNICODE_STRING* uc_string) +inline std::u16string read_unicode_string(emulator& emu, const UNICODE_STRING>* uc_string) { - return read_unicode_string(emu, emulator_object{emu, uc_string}); + return read_unicode_string(emu, emulator_object>>{emu, uc_string}); } diff --git a/src/windows-emulator/io_device.cpp b/src/windows-emulator/io_device.cpp index 2714491c..d249989f 100644 --- a/src/windows-emulator/io_device.cpp +++ b/src/windows-emulator/io_device.cpp @@ -12,17 +12,17 @@ namespace }; } -std::unique_ptr create_device(const std::wstring_view device) +std::unique_ptr>> create_device64(const std::u16string_view device) { - if (device == L"CNG" - || device == L"KsecDD" - || device == L"DeviceApi\\CMApi" - || device == L"ConDrv\\Server") + if (device == u"CNG" + || device == u"KsecDD" + || device == u"DeviceApi\\CMApi" + || device == u"ConDrv\\Server") { return std::make_unique(); } - if (device == L"Afd\\Endpoint") + if (device == u"Afd\\Endpoint") { return create_afd_endpoint(); } diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index cb8c8ab8..67c19661 100644 --- a/src/windows-emulator/process_context.hpp +++ b/src/windows-emulator/process_context.hpp @@ -51,7 +51,7 @@ struct event : ref_counted_object { bool signaled{}; EVENT_TYPE type{}; - std::wstring name{}; + std::u16string name{}; bool is_signaled() { @@ -87,7 +87,7 @@ struct event : ref_counted_object struct file { utils::file_handle handle{}; - std::wstring name{}; + std::u16string name{}; void serialize(utils::buffer_serializer& buffer) const { @@ -104,7 +104,7 @@ struct file struct semaphore { - std::wstring name{}; + std::u16string name{}; volatile uint32_t current_count{}; uint32_t max_count{}; @@ -125,7 +125,7 @@ struct semaphore struct port { - std::wstring name{}; + std::u16string name{}; uint64_t view_base{}; void serialize(utils::buffer_serializer& buffer) const @@ -218,7 +218,7 @@ public: uint32_t id{}; - std::wstring name{}; + std::u16string name{}; std::optional exit_status{}; std::optional await_object{}; diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index dd977b99..555a7425 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -64,7 +64,7 @@ namespace const emulator_object object_attributes) { const auto attributes = object_attributes.read(); - auto key = read_unicode_string(c.emu, attributes.ObjectName); + auto key = read_unicode_string(c.emu, reinterpret_cast>*>(attributes.ObjectName)); if (attributes.RootDirectory) { @@ -74,7 +74,9 @@ namespace return STATUS_INVALID_HANDLE; } - key = parent_handle->hive / parent_handle->path / key; + std::filesystem::path key_path = key; + std::filesystem::path full_path = parent_handle->hive / parent_handle->path / key_path; + key = full_path.u16string(); } c.win_emu.logger.print(color::dark_gray, "--> Registry key: %S\n", key.c_str()); @@ -166,7 +168,7 @@ namespace } NTSTATUS handle_NtQueryValueKey(const syscall_context& c, const handle key_handle, - const emulator_object value_name, + const emulator_object>> value_name, const KEY_VALUE_INFORMATION_CLASS key_value_information_class, const uint64_t key_value_information, const ULONG length, const emulator_object result_length) @@ -404,13 +406,13 @@ namespace const emulator_object object_attributes, const EVENT_TYPE event_type, const BOOLEAN initial_state) { - std::wstring name{}; + std::u16string name{}; if (object_attributes) { const auto attributes = object_attributes.read(); if (attributes.ObjectName) { - name = read_unicode_string(c.emu, attributes.ObjectName); + name = read_unicode_string(c.emu, reinterpret_cast>*>(attributes.ObjectName)); } } @@ -433,7 +435,7 @@ namespace const emulator_object object_attributes) { const auto attributes = object_attributes.read(); - const auto name = read_unicode_string(c.emu, attributes.ObjectName); + const auto name = read_unicode_string(c.emu, reinterpret_cast>*>(attributes.ObjectName)); for (auto& entry : c.proc.events) { @@ -484,7 +486,7 @@ namespace { const auto attributes = object_attributes.read(); - auto filename = read_unicode_string(c.emu, attributes.ObjectName); + auto filename = read_unicode_string(c.emu, reinterpret_cast>*>(attributes.ObjectName)); c.win_emu.logger.print(color::gray, "Opening section: %S\n", filename.c_str()); if (filename == L"\\Windows\\SharedSection") @@ -500,7 +502,7 @@ namespace return STATUS_NOT_SUPPORTED; } - filename = L"C:\\WINDOWS\\System32\\" + filename; + filename = u"C:\\WINDOWS\\System32\\" + filename; if (!std::filesystem::exists(filename)) { return STATUS_FILE_INVALID; @@ -534,7 +536,7 @@ namespace c.emu.allocate_memory(address, c.proc.shared_section_size, memory_permission::read_write); - const std::wstring_view windows_dir = c.proc.kusd.get().NtSystemRoot.arr; + const std::u16string_view windows_dir = c.proc.kusd.get().NtSystemRoot.arr; const auto windows_dir_size = windows_dir.size() * 2; constexpr auto windows_dir_offset = 0x10; @@ -542,22 +544,22 @@ namespace const auto obj_address = address + windows_dir_offset; - const emulator_object windir_obj{c.emu, obj_address}; - windir_obj.access([&](UNICODE_STRING& ucs) + const emulator_object>> windir_obj{c.emu, obj_address}; + windir_obj.access([&](UNICODE_STRING>& ucs) { const auto dir_address = kusd_mmio::address() + offsetof(KUSER_SHARED_DATA, NtSystemRoot); - ucs.Buffer = reinterpret_cast(dir_address - obj_address); + ucs.Buffer = dir_address - obj_address; ucs.Length = static_cast(windows_dir_size); ucs.MaximumLength = ucs.Length; }); - const emulator_object sysdir_obj{c.emu, obj_address + windir_obj.size()}; - sysdir_obj.access([&](UNICODE_STRING& ucs) + const emulator_object>> sysdir_obj{c.emu, obj_address + windir_obj.size()}; + sysdir_obj.access([&](UNICODE_STRING>& ucs) { - c.proc.base_allocator.make_unicode_string(ucs, L"C:\\WINDOWS\\System32"); - ucs.Buffer = reinterpret_cast(reinterpret_cast(ucs.Buffer) - obj_address); + c.proc.base_allocator.make_unicode_string(ucs, u"C:\\WINDOWS\\System32"); + ucs.Buffer = ucs.Buffer - obj_address; }); if (view_size.value()) @@ -1139,7 +1141,7 @@ namespace const auto peb = c.proc.peb.read(); emulator_object proc_params{c.emu, peb.ProcessParameters}; const auto params = proc_params.read(); - const auto length = params.ImagePathName.Length + sizeof(UNICODE_STRING) + 2; + const auto length = params.ImagePathName.Length + sizeof(UNICODE_STRING>) + 2; if (return_length) { @@ -1159,7 +1161,7 @@ namespace c.emu.write_memory(buffer_start, string.c_str(), (string.size() + 1) * 2); str.Length = params.ImagePathName.Length; str.MaximumLength = str.Length; - str.Buffer = reinterpret_cast(buffer_start); + str.Buffer = buffer_start; }); return STATUS_SUCCESS; @@ -1426,7 +1428,7 @@ namespace const emulator_object object_attributes) { const auto attributes = object_attributes.read(); - const auto object_name = read_unicode_string(c.emu, attributes.ObjectName); + const auto object_name = read_unicode_string(c.emu, reinterpret_cast>*>(attributes.ObjectName)); if (object_name == L"\\KnownDlls") { @@ -1442,7 +1444,7 @@ namespace const emulator_object object_attributes) { const auto attributes = object_attributes.read(); - const auto object_name = read_unicode_string(c.emu, attributes.ObjectName); + const auto object_name = read_unicode_string(c.emu, reinterpret_cast>*>(attributes.ObjectName)); if (object_name == L"KnownDllPath") { @@ -1459,14 +1461,14 @@ namespace { if (link_handle == KNOWN_DLLS_SYMLINK) { - constexpr std::wstring_view system32 = L"C:\\WINDOWS\\System32"; + constexpr std::u16string_view system32 = u"C:\\WINDOWS\\System32"; constexpr auto str_length = system32.size() * 2; constexpr auto max_length = str_length + 2; returned_length.write(max_length); bool too_small = false; - link_target.access([&](UNICODE_STRING& str) + link_target.access([&](UNICODE_STRING>& str) { if (str.MaximumLength < max_length) { @@ -1592,7 +1594,7 @@ namespace } NTSTATUS handle_NtConnectPort(const syscall_context& c, const emulator_object client_port_handle, - const emulator_object server_port_name, + const emulator_object>> server_port_name, const emulator_object /*security_qos*/, const emulator_object client_shared_memory, const emulator_object /*server_shared_memory*/, @@ -1855,7 +1857,7 @@ namespace return STATUS_INVALID_HANDLE; } - if (port->name != L"\\Windows\\ApiPort") + if (port->name != u"\\Windows\\ApiPort") { puts("!!! BAD PORT"); return STATUS_NOT_SUPPORTED; @@ -2009,9 +2011,9 @@ namespace return STATUS_SUCCESS; } - const wchar_t* map_mode(const ACCESS_MASK desired_access, const ULONG create_disposition) + constexpr std::u16string map_mode(const ACCESS_MASK desired_access, const ULONG create_disposition) { - const auto* mode = L""; + std::u16string mode = u""; switch (create_disposition) { @@ -2019,7 +2021,7 @@ namespace case FILE_SUPERSEDE: if (desired_access & GENERIC_WRITE) { - mode = L"wb"; + mode = u"wb"; } break; @@ -2027,11 +2029,11 @@ namespace case FILE_OPEN_IF: if (desired_access & GENERIC_WRITE) { - mode = L"r+b"; + mode = u"r+b"; } else if (desired_access & GENERIC_READ) { - mode = L"rb"; + mode = u"rb"; } break; @@ -2039,18 +2041,18 @@ namespace case FILE_OVERWRITE_IF: if (desired_access & GENERIC_WRITE) { - mode = L"w+b"; + mode = u"w+b"; } break; default: - mode = L""; + mode = u""; break; } if (desired_access & FILE_APPEND_DATA) { - mode = L"a+b"; + mode = u"a+b"; } return mode; @@ -2066,14 +2068,14 @@ namespace ULONG ea_length) { const auto attributes = object_attributes.read(); - auto filename = read_unicode_string(c.emu, attributes.ObjectName); + auto filename = read_unicode_string(c.emu, reinterpret_cast>*>(attributes.ObjectName)); auto printer = utils::finally([&] { c.win_emu.logger.print(color::dark_gray, "--> Opening file: %S\n", filename.c_str()); }); - constexpr std::wstring_view device_prefix = L"\\Device\\"; + constexpr std::u16string_view device_prefix = u"\\Device\\"; if (filename.starts_with(device_prefix)) { const io_device_creation_data data{ @@ -2092,7 +2094,7 @@ namespace handle root_handle{}; root_handle.bits = reinterpret_cast(attributes.RootDirectory); - if (root_handle.value.is_pseudo && (filename == L"\\Reference" || filename == L"\\Connect")) + if (root_handle.value.is_pseudo && (filename == u"\\Reference" || filename == u"\\Connect")) { file_handle.write(root_handle); return STATUS_SUCCESS; @@ -2114,7 +2116,7 @@ namespace printer.cancel(); - if (f.name.ends_with(L"\\") || create_options & FILE_DIRECTORY_FILE) + if (f.name.ends_with(u"\\") || create_options & FILE_DIRECTORY_FILE) { c.win_emu.logger.print(color::dark_gray, "--> Opening folder: %S\n", f.name.c_str()); @@ -2141,15 +2143,17 @@ namespace c.win_emu.logger.print(color::dark_gray, "--> Opening file: %S\n", f.name.c_str()); - const auto* mode = map_mode(desired_access, create_disposition); + std::u16string mode = map_mode(desired_access, create_disposition); - if (!mode || wcslen(mode) == 0) + if (mode.length() == 0 || mode == u"") { return STATUS_NOT_SUPPORTED; } FILE* file{}; - const auto error = _wfopen_s(&file, f.name.c_str(), mode); + // TODO: fix unicode conversion + //const auto error = _wfopen_s(&file, f.name.c_str(), mode); + const auto error = EACCES; if (!file) { @@ -2212,7 +2216,7 @@ namespace NTSTATUS handle_NtRaiseHardError(const syscall_context& c, const NTSTATUS error_status, const ULONG /*number_of_parameters*/, - const emulator_object /*unicode_string_parameter_mask*/, + const emulator_object>> /*unicode_string_parameter_mask*/, const emulator_object /*parameters*/, const HARDERROR_RESPONSE_OPTION /*valid_response_option*/, const emulator_object response) @@ -2260,7 +2264,7 @@ namespace const auto attributes = object_attributes.read(); if (attributes.ObjectName) { - s.name = read_unicode_string(c.emu, attributes.ObjectName); + s.name = read_unicode_string(c.emu, reinterpret_cast>*>(attributes.ObjectName)); } } diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index fa8ef0c4..c04e5b9f 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -215,33 +215,33 @@ namespace proc_params.StandardInput = STDIN_HANDLE.h; proc_params.StandardError = proc_params.StandardOutput; - proc_params.Environment = allocator.copy_string(L"=::=::\\"); - allocator.copy_string(L"EMULATOR=1"); - allocator.copy_string(L"COMPUTERNAME=momo"); - allocator.copy_string(L"SystemRoot=C:\\WINDOWS"); - allocator.copy_string(L""); + proc_params.Environment = reinterpret_cast(allocator.copy_string(u"=::=::\\")); + allocator.copy_string(u"EMULATOR=1"); + allocator.copy_string(u"COMPUTERNAME=momo"); + allocator.copy_string(u"SystemRoot=C:\\WINDOWS"); + allocator.copy_string(u""); - std::wstring command_line = L"\"" + settings.application.wstring() + L"\""; + std::u16string command_line = u"\"" + settings.application.u16string() + u"\""; for (const auto& arg : settings.arguments) { - command_line.push_back(L' '); + command_line.push_back(u' '); command_line.append(arg); } - std::wstring current_folder{}; + std::u16string current_folder{}; if (!settings.working_directory.empty()) { - current_folder = canonicalize_path(settings.working_directory).wstring() + L"\\"; + current_folder = canonicalize_path(settings.working_directory).u16string() + u"\\"; } else { - current_folder = canonicalize_path(settings.application).parent_path().wstring() + L"\\"; + 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.ImagePathName, canonicalize_path(settings.application).wstring()); + allocator.make_unicode_string(proc_params.ImagePathName, canonicalize_path(settings.application).u16string()); const auto total_length = allocator.get_next_address() - context.process_params.value(); diff --git a/src/windows-emulator/windows_emulator.hpp b/src/windows-emulator/windows_emulator.hpp index a31f39f5..e5f59f89 100644 --- a/src/windows-emulator/windows_emulator.hpp +++ b/src/windows-emulator/windows_emulator.hpp @@ -15,7 +15,7 @@ struct emulator_settings std::filesystem::path application{}; std::filesystem::path working_directory{}; std::filesystem::path registry_directory{"./registry"}; - std::vector arguments{}; + std::vector arguments{}; std::function stdout_callback{}; bool disable_logging{false}; bool use_relative_time{false};