From 34b4bc160981ab7138df9b9a4ec2f00e3e4ef669 Mon Sep 17 00:00:00 2001 From: ahm3dgg Date: Wed, 14 Jan 2026 06:09:05 +0200 Subject: [PATCH] Correctly build transitive dll list --- src/common/utils/string.hpp | 31 ------- src/windows-emulator/apiset/apiset.hpp | 1 - .../module/module_manager.cpp | 6 +- src/windows-emulator/process_context.cpp | 91 ++++++++----------- .../registry/registry_manager.cpp | 31 +++++++ .../registry/registry_manager.hpp | 2 + src/windows-emulator/syscalls/section.cpp | 23 ++--- 7 files changed, 85 insertions(+), 100 deletions(-) diff --git a/src/common/utils/string.hpp b/src/common/utils/string.hpp index d1980f56..66ff551d 100644 --- a/src/common/utils/string.hpp +++ b/src/common/utils/string.hpp @@ -170,12 +170,6 @@ namespace utils::string return data; } - template - bool equals_ignore_case(const std::basic_string& lhs, const std::basic_string_view rhs) - { - return std::ranges::equal(lhs, rhs, [](const auto c1, const auto c2) { return char_to_lower(c1) == char_to_lower(c2); }); - } - template bool equals_ignore_case(const std::basic_string& lhs, const std::basic_string& rhs) { @@ -188,18 +182,6 @@ namespace utils::string return std::ranges::equal(lhs, rhs, [](const auto c1, const auto c2) { return char_to_lower(c1) == char_to_lower(c2); }); } - template - bool starts_with_ignore_case(const std::basic_string& lhs, const std::basic_string_view rhs) - { - if (lhs.length() < rhs.length()) - { - return false; - } - - return std::ranges::equal(lhs.substr(0, rhs.length()), rhs, - [](const auto c1, const auto c2) { return char_to_lower(c1) == char_to_lower(c2); }); - } - template bool starts_with_ignore_case(const std::basic_string& lhs, const std::basic_string& rhs) { @@ -224,19 +206,6 @@ namespace utils::string [](const auto c1, const auto c2) { return char_to_lower(c1) == char_to_lower(c2); }); } - template - bool ends_with_ignore_case(const std::basic_string& lhs, const std::basic_string_view& rhs) - { - if (lhs.length() < rhs.length()) - { - return false; - } - - auto start = lhs.length() - rhs.length(); - return std::ranges::equal(lhs.substr(start, rhs.length()), rhs, - [](const auto c1, const auto c2) { return char_to_lower(c1) == char_to_lower(c2); }); - } - template bool ends_with_ignore_case(const std::basic_string& lhs, const std::basic_string& rhs) { diff --git a/src/windows-emulator/apiset/apiset.hpp b/src/windows-emulator/apiset/apiset.hpp index 21002fcb..c2cdbe7b 100644 --- a/src/windows-emulator/apiset/apiset.hpp +++ b/src/windows-emulator/apiset/apiset.hpp @@ -4,7 +4,6 @@ #include #include #include - #include "../emulator_utils.hpp" using apiset_map = std::map; diff --git a/src/windows-emulator/module/module_manager.cpp b/src/windows-emulator/module/module_manager.cpp index 10bccbff..5430e2e9 100644 --- a/src/windows-emulator/module/module_manager.cpp +++ b/src/windows-emulator/module/module_manager.cpp @@ -455,12 +455,12 @@ std::optional module_manager::get_module_load_count_by_path(const wind { auto local_file = std::filesystem::weakly_canonical(std::filesystem::absolute(this->file_sys_->translate(path))); - if (!modules_load_count.contains(local_file)) + if (auto load_count_entry = modules_load_count.find(local_file); load_count_entry != modules_load_count.end()) { - return {}; + return load_count_entry->second; } - return modules_load_count[local_file]; + return {}; } mapped_module* module_manager::map_module(const windows_path& file, const logger& logger, const bool is_static, bool allow_duplicate) diff --git a/src/windows-emulator/process_context.cpp b/src/windows-emulator/process_context.cpp index 226ee6b8..e7ffb995 100644 --- a/src/windows-emulator/process_context.cpp +++ b/src/windows-emulator/process_context.cpp @@ -7,6 +7,9 @@ #include #include +#include +#include + namespace { emulator_allocator create_allocator(memory_manager& memory, const size_t size, const bool is_wow64_process) @@ -415,8 +418,8 @@ void process_context::setup(x86_64_emulator& emu, memory_manager& memory, regist } this->apiset = apiset::get_namespace_table(reinterpret_cast(apiset_container.data.data())); - this->build_knowndlls_section_table(registry, file_system, apiset, true); this->build_knowndlls_section_table(registry, file_system, apiset, false); + this->build_knowndlls_section_table(registry, file_system, apiset, true); this->ntdll_image_base = ntdll.image_base; this->ldr_initialize_thunk = ntdll.find_export("LdrInitializeThunk"); @@ -772,6 +775,10 @@ void process_context::build_knowndlls_section_table(registry_manager& registry, bool is_32bit) { windows_path system_root_path; + std::set visisted; + std::queue q; + + static const std::wregex apiset_pattern(LR"((api|ext)-[0-9A-Za-z-]+l\d+-\d+-\d+\.dll)", std::regex::icase); if (is_32bit) { @@ -789,53 +796,45 @@ void process_context::build_knowndlls_section_table(registry_manager& registry, return; } - for (size_t i = 0; const auto value_opt = registry.get_value(*knowndlls_key, i); i++) + size_t i = 0; + for (;;) { - const auto& value = *value_opt; + auto known_dll_name_opt = registry.read_u16string(knowndlls_key.value(), i++); - if (value.type != REG_SZ && value.type != REG_EXPAND_SZ) + if (!known_dll_name_opt) { - continue; + break; } - if (value.data.empty() || value.data.size() % 2 != 0) - { - continue; - } + auto known_dll_name = known_dll_name_opt.value(); + q.push(known_dll_name); - const auto char_count = value.data.size() / sizeof(char16_t); - const auto* data_ptr = reinterpret_cast(value.data.data()); - if (data_ptr[char_count - 1] != u'\0') - { - continue; - } + utils::string::to_lower_inplace(known_dll_name); + visisted.insert(known_dll_name); + } - auto known_dll_name = std::u16string(data_ptr, char_count - 1); - auto known_dll_path = system_root_path / known_dll_name; - auto local_known_dll_path = file_system.translate(system_root_path / known_dll_name); + while (!q.empty()) + { + auto knowndll_filename = q.front(); + q.pop(); - if (!std::filesystem::exists(local_known_dll_path)) - { - continue; - } + utils::string::to_lower_inplace(knowndll_filename); std::vector file; - - if (!utils::io::read_file(local_known_dll_path, &file)) + if (!utils::io::read_file(file_system.translate(system_root_path / knowndll_filename), &file)) { continue; } - section knowndll_section; - knowndll_section.file_name = known_dll_path.u16string(); - knowndll_section.maximum_size = 0; - knowndll_section.allocation_attributes = SEC_IMAGE; - knowndll_section.section_page_protection = PAGE_EXECUTE; - knowndll_section.cache_image_info_from_filedata(file); - add_knowndll_section(known_dll_name, knowndll_section, is_32bit); + section s; + s.file_name = (system_root_path / knowndll_filename).u16string(); + s.maximum_size = 0; + s.allocation_attributes = SEC_IMAGE; + s.section_page_protection = PAGE_EXECUTE; + s.cache_image_info_from_filedata(file); + add_knowndll_section(knowndll_filename, s, is_32bit); utils::safe_buffer_accessor buffer{file}; - const auto dos_header = buffer.as(0).get(); const auto nt_headers_offset = dos_header.e_lfanew; const auto nt_headers = buffer.as>(static_cast(nt_headers_offset)).get(); @@ -854,6 +853,7 @@ void process_context::build_knowndlls_section_table(registry_manager& registry, uint64_t import_directory_raw = rva_to_file_offset(import_directory_vbase, import_directory_rbase, import_directory_entry.VirtualAddress); auto import_descriptors = buffer.as(static_cast(import_directory_raw)); + for (size_t import_desc_index = 0;; import_desc_index++) { const auto descriptor = import_descriptors.get(import_desc_index); @@ -864,42 +864,25 @@ void process_context::build_knowndlls_section_table(registry_manager& registry, auto known_dll_dep_name = u8_to_u16( buffer.as_string(static_cast(rva_to_file_offset(import_directory_vbase, import_directory_rbase, descriptor.Name)))); + utils::string::to_lower_inplace(known_dll_dep_name); - if (known_dll_dep_name.starts_with(u"api-") || known_dll_dep_name.starts_with(u"ext-")) + if (std::regex_match(known_dll_dep_name.begin(), known_dll_dep_name.end(), apiset_pattern)) { if (auto apiset_entry = apiset.find(known_dll_dep_name); apiset_entry != apiset.end()) { known_dll_dep_name = apiset_entry->second; } - else { continue; } } - if (has_knowndll_section(known_dll_dep_name, is_32bit)) + if (!visisted.contains(known_dll_dep_name)) { - continue; + q.push(known_dll_dep_name); + visisted.insert(known_dll_dep_name); } - - auto known_dll_dep_path = system_root_path / known_dll_dep_name; - auto local_known_dll_dep_path = file_system.translate(system_root_path / known_dll_dep_name); - - std::vector known_dll_dep_file; - - if (!utils::io::read_file(local_known_dll_dep_path, &known_dll_dep_file)) - { - continue; - } - - section knowndll_dep_section; - knowndll_dep_section.file_name = known_dll_dep_path.u16string(); - knowndll_dep_section.maximum_size = 0; - knowndll_dep_section.allocation_attributes = SEC_IMAGE; - knowndll_dep_section.section_page_protection = PAGE_EXECUTE; - knowndll_dep_section.cache_image_info_from_filedata(known_dll_dep_file); - add_knowndll_section(known_dll_dep_name, knowndll_dep_section, is_32bit); } } } diff --git a/src/windows-emulator/registry/registry_manager.cpp b/src/windows-emulator/registry/registry_manager.cpp index 0845af99..8599257c 100644 --- a/src/windows-emulator/registry/registry_manager.cpp +++ b/src/windows-emulator/registry/registry_manager.cpp @@ -245,3 +245,34 @@ std::optional registry_manager::get_sub_key_name(const registr return *name; } + +std::optional registry_manager::read_u16string(const registry_key& key, size_t index) +{ + const auto value_opt = this->get_value(key, index); + if (!value_opt) + { + return {}; + } + + const auto& value = value_opt.value(); + + if (value.type != REG_SZ && value.type != REG_EXPAND_SZ) + { + return {}; + } + + if (value.data.empty() || value.data.size() % 2 != 0) + { + return {}; + } + + const auto char_count = value.data.size() / sizeof(char16_t); + const auto* data_ptr = reinterpret_cast(value.data.data()); + if (data_ptr[char_count - 1] != u'\0') + { + return {}; + } + + auto s = std::u16string(data_ptr, char_count - 1); + return s; +} diff --git a/src/windows-emulator/registry/registry_manager.hpp b/src/windows-emulator/registry/registry_manager.hpp index d0c48fc9..24c20f1e 100644 --- a/src/windows-emulator/registry/registry_manager.hpp +++ b/src/windows-emulator/registry/registry_manager.hpp @@ -84,6 +84,8 @@ class registry_manager std::optional get_hive_key(const registry_key& key); + std::optional read_u16string(const registry_key& key, size_t index); + private: std::filesystem::path hive_path_{}; hive_map hives_{}; diff --git a/src/windows-emulator/syscalls/section.cpp b/src/windows-emulator/syscalls/section.cpp index 2121c40c..8a373c9c 100644 --- a/src/windows-emulator/syscalls/section.cpp +++ b/src/windows-emulator/syscalls/section.cpp @@ -72,9 +72,10 @@ namespace syscalls const auto attributes = object_attributes.read(); auto filename = read_unicode_string(c.emu, attributes.ObjectName); + auto filename_sv = std::u16string_view(filename); c.win_emu.callbacks.on_generic_access("Opening section", filename); - if (utils::string::equals_ignore_case(filename, u"\\Windows\\SharedSection"sv)) + if (utils::string::equals_ignore_case(filename_sv, u"\\Windows\\SharedSection"sv)) { constexpr auto shared_section_size = 0x10000; @@ -88,7 +89,7 @@ namespace syscalls return STATUS_SUCCESS; } - if (utils::string::equals_ignore_case(filename, u"DBWIN_BUFFER"sv)) + if (utils::string::equals_ignore_case(filename_sv, u"DBWIN_BUFFER"sv)) { constexpr auto dbwin_buffer_section_size = 0x1000; @@ -102,18 +103,18 @@ namespace syscalls return STATUS_SUCCESS; } - if (utils::string::equals_ignore_case(filename, u"windows_shell_global_counters"sv) || - utils::string::equals_ignore_case(filename, u"Global\\__ComCatalogCache__"sv) || - utils::string::equals_ignore_case(filename, u"{00020000-0000-1005-8005-0000C06B5161}"sv) || - utils::string::equals_ignore_case(filename, u"Global\\{00020000-0000-1005-8005-0000C06B5161}"sv)) + if (utils::string::equals_ignore_case(filename_sv, u"windows_shell_global_counters"sv) || + utils::string::equals_ignore_case(filename_sv, u"Global\\__ComCatalogCache__"sv) || + utils::string::equals_ignore_case(filename_sv, u"{00020000-0000-1005-8005-0000C06B5161}"sv) || + utils::string::equals_ignore_case(filename_sv, u"Global\\{00020000-0000-1005-8005-0000C06B5161}"sv)) { return STATUS_NOT_SUPPORTED; } bool is_knowndll = (attributes.RootDirectory == KNOWN_DLLS32_DIRECTORY || - utils::string::starts_with_ignore_case(filename, u"\\KnownDlls32\\"sv)) || + utils::string::starts_with_ignore_case(filename_sv, u"\\KnownDlls32\\"sv)) || attributes.RootDirectory == KNOWN_DLLS_DIRECTORY || - utils::string::starts_with_ignore_case(filename, u"\\KnownDlls\\"sv); + utils::string::starts_with_ignore_case(filename_sv, u"\\KnownDlls\\"sv); if (!is_knowndll && attributes.RootDirectory != BASE_NAMED_OBJECTS_DIRECTORY) { @@ -125,16 +126,16 @@ namespace syscalls if (is_knowndll) { bool is_knowndll32 = attributes.RootDirectory == KNOWN_DLLS32_DIRECTORY || - utils::string::starts_with_ignore_case(filename, u"\\KnownDlls32\\"sv); + utils::string::starts_with_ignore_case(filename_sv, u"\\KnownDlls32\\"sv); std::u16string knowndll_name = filename; - if (utils::string::starts_with_ignore_case(filename, u"\\KnownDlls32\\"sv)) + if (utils::string::starts_with_ignore_case(filename_sv, u"\\KnownDlls32\\"sv)) { knowndll_name = filename.substr(13, filename.length() - 13); } - else if (utils::string::starts_with_ignore_case(filename, u"\\KnownDlls\\"sv)) + else if (utils::string::starts_with_ignore_case(filename_sv, u"\\KnownDlls\\"sv)) { knowndll_name = filename.substr(11, filename.length() - 11); }