From 0438b7a62b715b8a2b5777f19d59ef73ebeaa349 Mon Sep 17 00:00:00 2001 From: ahm3dgg Date: Tue, 13 Jan 2026 01:44:36 +0200 Subject: [PATCH] Update module_load_count when unmapping --- src/common/utils/string.hpp | 31 +++++++++++++++++ .../module/module_manager.cpp | 21 +++++++++--- .../module/module_manager.hpp | 2 +- src/windows-emulator/process_context.cpp | 34 +++++++++---------- src/windows-emulator/process_context.hpp | 2 +- src/windows-emulator/syscalls/section.cpp | 33 +++++++++--------- 6 files changed, 83 insertions(+), 40 deletions(-) diff --git a/src/common/utils/string.hpp b/src/common/utils/string.hpp index 66ff551d..27ce6ba6 100644 --- a/src/common/utils/string.hpp +++ b/src/common/utils/string.hpp @@ -170,6 +170,12 @@ 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) { @@ -182,6 +188,18 @@ 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) { @@ -206,6 +224,19 @@ 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/module/module_manager.cpp b/src/windows-emulator/module/module_manager.cpp index 11d565bf..10bccbff 100644 --- a/src/windows-emulator/module/module_manager.cpp +++ b/src/windows-emulator/module/module_manager.cpp @@ -223,7 +223,7 @@ mapped_module* module_manager::map_module_core(const pe_detection_result& detect if (!mod.path.empty()) { - this->module_load_count[mod.path]++; + this->modules_load_count[mod.path]++; } const auto image_base = mod.image_base; @@ -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 (!module_load_count.contains(local_file)) + if (!modules_load_count.contains(local_file)) { return {}; } - return module_load_count[local_file]; + return modules_load_count[local_file]; } mapped_module* module_manager::map_module(const windows_path& file, const logger& logger, const bool is_static, bool allow_duplicate) @@ -538,7 +538,7 @@ mapped_module* module_manager::map_memory_module(uint64_t base_address, uint64_t void module_manager::serialize(utils::buffer_serializer& buffer) const { buffer.write_map(this->modules_); - buffer.write_map(this->module_load_count); + buffer.write_map(this->modules_load_count); buffer.write(this->executable ? this->executable->image_base : 0); buffer.write(this->ntdll ? this->ntdll->image_base : 0); @@ -556,7 +556,7 @@ void module_manager::serialize(utils::buffer_serializer& buffer) const void module_manager::deserialize(utils::buffer_deserializer& buffer) { buffer.read_map(this->modules_); - buffer.read_map(this->module_load_count); + buffer.read_map(this->modules_load_count); this->last_module_cache_ = this->modules_.end(); const auto executable_base = buffer.read(); @@ -595,6 +595,17 @@ bool module_manager::unmap(const uint64_t address) this->callbacks_->on_module_unload(mod->second); unmap_module(*this->memory_, mod->second); + + auto module_load_count = this->modules_load_count[mod->second.path] - 1; + if (module_load_count == 0) + { + this->modules_load_count.erase(mod->second.path); + } + else + { + this->modules_load_count[mod->second.path] = module_load_count; + } + this->modules_.erase(mod); this->last_module_cache_ = this->modules_.end(); diff --git a/src/windows-emulator/module/module_manager.hpp b/src/windows-emulator/module/module_manager.hpp index 38a28ee4..22f2c633 100644 --- a/src/windows-emulator/module/module_manager.hpp +++ b/src/windows-emulator/module/module_manager.hpp @@ -159,7 +159,7 @@ class module_manager mapped_module* executable{}; mapped_module* ntdll{}; mapped_module* win32u{}; - std::map module_load_count; + std::map modules_load_count; // WOW64-specific modules (for validation and future use) struct wow64_modules diff --git a/src/windows-emulator/process_context.cpp b/src/windows-emulator/process_context.cpp index 248c6288..83749ccc 100644 --- a/src/windows-emulator/process_context.cpp +++ b/src/windows-emulator/process_context.cpp @@ -3,8 +3,9 @@ #include "emulator_utils.hpp" #include "windows_emulator.hpp" -#include "utils/io.hpp" -#include "utils/buffer_accessor.hpp" + +#include +#include namespace { @@ -205,9 +206,9 @@ namespace return 0; } - std::unordered_map get_apiset_namespace_table(const API_SET_NAMESPACE* api_set_map) + apiset_map get_apiset_namespace_table(const API_SET_NAMESPACE* api_set_map) { - std::unordered_map apiset; + apiset_map apiset; for (size_t i = 0; i < api_set_map->Count; i++) { @@ -580,6 +581,7 @@ void process_context::serialize(utils::buffer_serializer& buffer) const buffer.write(this->timers); buffer.write(this->registry_keys); buffer.write_map(this->atoms); + buffer.write_map(this->apiset); buffer.write_map(this->knowndlls32_sections); buffer.write_map(this->knowndlls64_sections); @@ -633,6 +635,7 @@ void process_context::deserialize(utils::buffer_deserializer& buffer) buffer.read(this->timers); buffer.read(this->registry_keys); buffer.read_map(this->atoms); + buffer.read_map(this->apiset); buffer.read_map(this->knowndlls32_sections); buffer.read_map(this->knowndlls64_sections); @@ -814,7 +817,6 @@ void process_context::build_knowndlls_section_table(registry_manager& registry, return; } - local_system_root_path = file_system.translate(system_root_path); for (size_t i = 0; const auto value_opt = registry.get_value(*knowndlls_key, i); i++) { const auto& value = *value_opt; @@ -838,7 +840,7 @@ void process_context::build_knowndlls_section_table(registry_manager& registry, 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 = local_system_root_path / known_dll_name; + auto local_known_dll_path = file_system.translate(system_root_path / known_dll_name); if (!std::filesystem::exists(local_known_dll_path)) { @@ -884,16 +886,14 @@ void process_context::build_knowndlls_section_table(registry_manager& registry, break; } - auto known_dll_dep_name = - buffer.as_string(static_cast(rva_to_file_offset(import_directory_vbase, import_directory_rbase, descriptor.Name))); + 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)))); - auto known_dll_dep_name_16 = u8_to_u16(known_dll_dep_name); - - if (known_dll_dep_name_16.starts_with(u"api-") || known_dll_dep_name_16.starts_with(u"ext-")) + if (known_dll_dep_name.starts_with(u"api-") || known_dll_dep_name.starts_with(u"ext-")) { - if (this->apiset.contains(known_dll_dep_name_16)) + if (this->apiset.contains(known_dll_dep_name)) { - known_dll_dep_name_16 = apiset[known_dll_dep_name_16]; + known_dll_dep_name = apiset[known_dll_dep_name]; } else { @@ -901,14 +901,14 @@ void process_context::build_knowndlls_section_table(registry_manager& registry, } } - if (is_knowndll_section_exists(known_dll_dep_name_16, is_32bit)) + if (is_knowndll_section_exists(known_dll_dep_name, is_32bit)) { continue; } { - auto local_known_dll_dep_path = local_system_root_path / known_dll_dep_name_16; - auto known_dll_dep_path = system_root_path / known_dll_dep_name_16; + 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); auto known_dll_dep_file = utils::io::read_file(local_known_dll_dep_path); section s; @@ -917,7 +917,7 @@ void process_context::build_knowndlls_section_table(registry_manager& registry, s.allocation_attributes = SEC_IMAGE; s.section_page_protection = PAGE_EXECUTE; s.cache_image_info_from_filedata(known_dll_dep_file); - this->add_knowndll_section(known_dll_dep_name_16, s, is_32bit); + this->add_knowndll_section(known_dll_dep_name, s, is_32bit); } } } diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index 2678803a..7de9bae1 100644 --- a/src/windows-emulator/process_context.hpp +++ b/src/windows-emulator/process_context.hpp @@ -35,7 +35,7 @@ struct emulator_settings; struct application_settings; using knowndlls_map = std::map; -using apiset_map = std::unordered_map; +using apiset_map = std::map; struct process_context { struct callbacks diff --git a/src/windows-emulator/syscalls/section.cpp b/src/windows-emulator/syscalls/section.cpp index 9a483349..2121c40c 100644 --- a/src/windows-emulator/syscalls/section.cpp +++ b/src/windows-emulator/syscalls/section.cpp @@ -72,10 +72,9 @@ 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_sv, u"\\Windows\\SharedSection"sv)) + if (utils::string::equals_ignore_case(filename, u"\\Windows\\SharedSection"sv)) { constexpr auto shared_section_size = 0x10000; @@ -89,7 +88,7 @@ namespace syscalls return STATUS_SUCCESS; } - if (utils::string::equals_ignore_case(filename_sv, u"DBWIN_BUFFER"sv)) + if (utils::string::equals_ignore_case(filename, u"DBWIN_BUFFER"sv)) { constexpr auto dbwin_buffer_section_size = 0x1000; @@ -103,18 +102,18 @@ namespace syscalls return STATUS_SUCCESS; } - 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)) + 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)) { return STATUS_NOT_SUPPORTED; } bool is_knowndll = (attributes.RootDirectory == KNOWN_DLLS32_DIRECTORY || - utils::string::starts_with_ignore_case(filename_sv, u"\\KnownDlls32\\"sv)) || + utils::string::starts_with_ignore_case(filename, u"\\KnownDlls32\\"sv)) || attributes.RootDirectory == KNOWN_DLLS_DIRECTORY || - utils::string::starts_with_ignore_case(filename_sv, u"\\KnownDlls\\"sv); + utils::string::starts_with_ignore_case(filename, u"\\KnownDlls\\"sv); if (!is_knowndll && attributes.RootDirectory != BASE_NAMED_OBJECTS_DIRECTORY) { @@ -126,19 +125,21 @@ namespace syscalls if (is_knowndll) { bool is_knowndll32 = attributes.RootDirectory == KNOWN_DLLS32_DIRECTORY || - utils::string::starts_with_ignore_case(filename_sv, u"\\KnownDlls32"sv); + utils::string::starts_with_ignore_case(filename, u"\\KnownDlls32\\"sv); - if (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)) { - filename = filename_sv.substr(13, filename.length() - 13); + knowndll_name = filename.substr(13, filename.length() - 13); } - else if (utils::string::starts_with_ignore_case(filename_sv, u"\\KnownDlls\\"sv)) + else if (utils::string::starts_with_ignore_case(filename, u"\\KnownDlls\\"sv)) { - filename = filename_sv.substr(11, filename.length() - 11); + knowndll_name = filename.substr(11, filename.length() - 11); } - auto section = c.win_emu.process.get_knowndll_section_by_name(filename, is_knowndll32); + auto section = c.win_emu.process.get_knowndll_section_by_name(knowndll_name, is_knowndll32); if (!section.has_value()) { return STATUS_OBJECT_NAME_NOT_FOUND; @@ -150,7 +151,7 @@ namespace syscalls for (auto& [handle, section] : c.proc.sections) { - if (section.is_image() && utils::string::equals_ignore_case(section.file_name, filename)) + if (section.is_image() && utils::string::equals_ignore_case(section.name, filename)) { section_handle.write(c.proc.sections.make_handle(handle)); return STATUS_SUCCESS;