diff --git a/deps/windows-hive-parser b/deps/windows-hive-parser index b1bd6ca4..fdeabc39 160000 --- a/deps/windows-hive-parser +++ b/deps/windows-hive-parser @@ -1 +1 @@ -Subproject commit b1bd6ca49e4a91f0def04100b30564ae25d411ed +Subproject commit fdeabc39b1ed79fb7472fd08288eba8e6649a812 diff --git a/src/windows-emulator/handles.hpp b/src/windows-emulator/handles.hpp index 49fd1d55..8ee8d1d0 100644 --- a/src/windows-emulator/handles.hpp +++ b/src/windows-emulator/handles.hpp @@ -13,6 +13,7 @@ struct handle_types semaphore, port, thread, + registry, }; }; diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index b2b104e0..3caf52ce 100644 --- a/src/windows-emulator/process_context.hpp +++ b/src/windows-emulator/process_context.hpp @@ -2,6 +2,7 @@ #include "emulator_utils.hpp" #include "handles.hpp" +#include "registry_manager.hpp" #include "module/module_manager.hpp" #include @@ -375,6 +376,8 @@ struct process_context { } + registry_manager registry{R"(C:\Users\mauri\Desktop\windows\win-x64\registry)"}; // TODO: Fix + uint64_t executed_instructions{0}; uint64_t current_ip{0}; uint64_t previous_ip{0}; @@ -404,6 +407,7 @@ struct process_context handle_store files{}; handle_store semaphores{}; handle_store ports{}; + handle_store registry_keys{}; std::map atoms{}; std::vector default_register_set{}; @@ -414,6 +418,7 @@ struct process_context void serialize(utils::buffer_serializer& buffer) const { + buffer.write(this->registry); buffer.write(this->executed_instructions); buffer.write(this->current_ip); buffer.write(this->previous_ip); @@ -438,6 +443,7 @@ struct process_context buffer.write(this->files); buffer.write(this->semaphores); buffer.write(this->ports); + buffer.write(this->registry_keys); buffer.write_map(this->atoms); buffer.write_vector(this->default_register_set); @@ -449,6 +455,7 @@ struct process_context void deserialize(utils::buffer_deserializer& buffer) { + buffer.read(this->registry); buffer.read(this->executed_instructions); buffer.read(this->current_ip); buffer.read(this->previous_ip); @@ -477,6 +484,7 @@ struct process_context buffer.read(this->files); buffer.read(this->semaphores); buffer.read(this->ports); + buffer.read(this->registry_keys); buffer.read_map(this->atoms); buffer.read_vector(this->default_register_set); diff --git a/src/windows-emulator/registry_manager.cpp b/src/windows-emulator/registry_manager.cpp new file mode 100644 index 00000000..7137df9b --- /dev/null +++ b/src/windows-emulator/registry_manager.cpp @@ -0,0 +1,123 @@ +#include "registry_manager.hpp" +#include + +namespace +{ + std::filesystem::path canonicalize_path(const std::filesystem::path& key) + { + auto path = key.lexically_normal().wstring(); + std::ranges::transform(path, path.begin(), std::towlower); + return {std::move(path)}; + } + + bool is_subpath(const std::filesystem::path& root, const std::filesystem::path& p) + { + auto root_it = root.begin(); + auto p_it = p.begin(); + + for (; root_it != root.end(); ++root_it, ++p_it) + { + if (p_it == p.end() || *root_it != *p_it) + { + return false; + } + } + + return true; + } + + void register_hive(registry_manager::hive_map& hives, + const std::filesystem::path& key, const std::filesystem::path& file) + { + hives[canonicalize_path(key)] = std::make_unique(file); + } +} + +registry_manager::~registry_manager() = default; + +registry_manager::registry_manager(const std::filesystem::path& hive_path) +{ + const std::filesystem::path root = R"(\registry)"; + const std::filesystem::path machine = root / "machine"; + + register_hive(this->hives_, machine / "system", hive_path / "SYSTEM"); + register_hive(this->hives_, machine / "security", hive_path / "SECURITY"); + register_hive(this->hives_, machine / "sam", hive_path / "SAM"); + register_hive(this->hives_, machine / "software", hive_path / "SOFTWARE"); + register_hive(this->hives_, machine / "system", hive_path / "SYSTEM"); + register_hive(this->hives_, machine / "hardware", hive_path / "HARDWARE"); + + register_hive(this->hives_, root / "user", hive_path / "NTUSER.dat"); + + this->add_path_mapping(machine / "system" / "CurrentControlSet", machine / "system" / "ControlSet001"); +} + +void registry_manager::serialize(utils::buffer_serializer& buffer) const +{ + (void)buffer; +} + +void registry_manager::deserialize(utils::buffer_deserializer& buffer) +{ + (void)buffer; +} + +std::filesystem::path registry_manager::normalize_path(const std::filesystem::path& path) const +{ + auto canonical_path = canonicalize_path(path); + + for (const auto& mapping : this->path_mapping_) + { + if (is_subpath(mapping.first, canonical_path)) + { + return mapping.second / canonical_path.lexically_relative(mapping.first); + } + } + + return canonical_path; +} + +void registry_manager::add_path_mapping(const std::filesystem::path& key, const std::filesystem::path& value) +{ + this->path_mapping_[canonicalize_path(key)] = canonicalize_path(value); +} + +std::optional registry_manager::get_key(const std::filesystem::path& key) +{ + const auto normal_key = this->normalize_path(key); + const auto iterator = this->find_hive(normal_key); + if (iterator == this->hives_.end()) + { + return {}; + } + + registry_key reg_key{}; + reg_key.hive = iterator->first; + reg_key.path = normal_key.lexically_relative(reg_key.hive); + + if (reg_key.path.empty()) + { + return {std::move(reg_key)}; + } + + const auto entry = iterator->second->get_subkey(reg_key.path.begin()->string(), reg_key.path.generic_string()); + if (!entry) + { + return {}; + } + + return {std::move(reg_key)}; +} + +registry_manager::hive_map::iterator registry_manager::find_hive(const std::filesystem::path& key) +{ + for (auto i = this->hives_.begin(); i != this->hives_.end(); ++i) + { + if (is_subpath(i->first, key)) + { + return i; + } + } + + return this->hives_.end(); +} diff --git a/src/windows-emulator/registry_manager.hpp b/src/windows-emulator/registry_manager.hpp new file mode 100644 index 00000000..3f96cbde --- /dev/null +++ b/src/windows-emulator/registry_manager.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include "std_include.hpp" +#include + +class hive_parser; + +struct registry_key +{ + std::filesystem::path hive{}; + std::filesystem::path path{}; + + void serialize(utils::buffer_serializer& buffer) const + { + buffer.write_string(this->hive.wstring()); + buffer.write_string(this->path.wstring()); + } + + void deserialize(utils::buffer_deserializer& buffer) + { + this->hive = buffer.read_string(); + this->path = buffer.read_string(); + } +}; + +class registry_manager +{ +public: + using hive_ptr = std::unique_ptr; + using hive_map = std::unordered_map; + + registry_manager(const std::filesystem::path& hive_path); + ~registry_manager(); + + void serialize(utils::buffer_serializer& buffer) const; + void deserialize(utils::buffer_deserializer& buffer); + + std::optional get_key(const std::filesystem::path& key); + +private: + hive_map hives_{}; + std::unordered_map path_mapping_{}; + + std::filesystem::path normalize_path(const std::filesystem::path& path) const; + void add_path_mapping(const std::filesystem::path& key, const std::filesystem::path& value); + + hive_map::iterator find_hive(const std::filesystem::path& key); +}; diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index a848be4b..9bd29fa7 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -53,7 +53,7 @@ namespace return STATUS_NOT_SUPPORTED; } - NTSTATUS handle_NtOpenKey(const syscall_context& c, const emulator_object /*key_handle*/, + NTSTATUS handle_NtOpenKey(const syscall_context& c, const emulator_object key_handle, const ACCESS_MASK /*desired_access*/, const emulator_object object_attributes) { @@ -62,7 +62,16 @@ namespace c.win_emu.logger.print(color::dark_gray, "--> Registry key: %S\n", key.c_str()); - return STATUS_OBJECT_NAME_NOT_FOUND; + auto entry = c.proc.registry.get_key(key); + if (!entry.has_value()) + { + return STATUS_OBJECT_NAME_NOT_FOUND; + } + + const auto handle = c.proc.registry_keys.store(std::move(entry.value())); + key_handle.write(handle.bits); + + return STATUS_SUCCESS; } NTSTATUS handle_NtOpenKeyEx()