From db3a89a0da2a0329e60093af1f1733cebfca0bd3 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Tue, 23 Dec 2025 09:31:10 +0100 Subject: [PATCH] Support KeyCachedInformation --- src/common/platform/registry.hpp | 12 ++++++ src/windows-emulator/registry/hive_parser.hpp | 17 +++++++++ .../registry/registry_manager.cpp | 20 ++++++++++ .../registry/registry_manager.hpp | 8 ++++ src/windows-emulator/syscalls/registry.cpp | 37 ++++++++++++++++++- 5 files changed, 93 insertions(+), 1 deletion(-) diff --git a/src/common/platform/registry.hpp b/src/common/platform/registry.hpp index a44e8b2e..af2d7286 100644 --- a/src/common/platform/registry.hpp +++ b/src/common/platform/registry.hpp @@ -67,6 +67,18 @@ typedef struct _KEY_FULL_INFORMATION char16_t Class[1]; } KEY_FULL_INFORMATION, *PKEY_FULL_INFORMATION; +typedef struct _KEY_CACHED_INFORMATION +{ + LARGE_INTEGER LastWriteTime; + ULONG TitleIndex; + ULONG SubKeys; + ULONG MaxNameLen; + ULONG Values; + ULONG MaxValueNameLen; + ULONG MaxValueDataLen; + ULONG NameLength; +} KEY_CACHED_INFORMATION, *PKEY_CACHED_INFORMATION; + struct KEY_HANDLE_TAGS_INFORMATION { ULONG HandleTags; diff --git a/src/windows-emulator/registry/hive_parser.hpp b/src/windows-emulator/registry/hive_parser.hpp index 0db9979b..6fa98440 100644 --- a/src/windows-emulator/registry/hive_parser.hpp +++ b/src/windows-emulator/registry/hive_parser.hpp @@ -62,6 +62,18 @@ class hive_key const hive_value* get_value(std::ifstream& file, std::string_view name); const hive_value* get_value(std::ifstream& file, size_t index); + size_t get_sub_key_count(std::ifstream& file) + { + this->parse(file); + return this->sub_keys_.size(); + } + + size_t get_value_count(std::ifstream& file) + { + this->parse(file); + return this->values_.size(); + } + private: struct raw_hive_value : hive_value { @@ -138,6 +150,11 @@ class hive_parser return sub_key->get_value(this->file_, index); } + std::ifstream& get_file() + { + return this->file_; + } + private: std::ifstream file_{}; hive_key root_key_; diff --git a/src/windows-emulator/registry/registry_manager.cpp b/src/windows-emulator/registry/registry_manager.cpp index 9979e7d4..0845af99 100644 --- a/src/windows-emulator/registry/registry_manager.cpp +++ b/src/windows-emulator/registry/registry_manager.cpp @@ -209,6 +209,26 @@ registry_manager::hive_map::iterator registry_manager::find_hive(const utils::pa return this->hives_.end(); } +std::optional registry_manager::get_hive_key(const registry_key& key) +{ + const auto iterator = this->hives_.find(key.hive); + if (iterator == this->hives_.end()) + { + return std::nullopt; + } + + auto* hive_key = iterator->second->get_sub_key(key.path.get()); + if (!hive_key) + { + return std::nullopt; + } + + return exposed_hive_key{ + .key = *hive_key, + .file = iterator->second->get_file(), + }; +} + std::optional registry_manager::get_sub_key_name(const registry_key& key, const size_t index) { const auto iterator = this->hives_.find(key.hive); diff --git a/src/windows-emulator/registry/registry_manager.hpp b/src/windows-emulator/registry/registry_manager.hpp index 81e0cb79..d0c48fc9 100644 --- a/src/windows-emulator/registry/registry_manager.hpp +++ b/src/windows-emulator/registry/registry_manager.hpp @@ -54,6 +54,12 @@ struct registry_value std::span data; }; +struct exposed_hive_key +{ + hive_key& key; + std::ifstream& file; +}; + class registry_manager { public: @@ -76,6 +82,8 @@ class registry_manager std::optional get_sub_key_name(const registry_key& key, size_t index); + std::optional get_hive_key(const registry_key& key); + private: std::filesystem::path hive_path_{}; hive_map hives_{}; diff --git a/src/windows-emulator/syscalls/registry.cpp b/src/windows-emulator/syscalls/registry.cpp index d511b224..baf880dd 100644 --- a/src/windows-emulator/syscalls/registry.cpp +++ b/src/windows-emulator/syscalls/registry.cpp @@ -82,11 +82,46 @@ namespace syscalls return STATUS_SUCCESS; } - if (key_information_class == KeyFullInformation || key_information_class == KeyCachedInformation) + if (key_information_class == KeyFullInformation) { + c.win_emu.log.warn("Unsupported registry class: %X\n", key_information_class); return STATUS_NOT_SUPPORTED; } + if (key_information_class == KeyCachedInformation) + { + 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(); + } + + const auto hive_key = c.win_emu.registry.get_hive_key(*key); + if (!hive_key.has_value()) + { + return STATUS_OBJECT_NAME_NOT_FOUND; + } + + constexpr auto required_size = sizeof(KEY_CACHED_INFORMATION); + result_length.write(required_size); + + if (required_size > length) + { + return STATUS_BUFFER_TOO_SMALL; + } + + KEY_CACHED_INFORMATION info{}; + info.SubKeys = static_cast(hive_key->key.get_sub_key_count(hive_key->file)); + info.Values = static_cast(hive_key->key.get_value_count(hive_key->file)); + info.NameLength = static_cast(key_name.size() * 2); + info.MaxValueDataLen = 0x1000; + info.MaxValueNameLen = 0x1000; + info.MaxNameLen = 0x1000; + + c.emu.write_memory(key_information, info); + return STATUS_SUCCESS; + } + if (key_information_class == KeyHandleTagsInformation) { constexpr auto required_size = sizeof(KEY_HANDLE_TAGS_INFORMATION);