Fixes for section mapping and registry (#635)

This commit is contained in:
Maurice Heumann
2025-12-23 11:50:54 +01:00
committed by GitHub
6 changed files with 107 additions and 7 deletions

View File

@@ -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;

View File

@@ -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_;

View File

@@ -209,6 +209,26 @@ registry_manager::hive_map::iterator registry_manager::find_hive(const utils::pa
return this->hives_.end();
}
std::optional<exposed_hive_key> 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<std::string_view> registry_manager::get_sub_key_name(const registry_key& key, const size_t index)
{
const auto iterator = this->hives_.find(key.hive);

View File

@@ -54,6 +54,12 @@ struct registry_value
std::span<const std::byte> data;
};
struct exposed_hive_key
{
hive_key& key;
std::ifstream& file;
};
class registry_manager
{
public:
@@ -76,6 +82,8 @@ class registry_manager
std::optional<std::string_view> get_sub_key_name(const registry_key& key, size_t index);
std::optional<exposed_hive_key> get_hive_key(const registry_key& key);
private:
std::filesystem::path hive_path_{};
hive_map hives_{};

View File

@@ -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<ULONG>(hive_key->key.get_sub_key_count(hive_key->file));
info.Values = static_cast<ULONG>(hive_key->key.get_value_count(hive_key->file));
info.NameLength = static_cast<ULONG>(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);

View File

@@ -248,7 +248,7 @@ namespace syscalls
const emulator_object<uint64_t> base_address,
const EMULATOR_CAST(EmulatorTraits<Emu64>::ULONG_PTR, ULONG_PTR) /*zero_bits*/,
const EMULATOR_CAST(EmulatorTraits<Emu64>::SIZE_T, SIZE_T) /*commit_size*/,
const emulator_object<LARGE_INTEGER> /*section_offset*/,
const emulator_object<LARGE_INTEGER> section_offset,
const emulator_object<EMULATOR_CAST(EmulatorTraits<Emu64>::SIZE_T, SIZE_T)> view_size,
const SECTION_INHERIT /*inherit_disposition*/, const ULONG /*allocation_type*/,
const ULONG /*win32_protect*/)
@@ -350,9 +350,16 @@ namespace syscalls
return STATUS_SUCCESS;
}
uint64_t size = section_entry->maximum_size;
auto size = static_cast<size_t>(section_entry->maximum_size);
std::vector<std::byte> file_data{};
int64_t offset = 0;
if (section_offset)
{
offset = section_offset.read().QuadPart;
offset = std::max<int64_t>(offset, 0);
}
if (!section_entry->file_name.empty())
{
if (!utils::io::read_file(c.win_emu.file_sys.translate(section_entry->file_name), &file_data))
@@ -360,21 +367,22 @@ namespace syscalls
return STATUS_INVALID_PARAMETER;
}
size = page_align_up(file_data.size());
size = static_cast<size_t>(file_data.size() - offset);
}
const auto aligned_size = static_cast<size_t>(page_align_up(size));
const auto reserve_only = section_entry->allocation_attributes == SEC_RESERVE;
const auto protection = map_nt_to_emulator_protection(section_entry->section_page_protection);
const auto address = c.win_emu.memory.allocate_memory(static_cast<size_t>(size), protection, reserve_only);
const auto address = c.win_emu.memory.allocate_memory(aligned_size, protection, reserve_only);
if (!reserve_only && !file_data.empty())
{
c.emu.write_memory(address, file_data.data(), file_data.size());
c.emu.write_memory(address, file_data.data() + offset, size);
}
if (view_size)
{
view_size.write(size);
view_size.write(aligned_size);
}
base_address.write(address);