diff --git a/src/common/utils/string.hpp b/src/common/utils/string.hpp index a732217d..910b9233 100644 --- a/src/common/utils/string.hpp +++ b/src/common/utils/string.hpp @@ -8,12 +8,15 @@ #include #include +using namespace std::string_view_literals; + namespace utils::string { #ifdef __clang__ __attribute__((__format__(__printf__, 1, 2))) #endif - const char* va(const char* format, ...); + const char* + va(const char* format, ...); template requires(std::is_trivially_copyable_v) @@ -181,4 +184,54 @@ 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& 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_view& 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 ends_with_ignore_case(const std::basic_string& lhs, const std::basic_string& 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_view& 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); }); + } } diff --git a/src/windows-emulator/process_context.cpp b/src/windows-emulator/process_context.cpp index 6a97079f..71e836f9 100644 --- a/src/windows-emulator/process_context.cpp +++ b/src/windows-emulator/process_context.cpp @@ -232,141 +232,6 @@ namespace return apiset; } - - template - void create_known_dlls_section_objects(knowndlls_map& knowndlls_section_objects, - std::unordered_map& apiset, registry_manager& registry, - const file_system& file_system, bool is_wow64) - { - windows_path system_root_path; - std::filesystem::path local_system_root_path; - - if (is_wow64) - { - system_root_path = "C:\\Windows\\SysWOW64"; - } - else - { - system_root_path = "C:\\Windows\\System32"; - } - - std::optional knowndlls_key = - registry.get_key({R"(\Registry\Machine\System\CurrentControlSet\Control\Session Manager\KnownDLLs)"}); - if (!knowndlls_key) - { - 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; - - if (value.type != REG_SZ && value.type != REG_EXPAND_SZ) - { - continue; - } - - if (value.data.empty() || value.data.size() % 2 != 0) - { - continue; - } - - 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; - } - - 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; - - if (!std::filesystem::exists(local_known_dll_path)) - { - continue; - } - - utils::string::to_lower_inplace(known_dll_name); - auto file = utils::io::read_file(local_known_dll_path); - { - section s; - s.file_name = known_dll_path.u16string(); - s.maximum_size = 0; - s.allocation_attributes = SEC_IMAGE; - s.section_page_protection = PAGE_EXECUTE; - s.cache_image_info_from_filedata(file); - knowndlls_section_objects[known_dll_name] = s; - } - - 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(); - - const auto& import_directory_entry = winpe::get_data_directory_by_index(nt_headers, IMAGE_DIRECTORY_ENTRY_IMPORT); - if (!import_directory_entry.VirtualAddress) - { - continue; - } - - const auto section_with_import_descs = - winpe::get_section_header_by_rva(buffer, nt_headers, nt_headers_offset, import_directory_entry.VirtualAddress); - auto import_directory_vbase = section_with_import_descs.VirtualAddress; - auto import_directory_rbase = section_with_import_descs.PointerToRawData; - - 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); - if (!descriptor.Name) - { - break; - } - - auto known_dll_dep_name = 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); - 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 (apiset.contains(known_dll_dep_name_16)) - { - known_dll_dep_name_16 = apiset[known_dll_dep_name_16]; - } - else - { - continue; - } - } - - if (knowndlls_section_objects.contains(known_dll_dep_name_16)) - { - 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_file = utils::io::read_file(local_known_dll_dep_path); - - section s; - s.file_name = known_dll_dep_path.u16string(); - s.maximum_size = 0; - s.allocation_attributes = SEC_IMAGE; - s.section_page_protection = PAGE_EXECUTE; - s.cache_image_info_from_filedata(known_dll_dep_file); - knowndlls_section_objects[known_dll_dep_name_16] = s; - } - } - } - } } void process_context::setup(x86_64_emulator& emu, memory_manager& memory, registry_manager& registry, const file_system& file_system, @@ -576,10 +441,9 @@ void process_context::setup(x86_64_emulator& emu, memory_manager& memory, regist } } - const auto* api_set_data = reinterpret_cast(apiset_container.data.data()); - auto apiset = get_apiset_namespace_table(api_set_data); - create_known_dlls_section_objects(this->knowndlls32_sections, apiset, registry, file_system, true); - create_known_dlls_section_objects(this->knowndlls64_sections, apiset, registry, file_system, false); + this->apiset = get_apiset_namespace_table(reinterpret_cast(apiset_container.data.data())); + this->build_knowndlls_section_table(registry, file_system, true); + this->build_knowndlls_section_table(registry, file_system, false); this->ntdll_image_base = ntdll.image_base; this->ldr_initialize_thunk = ntdll.find_export("LdrInitializeThunk"); @@ -863,3 +727,182 @@ const std::u16string* process_context::get_atom_name(const uint16_t atom_id) con return &it->second.name; } + +template +void process_context::build_knowndlls_section_table(registry_manager& registry, const file_system& file_system, bool is_32bit) +{ + windows_path system_root_path; + std::filesystem::path local_system_root_path; + + if (is_32bit) + { + system_root_path = "C:\\Windows\\SysWOW64"; + } + else + { + system_root_path = "C:\\Windows\\System32"; + } + + std::optional knowndlls_key = + registry.get_key({R"(\Registry\Machine\System\CurrentControlSet\Control\Session Manager\KnownDLLs)"}); + if (!knowndlls_key) + { + 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; + + if (value.type != REG_SZ && value.type != REG_EXPAND_SZ) + { + continue; + } + + if (value.data.empty() || value.data.size() % 2 != 0) + { + continue; + } + + 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; + } + + 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; + + if (!std::filesystem::exists(local_known_dll_path)) + { + continue; + } + + auto file = utils::io::read_file(local_known_dll_path); + { + section s; + s.file_name = known_dll_path.u16string(); + s.maximum_size = 0; + s.allocation_attributes = SEC_IMAGE; + s.section_page_protection = PAGE_EXECUTE; + s.cache_image_info_from_filedata(file); + this->add_knowndll_section(known_dll_name, 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(); + + const auto& import_directory_entry = winpe::get_data_directory_by_index(nt_headers, IMAGE_DIRECTORY_ENTRY_IMPORT); + if (!import_directory_entry.VirtualAddress) + { + continue; + } + + const auto section_with_import_descs = + winpe::get_section_header_by_rva(buffer, nt_headers, nt_headers_offset, import_directory_entry.VirtualAddress); + auto import_directory_vbase = section_with_import_descs.VirtualAddress; + auto import_directory_rbase = section_with_import_descs.PointerToRawData; + + 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); + if (!descriptor.Name) + { + 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_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 (this->apiset.contains(known_dll_dep_name_16)) + { + known_dll_dep_name_16 = apiset[known_dll_dep_name_16]; + } + else + { + continue; + } + } + + if (is_knowndll_section_exists(known_dll_dep_name_16, 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_file = utils::io::read_file(local_known_dll_dep_path); + + section s; + s.file_name = known_dll_dep_path.u16string(); + s.maximum_size = 0; + 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); + } + } + } +} + +bool process_context::is_knowndll_section_exists(const std::u16string& name, bool is_32bit) +{ + auto lname = utils::string::to_lower(name); + + if (is_32bit) + { + return this->knowndlls32_sections.contains(lname); + } + + return this->knowndlls64_sections.contains(lname); +} + +std::optional
process_context::get_knowndll_section_by_name(const std::u16string& name, bool is_32bit) +{ + auto lname = utils::string::to_lower(name); + + if (is_32bit) + { + if (this->knowndlls32_sections.contains(lname)) + { + return this->knowndlls32_sections[lname]; + } + } + else + { + if (this->knowndlls64_sections.contains(lname)) + { + return this->knowndlls64_sections[lname]; + } + } + + return {}; +} + +void process_context::add_knowndll_section(const std::u16string& name, section section, bool is_32bit) +{ + auto lname = utils::string::to_lower(name); + + if (is_32bit) + { + this->knowndlls32_sections[lname] = section; + } + else + { + this->knowndlls64_sections[lname] = section; + } +} diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index 4d40f04b..4810e8fe 100644 --- a/src/windows-emulator/process_context.hpp +++ b/src/windows-emulator/process_context.hpp @@ -35,6 +35,7 @@ struct emulator_settings; struct application_settings; using knowndlls_map = std::map; +using apiset_map = std::unordered_map; struct process_context { struct callbacks @@ -86,6 +87,13 @@ struct process_context bool delete_atom(uint16_t atom_id); const std::u16string* get_atom_name(uint16_t atom_id) const; + template + void build_knowndlls_section_table(registry_manager& registry, const file_system& file_system, bool is_wow64); + + std::optional
get_knowndll_section_by_name(const std::u16string& name, bool is_32bit); + void add_knowndll_section(const std::u16string& name, section section, bool is_32bit); + bool is_knowndll_section_exists(const std::u16string& name, bool is_32bit); + void serialize(utils::buffer_serializer& buffer) const; void deserialize(utils::buffer_deserializer& buffer); @@ -142,6 +150,7 @@ struct process_context handle_store registry_keys{}; std::map atoms{}; + apiset_map apiset; knowndlls_map knowndlls32_sections; knowndlls_map knowndlls64_sections; diff --git a/src/windows-emulator/syscalls/section.cpp b/src/windows-emulator/syscalls/section.cpp index 7fa31d66..655a15ff 100644 --- a/src/windows-emulator/syscalls/section.cpp +++ b/src/windows-emulator/syscalls/section.cpp @@ -70,9 +70,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 (filename == u"\\Windows\\SharedSection") + if (utils::string::equals_ignore_case(filename_sv, u"\\Windows\\SharedSection"sv)) { constexpr auto shared_section_size = 0x10000; @@ -86,7 +87,7 @@ namespace syscalls return STATUS_SUCCESS; } - if (filename == u"DBWIN_BUFFER") + if (utils::string::equals_ignore_case(filename_sv, u"DBWIN_BUFFER"sv)) { constexpr auto dbwin_buffer_section_size = 0x1000; @@ -100,69 +101,56 @@ namespace syscalls return STATUS_SUCCESS; } - if (filename == u"windows_shell_global_counters" // - || filename == u"Global\\__ComCatalogCache__" // - || filename == u"{00020000-0000-1005-8005-0000C06B5161}" // - || filename == u"Global\\{00020000-0000-1005-8005-0000C06B5161}") + 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_known_dll = (attributes.RootDirectory == KNOWN_DLLS_DIRECTORY || attributes.RootDirectory == KNOWN_DLLS32_DIRECTORY || - filename.starts_with(u"\\KnownDlls") || filename.starts_with(u"\\KnownDlls32")); + bool is_knowndll = (attributes.RootDirectory == KNOWN_DLLS32_DIRECTORY || + utils::string::starts_with_ignore_case(filename_sv, u"\\KnownDlls32\\"sv)) || + attributes.RootDirectory == KNOWN_DLLS_DIRECTORY || + utils::string::starts_with_ignore_case(filename_sv, u"\\KnownDlls\\"sv); - if (!is_known_dll && attributes.RootDirectory != BASE_NAMED_OBJECTS_DIRECTORY) + if (!is_knowndll && attributes.RootDirectory != BASE_NAMED_OBJECTS_DIRECTORY) { c.win_emu.log.error("Unsupported section\n"); c.emu.stop(); return STATUS_NOT_SUPPORTED; } - utils::string::to_lower_inplace(filename); - - if (attributes.RootDirectory == KNOWN_DLLS_DIRECTORY || filename.starts_with(u"\\knowndlls\\")) + if (is_knowndll) { - auto& knowndlls_sections = c.win_emu.process.knowndlls64_sections; + bool is_knowndll32 = attributes.RootDirectory == KNOWN_DLLS32_DIRECTORY || + utils::string::starts_with_ignore_case(filename_sv, u"\\KnownDlls32"sv); - if (filename.starts_with(u"\\knowndlls\\")) + if (utils::string::starts_with_ignore_case(filename_sv, u"\\KnownDlls32\\"sv)) { - filename = std::u16string_view(filename).substr(11, filename.length() - 11); + filename = filename_sv.substr(13, filename.length() - 13); } - if (!knowndlls_sections.contains(filename)) + else if (utils::string::starts_with_ignore_case(filename_sv, u"\\KnownDlls\\"sv)) + { + filename = filename_sv.substr(11, filename.length() - 11); + } + + auto section = c.win_emu.process.get_knowndll_section_by_name(filename, is_knowndll32); + if (!section.has_value()) { return STATUS_OBJECT_NAME_NOT_FOUND; } - auto knowndll_section = knowndlls_sections[filename]; - section_handle.write(c.proc.sections.store(knowndll_section)); + section_handle.write(c.proc.sections.store(section.value())); return STATUS_SUCCESS; } - if (attributes.RootDirectory == KNOWN_DLLS32_DIRECTORY || filename.starts_with(u"\\knowndlls32\\")) + for (auto& [handle, section] : c.proc.sections) { - auto& knowndlls_sections = c.win_emu.process.knowndlls32_sections; - - if (filename.starts_with(u"\\knowndlls32\\")) + if (section.is_image() && utils::string::equals_ignore_case(section.file_name, filename)) { - filename = std::u16string_view(filename).substr(13, filename.length() - 13); - } - - if (!knowndlls_sections.contains(filename)) - { - return STATUS_OBJECT_NAME_NOT_FOUND; - } - - auto knowndll_section = knowndlls_sections[filename]; - section_handle.write(c.proc.sections.store(knowndll_section)); - return STATUS_SUCCESS; - } - - for (auto& section_entry : c.proc.sections) - { - if (section_entry.second.is_image() && section_entry.second.name == filename) - { - section_handle.write(c.proc.sections.make_handle(section_entry.first)); + section_handle.write(c.proc.sections.make_handle(handle)); return STATUS_SUCCESS; } }