From d1557693337b3c16aa7ee1d3d9ef6a000b9897c5 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Mon, 4 Nov 2024 18:36:18 +0100 Subject: [PATCH] Fix basic registry support and add test --- src/test-sample/test.cpp | 48 ++++++++++++++++++- src/windows-emulator/handles.hpp | 6 +-- src/windows-emulator/process_context.hpp | 2 +- src/windows-emulator/registry/hive_parser.cpp | 2 +- .../registry/registry_manager.cpp | 14 +++++- .../registry/registry_manager.hpp | 2 +- src/windows-emulator/syscalls.cpp | 12 +++-- 7 files changed, 74 insertions(+), 12 deletions(-) diff --git a/src/test-sample/test.cpp b/src/test-sample/test.cpp index 927a0fc..2e7b9dc 100644 --- a/src/test-sample/test.cpp +++ b/src/test-sample/test.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -92,6 +93,49 @@ bool test_io() return text == buffer; } +std::optional read_registry_string(const HKEY root, const char* path, const char* value) +{ + HKEY key{}; + if (RegOpenKeyExA(root, path, 0, KEY_READ, &key) != + ERROR_SUCCESS) + { + return std::nullopt; + } + + char data[MAX_PATH]{}; + DWORD length = sizeof(data); + const auto res = RegQueryValueExA(key, value, nullptr, nullptr, reinterpret_cast(data), &length); + + if (RegCloseKey(key) != ERROR_SUCCESS) + { + return std::nullopt; + } + + if (res != ERROR_SUCCESS) + { + return std::nullopt; + } + + if (length == 0) + { + return ""; + } + + return {std::string(data, min(length - 1, sizeof(data)))}; +} + +bool test_registry() +{ + const auto val = read_registry_string(HKEY_LOCAL_MACHINE, R"(SOFTWARE\Microsoft\Windows\CurrentVersion)", + "ProgramFilesDir"); + if (!val) + { + return false; + } + + return *val == "C:\\Program Files"; +} + void throw_exception() { if (do_the_task) @@ -128,7 +172,8 @@ bool test_native_exceptions() throw_native_exception(); return false; } - __except(EXCEPTION_EXECUTE_HANDLER) { + __except (EXCEPTION_EXECUTE_HANDLER) + { return true; } } @@ -146,6 +191,7 @@ int main(int /*argc*/, const char* /*argv*/[]) bool valid = true; RUN_TEST(test_io, "I/O") + RUN_TEST(test_registry, "Registry") RUN_TEST(test_threads, "Threads") RUN_TEST(test_env, "Environment") RUN_TEST(test_exceptions, "Exceptions") diff --git a/src/windows-emulator/handles.hpp b/src/windows-emulator/handles.hpp index 8ee8d1d..0013f23 100644 --- a/src/windows-emulator/handles.hpp +++ b/src/windows-emulator/handles.hpp @@ -95,7 +95,7 @@ namespace handle_detail }; } -template +template requires(utils::Serializable) class handle_store { @@ -117,7 +117,7 @@ class handle_store h.bits = 0; h.value.is_pseudo = false; h.value.type = Type; - h.value.id = index; + h.value.id = index << IndexShift; return h; } @@ -287,7 +287,7 @@ class handle_store return this->store_.end(); } - return this->store_.find(h.id); + return this->store_.find(h.id >> IndexShift); } uint32_t find_free_index() diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index 3a1a780..919f69c 100644 --- a/src/windows-emulator/process_context.hpp +++ b/src/windows-emulator/process_context.hpp @@ -394,7 +394,7 @@ struct process_context handle_store files{}; handle_store semaphores{}; handle_store ports{}; - handle_store registry_keys{}; + handle_store registry_keys{}; std::map atoms{}; std::vector default_register_set{}; diff --git a/src/windows-emulator/registry/hive_parser.cpp b/src/windows-emulator/registry/hive_parser.cpp index 03190cb..e9825f3 100644 --- a/src/windows-emulator/registry/hive_parser.cpp +++ b/src/windows-emulator/registry/hive_parser.cpp @@ -149,7 +149,7 @@ const hive_value* hive_key::get_value(std::ifstream& file, const std::string_vie auto& value = entry->second; - if (value.parsed) + if (!value.parsed) { value.data = read_file_data(file, MAIN_ROOT_OFFSET + value.data_offset, value.data_length); value.parsed = true; diff --git a/src/windows-emulator/registry/registry_manager.cpp b/src/windows-emulator/registry/registry_manager.cpp index e55d304..193bf65 100644 --- a/src/windows-emulator/registry/registry_manager.cpp +++ b/src/windows-emulator/registry/registry_manager.cpp @@ -7,6 +7,14 @@ namespace { + void string_to_lower(std::string& str) + { + std::ranges::transform(str, str.begin(), [](const char val) + { + return static_cast(std::tolower(static_cast(val))); + }); + } + std::filesystem::path canonicalize_path(const std::filesystem::path& key) { auto path = key.lexically_normal().wstring(); @@ -107,7 +115,7 @@ std::optional registry_manager::get_key(const std::filesystem::pat { registry_key reg_key{}; reg_key.hive = normal_key; - return { std::move(reg_key) }; + return {std::move(reg_key)}; } const auto iterator = this->find_hive(normal_key); @@ -134,8 +142,10 @@ std::optional registry_manager::get_key(const std::filesystem::pat return {std::move(reg_key)}; } -std::optional registry_manager::get_value(const registry_key& key, const std::string_view name) +std::optional registry_manager::get_value(const registry_key& key, std::string name) { + string_to_lower(name); + const auto iterator = this->hives_.find(key.hive); if (iterator == this->hives_.end()) { diff --git a/src/windows-emulator/registry/registry_manager.hpp b/src/windows-emulator/registry/registry_manager.hpp index 7115337..af67214 100644 --- a/src/windows-emulator/registry/registry_manager.hpp +++ b/src/windows-emulator/registry/registry_manager.hpp @@ -51,7 +51,7 @@ class registry_manager void deserialize(utils::buffer_deserializer& buffer); std::optional get_key(const std::filesystem::path& key); - std::optional get_value(const registry_key& key, const std::string_view name); + std::optional get_value(const registry_key& key, std::string name); private: std::filesystem::path hive_path_{}; diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index c4ed8f1..473a701 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -183,7 +183,7 @@ namespace if (key_value_information_class == KeyValueBasicInformation) { - const auto required_size = sizeof(KEY_VALUE_BASIC_INFORMATION) + (original_name.size() * 2) - 1; + const auto required_size = offsetof(KEY_VALUE_BASIC_INFORMATION, Name) + (original_name.size() * 2) - 1; result_length.write(static_cast(required_size)); if (required_size > length) @@ -208,7 +208,7 @@ namespace if (key_value_information_class == KeyValuePartialInformation) { - const auto required_size = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + value->data.size() - 1; + const auto required_size = offsetof(KEY_VALUE_PARTIAL_INFORMATION, Data) + value->data.size(); result_length.write(static_cast(required_size)); if (required_size > length) @@ -235,7 +235,7 @@ namespace { const auto name_size = original_name.size() * 2; const auto value_size = value->data.size(); - const auto required_size = sizeof(KEY_VALUE_FULL_INFORMATION) + name_size + value_size + -1; + const auto required_size = offsetof(KEY_VALUE_FULL_INFORMATION, Name) + name_size + value_size + -1; result_length.write(static_cast(required_size)); if (required_size > length) @@ -268,6 +268,11 @@ namespace return STATUS_NOT_SUPPORTED; } + NTSTATUS handle_NtCreateKey() + { + return STATUS_NOT_SUPPORTED; + } + NTSTATUS handle_NtSetInformationThread(const syscall_context& c, const uint64_t thread_handle, const THREADINFOCLASS info_class, const uint64_t thread_information, @@ -2537,6 +2542,7 @@ void syscall_dispatcher::add_handlers(std::map& ha add_handler(NtQueryKey); add_handler(NtGetNlsSectionPtr); add_handler(NtAccessCheck); + add_handler(NtCreateKey); #undef add_handler }