diff --git a/src/common/platform/status.hpp b/src/common/platform/status.hpp index 1fb015b9..d4b7ff5d 100644 --- a/src/common/platform/status.hpp +++ b/src/common/platform/status.hpp @@ -22,70 +22,72 @@ using NTSTATUS = std::uint32_t; #define STATUS_INTEGER_DIVIDE_BY_ZERO ((NTSTATUS)0xC0000094L) #endif -#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) -#define STATUS_WAIT_1 ((NTSTATUS)0x00000001L) -#define STATUS_ALERTED ((NTSTATUS)0x00000101L) -#define STATUS_PIPE_LISTENING ((NTSTATUS)0x00000105L) -#define STATUS_PIPE_CONNECTED ((NTSTATUS)0x00000106L) +#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) +#define STATUS_WAIT_1 ((NTSTATUS)0x00000001L) +#define STATUS_ALERTED ((NTSTATUS)0x00000101L) +#define STATUS_PIPE_LISTENING ((NTSTATUS)0x00000105L) +#define STATUS_PIPE_CONNECTED ((NTSTATUS)0x00000106L) -#define STATUS_OBJECT_NAME_EXISTS ((NTSTATUS)0x40000000L) -#define STATUS_SERVICE_NOTIFICATION ((NTSTATUS)0x40000018L) +#define STATUS_OBJECT_NAME_EXISTS ((NTSTATUS)0x40000000L) +#define STATUS_SERVICE_NOTIFICATION ((NTSTATUS)0x40000018L) -#define STATUS_BUFFER_OVERFLOW ((NTSTATUS)0x80000005L) -#define STATUS_NO_MORE_FILES ((NTSTATUS)0x80000006L) -#define STATUS_NO_MORE_ENTRIES ((NTSTATUS)0x8000001AL) +#define STATUS_BUFFER_OVERFLOW ((NTSTATUS)0x80000005L) +#define STATUS_NO_MORE_FILES ((NTSTATUS)0x80000006L) +#define STATUS_NO_MORE_ENTRIES ((NTSTATUS)0x8000001AL) -#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L) -#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) -#define STATUS_CONFLICTING_ADDRESSES ((NTSTATUS)0xC0000018L) -#define STATUS_NOT_MAPPED_VIEW ((NTSTATUS)0xC0000019L) -#define STATUS_UNABLE_TO_DELETE_SECTION ((NTSTATUS)0xC000001BL) -#define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L) -#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L) -#define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS)0xC0000034L) -#define STATUS_OBJECT_NAME_COLLISION ((NTSTATUS)0xC0000035L) -#define STATUS_INVALID_PAGE_PROTECTION ((NTSTATUS)0xC0000045L) -#define STATUS_MUTANT_NOT_OWNED ((NTSTATUS)0xC0000046L) -#define STATUS_SEMAPHORE_LIMIT_EXCEEDED ((NTSTATUS)0xC0000047L) -#define STATUS_SECTION_NOT_IMAGE ((NTSTATUS)0xC0000049L) -#define STATUS_PROCEDURE_NOT_FOUND ((NTSTATUS)0xC000007AL) -#define STATUS_NO_TOKEN ((NTSTATUS)0xC000007CL) -#define STATUS_FILE_INVALID ((NTSTATUS)0xC0000098L) -#define STATUS_INSUFFICIENT_RESOURCES ((NTSTATUS)0xC000009AL) -#define STATUS_FREE_VM_NOT_AT_BASE ((NTSTATUS)0xC000009FL) -#define STATUS_MEMORY_NOT_ALLOCATED ((NTSTATUS)0xC00000A0L) -#define STATUS_PIPE_BUSY ((NTSTATUS)0xC00000AAL) -#define STATUS_PIPE_NOT_AVAILABLE ((NTSTATUS)0xC00000ACL) -#define STATUS_INVALID_PIPE_STATE ((NTSTATUS)0xC00000ADL) -#define STATUS_PIPE_DISCONNECTED ((NTSTATUS)0xC00000B0L) -#define STATUS_PIPE_CLOSING ((NTSTATUS)0xC00000B1L) -#define STATUS_FILE_IS_A_DIRECTORY ((NTSTATUS)0xC00000BAL) -#define STATUS_NOT_SUPPORTED ((NTSTATUS)0xC00000BBL) -#define STATUS_PIPE_NOT_CONNECTED ((NTSTATUS)0xC00000BEL) -#define STATUS_PIPE_EMPTY ((NTSTATUS)0xC00000D9L) -#define STATUS_INTERNAL_ERROR ((NTSTATUS)0xC00000E5L) -#define STATUS_INVALID_PARAMETER_1 ((NTSTATUS)0xC00000EFL) -#define STATUS_INVALID_PARAMETER_2 ((NTSTATUS)0xC00000F0L) -#define STATUS_INVALID_PARAMETER_3 ((NTSTATUS)0xC00000F1L) -#define STATUS_INVALID_PARAMETER_4 ((NTSTATUS)0xC00000F2L) -#define STATUS_INVALID_PARAMETER_5 ((NTSTATUS)0xC00000F3L) -#define STATUS_INVALID_PARAMETER_6 ((NTSTATUS)0xC00000F4L) -#define STATUS_INVALID_PARAMETER_7 ((NTSTATUS)0xC00000F5L) -#define STATUS_INVALID_PARAMETER_8 ((NTSTATUS)0xC00000F6L) -#define STATUS_INVALID_PARAMETER_9 ((NTSTATUS)0xC00000F7L) -#define STATUS_INVALID_PARAMETER_10 ((NTSTATUS)0xC00000F8L) -#define STATUS_INVALID_PARAMETER_11 ((NTSTATUS)0xC00000F9L) -#define STATUS_INVALID_PARAMETER_12 ((NTSTATUS)0xC00000FAL) -#define STATUS_INVALID_ADDRESS ((NTSTATUS)0xC0000141L) -#define STATUS_PIPE_BROKEN ((NTSTATUS)0xC000014BL) -#define STATUS_CONNECTION_RESET ((NTSTATUS)0xC000020DL) -#define STATUS_NOT_FOUND ((NTSTATUS)0xC0000225L) -#define STATUS_NOT_SAME_OBJECT ((NTSTATUS)0xC00001ACL) -#define STATUS_CONNECTION_REFUSED ((NTSTATUS)0xC0000236L) -#define STATUS_TIMER_RESOLUTION_NOT_SET ((NTSTATUS)0xC0000245L) -#define STATUS_ADDRESS_ALREADY_ASSOCIATED ((NTSTATUS)0xC0000328L) -#define STATUS_PORT_NOT_SET ((NTSTATUS)0xC0000353L) -#define STATUS_DEBUGGER_INACTIVE ((NTSTATUS)0xC0000354L) +#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L) +#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) +#define STATUS_CONFLICTING_ADDRESSES ((NTSTATUS)0xC0000018L) +#define STATUS_NOT_MAPPED_VIEW ((NTSTATUS)0xC0000019L) +#define STATUS_UNABLE_TO_DELETE_SECTION ((NTSTATUS)0xC000001BL) +#define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L) +#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L) +#define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS)0xC0000034L) +#define STATUS_OBJECT_NAME_COLLISION ((NTSTATUS)0xC0000035L) +#define STATUS_INVALID_PAGE_PROTECTION ((NTSTATUS)0xC0000045L) +#define STATUS_MUTANT_NOT_OWNED ((NTSTATUS)0xC0000046L) +#define STATUS_SEMAPHORE_LIMIT_EXCEEDED ((NTSTATUS)0xC0000047L) +#define STATUS_SECTION_NOT_IMAGE ((NTSTATUS)0xC0000049L) +#define STATUS_PROCEDURE_NOT_FOUND ((NTSTATUS)0xC000007AL) +#define STATUS_NO_TOKEN ((NTSTATUS)0xC000007CL) +#define STATUS_FILE_INVALID ((NTSTATUS)0xC0000098L) +#define STATUS_INSUFFICIENT_RESOURCES ((NTSTATUS)0xC000009AL) +#define STATUS_FREE_VM_NOT_AT_BASE ((NTSTATUS)0xC000009FL) +#define STATUS_MEMORY_NOT_ALLOCATED ((NTSTATUS)0xC00000A0L) +#define STATUS_PIPE_BUSY ((NTSTATUS)0xC00000AAL) +#define STATUS_PIPE_NOT_AVAILABLE ((NTSTATUS)0xC00000ACL) +#define STATUS_INVALID_PIPE_STATE ((NTSTATUS)0xC00000ADL) +#define STATUS_PIPE_DISCONNECTED ((NTSTATUS)0xC00000B0L) +#define STATUS_PIPE_CLOSING ((NTSTATUS)0xC00000B1L) +#define STATUS_FILE_IS_A_DIRECTORY ((NTSTATUS)0xC00000BAL) +#define STATUS_NOT_SUPPORTED ((NTSTATUS)0xC00000BBL) +#define STATUS_PIPE_NOT_CONNECTED ((NTSTATUS)0xC00000BEL) +#define STATUS_PIPE_EMPTY ((NTSTATUS)0xC00000D9L) +#define STATUS_INTERNAL_ERROR ((NTSTATUS)0xC00000E5L) +#define STATUS_INVALID_PARAMETER_1 ((NTSTATUS)0xC00000EFL) +#define STATUS_INVALID_PARAMETER_2 ((NTSTATUS)0xC00000F0L) +#define STATUS_INVALID_PARAMETER_3 ((NTSTATUS)0xC00000F1L) +#define STATUS_INVALID_PARAMETER_4 ((NTSTATUS)0xC00000F2L) +#define STATUS_INVALID_PARAMETER_5 ((NTSTATUS)0xC00000F3L) +#define STATUS_INVALID_PARAMETER_6 ((NTSTATUS)0xC00000F4L) +#define STATUS_INVALID_PARAMETER_7 ((NTSTATUS)0xC00000F5L) +#define STATUS_INVALID_PARAMETER_8 ((NTSTATUS)0xC00000F6L) +#define STATUS_INVALID_PARAMETER_9 ((NTSTATUS)0xC00000F7L) +#define STATUS_INVALID_PARAMETER_10 ((NTSTATUS)0xC00000F8L) +#define STATUS_INVALID_PARAMETER_11 ((NTSTATUS)0xC00000F9L) +#define STATUS_INVALID_PARAMETER_12 ((NTSTATUS)0xC00000FAL) +#define STATUS_INVALID_ADDRESS ((NTSTATUS)0xC0000141L) +#define STATUS_PIPE_BROKEN ((NTSTATUS)0xC000014BL) +#define STATUS_CONNECTION_RESET ((NTSTATUS)0xC000020DL) +#define STATUS_NOT_FOUND ((NTSTATUS)0xC0000225L) +#define STATUS_NOT_SAME_OBJECT ((NTSTATUS)0xC00001ACL) +#define STATUS_CONNECTION_REFUSED ((NTSTATUS)0xC0000236L) +#define STATUS_TIMER_RESOLUTION_NOT_SET ((NTSTATUS)0xC0000245L) +#define STATUS_ADDRESS_ALREADY_ASSOCIATED ((NTSTATUS)0xC0000328L) +#define STATUS_PORT_NOT_SET ((NTSTATUS)0xC0000353L) +#define STATUS_DEBUGGER_INACTIVE ((NTSTATUS)0xC0000354L) +#define STATUS_IMAGE_NOT_AT_BASE ((NTSTATUS)0x40000003L) +#define STATUS_IMAGE_MACHINE_TYPE_MISMATCH ((NTSTATUS)0x4000000EL) -#define FILE_DEVICE_NETWORK 0x00000012 -#define FSCTL_AFD_BASE FILE_DEVICE_NETWORK +#define FILE_DEVICE_NETWORK 0x00000012 +#define FSCTL_AFD_BASE FILE_DEVICE_NETWORK diff --git a/src/common/platform/win_pefile.hpp b/src/common/platform/win_pefile.hpp index 82770ce9..20b8073e 100644 --- a/src/common/platform/win_pefile.hpp +++ b/src/common/platform/win_pefile.hpp @@ -4,8 +4,11 @@ #include #include #include +#include #include #include +#include +#include "../utils/buffer_accessor.hpp" #include "primitives.hpp" @@ -480,6 +483,24 @@ struct SECTION_IMAGE_INFORMATION namespace winpe { + struct pe_image_basic_info + { + uint64_t entry_point_rva{}; + uint64_t image_base{}; + uint64_t size_of_stack_reserve{}; + uint64_t size_of_stack_commit{}; + uint32_t size_of_code{}; + uint32_t loader_flags{}; + uint32_t checksum{}; + uint16_t machine{}; + uint16_t subsystem{}; + uint16_t subsystem_major_version{}; + uint16_t subsystem_minor_version{}; + uint16_t image_characteristics{}; + uint16_t dll_characteristics{}; + bool has_code{false}; + std::array _padding{}; + }; enum class pe_arch { @@ -487,6 +508,51 @@ namespace winpe pe64 }; + template + inline uint64_t get_first_section_offset(const PENTHeaders_t& nt_headers, const uint64_t nt_headers_offset) + { + const auto* nt_headers_addr = reinterpret_cast(&nt_headers); + const size_t optional_header_offset = + reinterpret_cast(&(nt_headers.OptionalHeader)) - reinterpret_cast(&nt_headers); + const size_t optional_header_size = nt_headers.FileHeader.SizeOfOptionalHeader; + const auto* first_section_addr = nt_headers_addr + optional_header_offset + optional_header_size; + + const auto first_section_absolute = reinterpret_cast(first_section_addr); + const auto absolute_base = reinterpret_cast(&nt_headers); + return nt_headers_offset + (first_section_absolute - absolute_base); + } + + template + inline PEDirectory_t2 get_data_directory_by_index(const PENTHeaders_t& nt_headers, uint64_t directory_index) + { + return nt_headers.OptionalHeader.DataDirectory[directory_index]; + } + + template + IMAGE_SECTION_HEADER get_section_header_by_rva(const utils::safe_buffer_accessor& buffer, + const PENTHeaders_t& nt_headers, uint64_t nt_headers_offset, uint64_t rva) + { + IMAGE_SECTION_HEADER section_header = {}; + + auto next_section_offset = winpe::get_first_section_offset(nt_headers, nt_headers_offset); + for (size_t i = 0; i < nt_headers.FileHeader.NumberOfSections; i++) + { + const auto section = buffer.as(static_cast(next_section_offset)).get(); + auto section_va_start = section.VirtualAddress; + auto section_va_end = section.VirtualAddress + section.Misc.VirtualSize; + + if (section_va_start <= rva && rva <= section_va_end) + { + section_header = section; + break; + } + + next_section_offset += sizeof(IMAGE_SECTION_HEADER); + } + + return section_header; + } + inline std::variant get_pe_arch(const std::filesystem::path& file) { std::ifstream f(file, std::ios::binary); @@ -593,6 +659,85 @@ namespace winpe return std::make_error_code(std::errc::executable_format_error); } + template + inline bool parse_pe_headers(const std::vector& file_data, pe_image_basic_info& info) + { + if (file_data.size() < sizeof(PEDosHeader_t)) + { + return false; + } + + const auto* dos_header = reinterpret_cast(file_data.data()); + if (dos_header->e_magic != PEDosHeader_t::k_Magic) + { + return false; + } + + if (file_data.size() < dos_header->e_lfanew + sizeof(uint32_t) + sizeof(PEFileHeader_t) + sizeof(uint16_t)) + { + return false; + } + + const auto* magic_ptr = + reinterpret_cast(file_data.data() + dos_header->e_lfanew + sizeof(uint32_t) + sizeof(PEFileHeader_t)); + const uint16_t magic = *magic_ptr; + + constexpr uint16_t expected_magic = (sizeof(T) == sizeof(uint32_t)) + ? static_cast(PEOptionalHeader_t::k_Magic) + : static_cast(PEOptionalHeader_t::k_Magic); + + if (magic != expected_magic) + { + return false; + } + + if (file_data.size() < dos_header->e_lfanew + sizeof(PENTHeaders_t)) + { + return false; + } + + const auto* nt_headers = reinterpret_cast*>(file_data.data() + dos_header->e_lfanew); + if (nt_headers->Signature != PENTHeaders_t::k_Signature) + { + return false; + } + + const auto& file_header = nt_headers->FileHeader; + const auto& optional_header = nt_headers->OptionalHeader; + + info.machine = static_cast(file_header.Machine); + info.image_characteristics = file_header.Characteristics; + + info.entry_point_rva = optional_header.AddressOfEntryPoint; + info.image_base = optional_header.ImageBase; + info.subsystem = optional_header.Subsystem; + info.subsystem_major_version = optional_header.MajorSubsystemVersion; + info.subsystem_minor_version = optional_header.MinorSubsystemVersion; + info.dll_characteristics = optional_header.DllCharacteristics; + info.size_of_stack_reserve = optional_header.SizeOfStackReserve; + info.size_of_stack_commit = optional_header.SizeOfStackCommit; + info.size_of_code = optional_header.SizeOfCode; + info.loader_flags = optional_header.LoaderFlags; + info.checksum = optional_header.CheckSum; + + info.has_code = (optional_header.SizeOfCode > 0) || (optional_header.AddressOfEntryPoint != 0); + + const auto sections_offset = dos_header->e_lfanew + sizeof(uint32_t) + sizeof(PEFileHeader_t) + file_header.SizeOfOptionalHeader; + if (file_data.size() >= sections_offset + sizeof(IMAGE_SECTION_HEADER) * file_header.NumberOfSections) + { + const auto* sections = reinterpret_cast(file_data.data() + sections_offset); + for (uint16_t i = 0; i < file_header.NumberOfSections; ++i) + { + if (sections[i].Characteristics & IMAGE_SCN_CNT_CODE) + { + info.has_code = true; + break; + } + } + } + + return true; + } } // NOLINTEND(modernize-use-using,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) diff --git a/src/common/utils/string.hpp b/src/common/utils/string.hpp index c887de7f..000cfb0a 100644 --- a/src/common/utils/string.hpp +++ b/src/common/utils/string.hpp @@ -196,4 +196,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/emulator/address_utils.hpp b/src/emulator/address_utils.hpp index 224f2831..12773f59 100644 --- a/src/emulator/address_utils.hpp +++ b/src/emulator/address_utils.hpp @@ -52,3 +52,8 @@ constexpr uint64_t page_align_up(const uint64_t value, const uint64_t page_size { return align_up(value, page_size); } + +constexpr uint64_t rva_to_file_offset(uint64_t va_base, uint64_t raw_base, uint64_t rva) +{ + return rva - (va_base - raw_base); +} diff --git a/src/tools/dump-apiset/dump-apiset.cpp b/src/tools/dump-apiset/dump-apiset.cpp index 5388e6b2..a829a7b3 100644 --- a/src/tools/dump-apiset/dump-apiset.cpp +++ b/src/tools/dump-apiset/dump-apiset.cpp @@ -32,7 +32,7 @@ int main() printf("EntryOffset: %08lX\n", api_set_map->EntryOffset); printf("HashOffset: %08lX\n", api_set_map->HashOffset); printf("HashFactor: %08lX\n", api_set_map->HashFactor); - // print_apiset(apiSetMap); + print_apiset(api_set_map); // Compress the API-SET binary blob const auto* data_ptr = reinterpret_cast(api_set_map); diff --git a/src/windows-emulator/apiset/apiset.cpp b/src/windows-emulator/apiset/apiset.cpp index b607178a..c4ecec65 100644 --- a/src/windows-emulator/apiset/apiset.cpp +++ b/src/windows-emulator/apiset/apiset.cpp @@ -175,4 +175,32 @@ namespace apiset return api_set_map_obj; } + + apiset_map get_namespace_table(const API_SET_NAMESPACE* apiset_ns_data) + { + std::map apiset; + + for (size_t i = 0; i < apiset_ns_data->Count; i++) + { + const auto* entry = reinterpret_cast( + reinterpret_cast(apiset_ns_data) + apiset_ns_data->EntryOffset + i * sizeof(API_SET_NAMESPACE_ENTRY)); + + std::u16string name(reinterpret_cast(reinterpret_cast(apiset_ns_data) + entry->NameOffset), + entry->NameLength / sizeof(char16_t)); + + if (!entry->ValueCount) + { + continue; + } + + const auto* value = reinterpret_cast( + reinterpret_cast(apiset_ns_data) + entry->ValueOffset + (entry->ValueCount - 1) * sizeof(API_SET_VALUE_ENTRY)); + std::u16string base_name(reinterpret_cast(reinterpret_cast(apiset_ns_data) + value->ValueOffset), + value->ValueLength / sizeof(char16_t)); + + apiset[name + u".dll"] = base_name; + } + + return apiset; + } } diff --git a/src/windows-emulator/apiset/apiset.hpp b/src/windows-emulator/apiset/apiset.hpp index 99422c46..c2cdbe7b 100644 --- a/src/windows-emulator/apiset/apiset.hpp +++ b/src/windows-emulator/apiset/apiset.hpp @@ -3,9 +3,10 @@ #include #include #include - +#include #include "../emulator_utils.hpp" +using apiset_map = std::map; namespace apiset { enum class location : uint8_t @@ -33,4 +34,6 @@ namespace apiset const API_SET_NAMESPACE& orig_api_set_map); emulator_object clone(x86_64_emulator& emu, emulator_allocator& allocator, const container& container); + + apiset_map get_namespace_table(const API_SET_NAMESPACE* apiset_ns_data); } diff --git a/src/windows-emulator/module/module_manager.cpp b/src/windows-emulator/module/module_manager.cpp index 6bfcb15e..7964ff3e 100644 --- a/src/windows-emulator/module/module_manager.cpp +++ b/src/windows-emulator/module/module_manager.cpp @@ -247,6 +247,11 @@ mapped_module* module_manager::map_module_core(const pe_detection_result& detect mapped_module mod = mapper(); mod.is_static = is_static; + if (!mod.path.empty()) + { + this->modules_load_count[mod.path]++; + } + const auto image_base = mod.image_base; const auto entry = this->modules_.try_emplace(image_base, std::move(mod)); this->last_module_cache_ = this->modules_.end(); @@ -468,22 +473,45 @@ void module_manager::map_main_modules(const windows_path& executable_path, windo } } -mapped_module* module_manager::map_module(const windows_path& file, const logger& logger, const bool is_static) +std::optional module_manager::get_module_load_count_by_path(const windows_path& path) { - return this->map_local_module(this->file_sys_->translate(file), logger, is_static); + auto local_file = std::filesystem::weakly_canonical(std::filesystem::absolute(this->file_sys_->translate(path))); + + if (auto load_count_entry = modules_load_count.find(local_file); load_count_entry != modules_load_count.end()) + { + return load_count_entry->second; + } + + return {}; +} + +mapped_module* module_manager::map_module(const windows_path& file, const logger& logger, const bool is_static, bool allow_duplicate) +{ + auto local_file = this->file_sys_->translate(file); + + if (local_file.filename() == "win32u.dll") + { + return this->map_local_module(local_file, logger, is_static, false); + } + + return this->map_local_module(local_file, logger, is_static, allow_duplicate); } // Refactored map_local_module using the new architecture -mapped_module* module_manager::map_local_module(const std::filesystem::path& file, const logger& logger, const bool is_static) +mapped_module* module_manager::map_local_module(const std::filesystem::path& file, const logger& logger, const bool is_static, + bool allow_duplicate) { auto local_file = weakly_canonical(absolute(file)); - // Check if module is already loaded - for (auto& mod : this->modules_ | std::views::values) + if (!allow_duplicate) { - if (mod.path == local_file) + // Check if module is already loaded + for (auto& mod : this->modules_ | std::views::values) { - return &mod; + if (mod.path == local_file) + { + return &mod; + } } } @@ -502,14 +530,17 @@ mapped_module* module_manager::map_local_module(const std::filesystem::path& fil // Refactored map_memory_module using the new architecture mapped_module* module_manager::map_memory_module(uint64_t base_address, uint64_t image_size, const std::string& module_name, - const logger& logger, bool is_static) + const logger& logger, bool is_static, bool allow_duplicate) { - // Check if module is already loaded at this address - for (auto& mod : this->modules_ | std::views::values) + if (!allow_duplicate) { - if (mod.image_base == base_address) + // Check if module is already loaded at this address + for (auto& mod : this->modules_ | std::views::values) { - return &mod; + if (mod.image_base == base_address) + { + return &mod; + } } } @@ -529,6 +560,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->modules_load_count); buffer.write(this->executable ? this->executable->image_base : 0); buffer.write(this->ntdll ? this->ntdll->image_base : 0); @@ -546,6 +578,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->modules_load_count); this->last_module_cache_ = this->modules_.end(); const auto executable_base = buffer.read(); @@ -584,6 +617,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 0cc9d475..dfc60ecf 100644 --- a/src/windows-emulator/module/module_manager.hpp +++ b/src/windows-emulator/module/module_manager.hpp @@ -97,10 +97,12 @@ class module_manager void map_main_modules(const windows_path& executable_path, windows_version_manager& version, process_context& context, const logger& logger); - mapped_module* map_module(const windows_path& file, const logger& logger, bool is_static = false); - mapped_module* map_local_module(const std::filesystem::path& file, const logger& logger, bool is_static = false); + std::optional get_module_load_count_by_path(const windows_path& path); + mapped_module* map_module(const windows_path& file, const logger& logger, bool is_static = false, bool allow_duplicate = false); + mapped_module* map_local_module(const std::filesystem::path& file, const logger& logger, bool is_static = false, + bool allow_duplicate = false); mapped_module* map_memory_module(uint64_t base_address, uint64_t image_size, const std::string& module_name, const logger& logger, - bool is_static = false); + bool is_static = false, bool allow_duplicate = false); mapped_module* find_by_address(const uint64_t address) { @@ -160,6 +162,7 @@ class module_manager mapped_module* executable{}; mapped_module* ntdll{}; mapped_module* win32u{}; + std::map modules_load_count; // WOW64-specific modules (for validation and future use) struct wow64_modules diff --git a/src/windows-emulator/module/module_mapping.cpp b/src/windows-emulator/module/module_mapping.cpp index 6e179b24..e4a24802 100644 --- a/src/windows-emulator/module/module_mapping.cpp +++ b/src/windows-emulator/module/module_mapping.cpp @@ -4,23 +4,10 @@ #include #include +#include namespace { - template - uint64_t get_first_section_offset(const PENTHeaders_t& nt_headers, const uint64_t nt_headers_offset) - { - const auto* nt_headers_addr = reinterpret_cast(&nt_headers); - const size_t optional_header_offset = - reinterpret_cast(&(nt_headers.OptionalHeader)) - reinterpret_cast(&nt_headers); - const size_t optional_header_size = nt_headers.FileHeader.SizeOfOptionalHeader; - const auto* first_section_addr = nt_headers_addr + optional_header_offset + optional_header_size; - - const auto first_section_absolute = reinterpret_cast(first_section_addr); - const auto absolute_base = reinterpret_cast(&nt_headers); - return nt_headers_offset + (first_section_absolute - absolute_base); - } - template std::vector read_mapped_memory(const memory_manager& memory, const mapped_module& binary) { @@ -210,7 +197,7 @@ namespace void map_sections(memory_manager& memory, mapped_module& binary, const utils::safe_buffer_accessor buffer, const PENTHeaders_t& nt_headers, const uint64_t nt_headers_offset) { - const auto first_section_offset = get_first_section_offset(nt_headers, nt_headers_offset); + const auto first_section_offset = winpe::get_first_section_offset(nt_headers, nt_headers_offset); const auto sections = buffer.as(static_cast(first_section_offset)); for (size_t i = 0; i < nt_headers.FileHeader.NumberOfSections; ++i) @@ -384,7 +371,7 @@ mapped_module map_module_from_memory(memory_manager& memory, uint64_t base_addre binary.size_of_heap_reserve = optional_header.SizeOfHeapReserve; binary.size_of_heap_commit = optional_header.SizeOfHeapCommit; - const auto section_offset = get_first_section_offset(nt_headers, nt_headers_offset); + const auto section_offset = winpe::get_first_section_offset(nt_headers, nt_headers_offset); const auto sections = buffer.as(static_cast(section_offset)); for (size_t i = 0; i < nt_headers.FileHeader.NumberOfSections; ++i) diff --git a/src/windows-emulator/process_context.cpp b/src/windows-emulator/process_context.cpp index 8fd5a138..911a7417 100644 --- a/src/windows-emulator/process_context.cpp +++ b/src/windows-emulator/process_context.cpp @@ -5,6 +5,10 @@ #include "windows_emulator.hpp" #include "version/windows_version_manager.hpp" +#include +#include +#include + namespace { emulator_allocator create_allocator(memory_manager& memory, const size_t size, const bool is_wow64_process) @@ -179,9 +183,9 @@ namespace } } -void process_context::setup(x86_64_emulator& emu, memory_manager& memory, registry_manager& registry, windows_version_manager& version, - const application_settings& app_settings, const mapped_module& executable, const mapped_module& ntdll, - const apiset::container& apiset_container, const mapped_module* ntdll32) +void process_context::setup(x86_64_emulator& emu, memory_manager& memory, registry_manager& registry, file_system& file_system, + windows_version_manager& version, const application_settings& app_settings, const mapped_module& executable, + const mapped_module& ntdll, const apiset::container& apiset_container, const mapped_module* ntdll32) { setup_gdt(emu, memory); @@ -386,6 +390,10 @@ 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, 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"); this->rtl_user_thread_start = ntdll.find_export("RtlUserThreadStart"); @@ -520,6 +528,9 @@ 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); buffer.write(this->last_extended_params_numa_node); buffer.write(this->last_extended_params_attributes); @@ -570,6 +581,9 @@ 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); buffer.read(this->last_extended_params_numa_node); buffer.read(this->last_extended_params_attributes); @@ -726,3 +740,164 @@ 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, const apiset_map& apiset, + bool is_32bit) +{ + windows_path system_root_path; + std::set visisted; + std::queue q; + + 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; + } + + size_t i = 0; + for (;;) + { + auto known_dll_name_opt = registry.read_u16string(knowndlls_key.value(), i++); + + if (!known_dll_name_opt) + { + break; + } + + auto known_dll_name = known_dll_name_opt.value(); + utils::string::to_lower_inplace(known_dll_name); + + q.push(known_dll_name); + visisted.insert(known_dll_name); + } + + while (!q.empty()) + { + auto knowndll_filename = q.front(); + q.pop(); + + std::vector file; + if (!utils::io::read_file(file_system.translate(system_root_path / knowndll_filename), &file)) + { + continue; + } + + 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(); + + 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 = 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 (auto apiset_entry = apiset.find(known_dll_dep_name); apiset_entry != apiset.end()) + { + known_dll_dep_name = apiset_entry->second; + } + else + { + continue; + } + } + + if (!visisted.contains(known_dll_dep_name)) + { + q.push(known_dll_dep_name); + visisted.insert(known_dll_dep_name); + } + } + } +} + +bool process_context::has_knowndll_section(const std::u16string& name, bool is_32bit) const +{ + auto lname = utils::string::to_lower(name); + + if (is_32bit) + { + return knowndlls32_sections.contains(lname); + } + + return knowndlls64_sections.contains(lname); +} + +std::optional
process_context::get_knowndll_section_by_name(const std::u16string& name, bool is_32bit) const +{ + auto lname = utils::string::to_lower(name); + + if (is_32bit) + { + if (auto section = knowndlls32_sections.find(lname); section != knowndlls32_sections.end()) + { + return section->second; + } + } + else + { + if (auto section = knowndlls64_sections.find(lname); section != knowndlls64_sections.end()) + { + return section->second; + } + } + + return {}; +} + +void process_context::add_knowndll_section(const std::u16string& name, const section& section, bool is_32bit) +{ + auto lname = utils::string::to_lower(name); + + if (is_32bit) + { + knowndlls32_sections[lname] = section; + } + else + { + knowndlls64_sections[lname] = section; + } +} diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index 77323284..083aec0f 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; class windows_version_manager; +using knowndlls_map = std::map; struct process_context { struct callbacks @@ -73,9 +74,9 @@ struct process_context { } - void setup(x86_64_emulator& emu, memory_manager& memory, registry_manager& registry, windows_version_manager& version, - const application_settings& app_settings, const mapped_module& executable, const mapped_module& ntdll, - const apiset::container& apiset_container, const mapped_module* ntdll32 = nullptr); + void setup(x86_64_emulator& emu, memory_manager& memory, registry_manager& registry, file_system& file_system, + windows_version_manager& version, const application_settings& app_settings, const mapped_module& executable, + const mapped_module& ntdll, const apiset::container& apiset_container, const mapped_module* ntdll32 = nullptr); void setup_callback_hook(windows_emulator& win_emu, memory_manager& memory); @@ -88,6 +89,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, const apiset_map& apiset, bool is_32bit); + + std::optional
get_knowndll_section_by_name(const std::u16string& name, bool is_32bit) const; + void add_knowndll_section(const std::u16string& name, const section& section, bool is_32bit); + bool has_knowndll_section(const std::u16string& name, bool is_32bit) const; + void serialize(utils::buffer_serializer& buffer) const; void deserialize(utils::buffer_deserializer& buffer); @@ -137,6 +145,10 @@ struct process_context handle_store registry_keys{}; std::map atoms{}; + apiset_map apiset; + knowndlls_map knowndlls32_sections; + knowndlls_map knowndlls64_sections; + std::vector default_register_set{}; uint32_t spawned_thread_count{0}; 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.cpp b/src/windows-emulator/syscalls.cpp index 9ce1e84a..163575af 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -364,6 +364,8 @@ namespace syscalls emulator_object return_length); NTSTATUS handle_NtQuerySecurityAttributesToken(); NTSTATUS handle_NtAdjustPrivilegesToken(); + NTSTATUS handle_NtFlushInstructionCache(const syscall_context& c, handle process_handle, emulator_object base_address, + uint64_t region_size); NTSTATUS handle_NtQueryPerformanceCounter(const syscall_context& c, const emulator_object performance_counter, const emulator_object performance_frequency) @@ -1322,6 +1324,7 @@ void syscall_dispatcher::add_handlers(std::map& ha add_handler(NtRemoveProcessDebug); add_handler(NtNotifyChangeDirectoryFileEx); add_handler(NtUserGetHDevName); + add_handler(NtFlushInstructionCache); add_handler(NtUserMapDesktopObject); #undef add_handler diff --git a/src/windows-emulator/syscalls/process.cpp b/src/windows-emulator/syscalls/process.cpp index f708eb73..329db21a 100644 --- a/src/windows-emulator/syscalls/process.cpp +++ b/src/windows-emulator/syscalls/process.cpp @@ -421,4 +421,14 @@ namespace syscalls return STATUS_NOT_SUPPORTED; } + + NTSTATUS handle_NtFlushInstructionCache(const syscall_context& c, const handle process_handle, + const emulator_object base_address, const uint64_t region_size) + { + (void)c; + (void)process_handle; + (void)base_address; + (void)region_size; + return STATUS_SUCCESS; + } } diff --git a/src/windows-emulator/syscalls/section.cpp b/src/windows-emulator/syscalls/section.cpp index 441d31bb..8a373c9c 100644 --- a/src/windows-emulator/syscalls/section.cpp +++ b/src/windows-emulator/syscalls/section.cpp @@ -7,93 +7,7 @@ namespace syscalls { - // Helper function to parse PE headers and extract image information - template - static bool parse_pe_headers(const std::vector& file_data, section::image_info& info) - { - if (file_data.size() < sizeof(PEDosHeader_t)) - { - return false; - } - - const auto* dos_header = reinterpret_cast(file_data.data()); - if (dos_header->e_magic != PEDosHeader_t::k_Magic) - { - return false; - } - - // First check if we can read up to the optional header magic - if (file_data.size() < dos_header->e_lfanew + sizeof(uint32_t) + sizeof(PEFileHeader_t) + sizeof(uint16_t)) - { - return false; - } - - // Read the magic number from the optional header - const auto* magic_ptr = - reinterpret_cast(file_data.data() + dos_header->e_lfanew + sizeof(uint32_t) + sizeof(PEFileHeader_t)); - const uint16_t magic = *magic_ptr; - - // Check if the magic matches the expected type - constexpr uint16_t expected_magic = (sizeof(T) == sizeof(uint32_t)) - ? static_cast(PEOptionalHeader_t::k_Magic) - : static_cast(PEOptionalHeader_t::k_Magic); - - if (magic != expected_magic) - { - return false; - } - - // Now check the full NT headers size - if (file_data.size() < dos_header->e_lfanew + sizeof(PENTHeaders_t)) - { - return false; - } - - const auto* nt_headers = reinterpret_cast*>(file_data.data() + dos_header->e_lfanew); - if (nt_headers->Signature != PENTHeaders_t::k_Signature) - { - return false; - } - - const auto& file_header = nt_headers->FileHeader; - const auto& optional_header = nt_headers->OptionalHeader; - - // Extract information from headers - info.machine = static_cast(file_header.Machine); - info.image_characteristics = file_header.Characteristics; - - info.entry_point_rva = optional_header.AddressOfEntryPoint; - info.image_base = optional_header.ImageBase; - info.subsystem = optional_header.Subsystem; - info.subsystem_major_version = optional_header.MajorSubsystemVersion; - info.subsystem_minor_version = optional_header.MinorSubsystemVersion; - info.dll_characteristics = optional_header.DllCharacteristics; - info.size_of_stack_reserve = optional_header.SizeOfStackReserve; - info.size_of_stack_commit = optional_header.SizeOfStackCommit; - info.size_of_code = optional_header.SizeOfCode; - info.loader_flags = optional_header.LoaderFlags; - info.checksum = optional_header.CheckSum; - - // Check if image contains code - info.has_code = (optional_header.SizeOfCode > 0) || (optional_header.AddressOfEntryPoint != 0); - - // Also check section characteristics for code sections - const auto sections_offset = dos_header->e_lfanew + sizeof(uint32_t) + sizeof(PEFileHeader_t) + file_header.SizeOfOptionalHeader; - if (file_data.size() >= sections_offset + sizeof(IMAGE_SECTION_HEADER) * file_header.NumberOfSections) - { - const auto* sections = reinterpret_cast(file_data.data() + sections_offset); - for (uint16_t i = 0; i < file_header.NumberOfSections; ++i) - { - if (sections[i].Characteristics & IMAGE_SCN_CNT_CODE) - { - info.has_code = true; - break; - } - } - } - - return true; - } + using namespace std::string_view_literals; NTSTATUS handle_NtCreateSection(const syscall_context& c, const emulator_object section_handle, const ACCESS_MASK /*desired_access*/, @@ -141,36 +55,7 @@ namespace syscalls std::vector file_data; if (utils::io::read_file(c.win_emu.file_sys.translate(s.file_name), &file_data)) { - section::image_info info{}; - - // Read the PE magic to determine if it's 32-bit or 64-bit - bool parsed = false; - if (file_data.size() >= sizeof(PEDosHeader_t)) - { - const auto* dos_header = reinterpret_cast(file_data.data()); - if (dos_header->e_magic == PEDosHeader_t::k_Magic && - file_data.size() >= dos_header->e_lfanew + sizeof(uint32_t) + sizeof(PEFileHeader_t) + sizeof(uint16_t)) - { - const auto* magic_ptr = reinterpret_cast(file_data.data() + dos_header->e_lfanew + - sizeof(uint32_t) + sizeof(PEFileHeader_t)); - const uint16_t magic = *magic_ptr; - - // Parse based on the actual PE type - if (magic == PEOptionalHeader_t::k_Magic) - { - parsed = parse_pe_headers(file_data, info); - } - else if (magic == PEOptionalHeader_t::k_Magic) - { - parsed = parse_pe_headers(file_data, info); - } - } - } - - if (parsed) - { - s.cached_image_info = info; - } + s.cache_image_info_from_filedata(file_data); } } @@ -187,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 (filename == u"\\Windows\\SharedSection") + if (utils::string::equals_ignore_case(filename_sv, u"\\Windows\\SharedSection"sv)) { constexpr auto shared_section_size = 0x10000; @@ -203,7 +89,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; @@ -217,29 +103,58 @@ 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; } - if (attributes.RootDirectory != KNOWN_DLLS_DIRECTORY && attributes.RootDirectory != KNOWN_DLLS32_DIRECTORY && - attributes.RootDirectory != BASE_NAMED_OBJECTS_DIRECTORY && !filename.starts_with(u"\\KnownDlls")) + 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_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); - - for (auto& section_entry : c.proc.sections) + if (is_knowndll) { - if (section_entry.second.is_image() && section_entry.second.name == filename) + bool is_knowndll32 = attributes.RootDirectory == KNOWN_DLLS32_DIRECTORY || + utils::string::starts_with_ignore_case(filename_sv, u"\\KnownDlls32\\"sv); + + std::u16string knowndll_name = filename; + + if (utils::string::starts_with_ignore_case(filename_sv, u"\\KnownDlls32\\"sv)) { - section_handle.write(c.proc.sections.make_handle(section_entry.first)); + knowndll_name = filename.substr(13, filename.length() - 13); + } + + else if (utils::string::starts_with_ignore_case(filename_sv, u"\\KnownDlls\\"sv)) + { + knowndll_name = filename.substr(11, filename.length() - 11); + } + + 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; + } + + section_handle.write(c.proc.sections.store(section.value())); + return STATUS_SUCCESS; + } + + for (auto& [handle, section] : c.proc.sections) + { + if (section.is_image() && utils::string::equals_ignore_case(section.name, filename)) + { + section_handle.write(c.proc.sections.make_handle(handle)); return STATUS_SUCCESS; } } @@ -334,7 +249,7 @@ namespace syscalls if (section_entry->is_image()) { - const auto* binary = c.win_emu.mod_manager.map_module(section_entry->file_name, c.win_emu.log); + const auto* binary = c.win_emu.mod_manager.map_module(section_entry->file_name, c.win_emu.log, false, true); if (!binary) { return STATUS_FILE_INVALID; @@ -350,6 +265,17 @@ namespace syscalls base_address.write(binary->image_base); + // Should return STATUS_IMAGE_MACHINE_TYPE_MISMATCH if a 64-bit process tried to map a 32-bit PE. + if (!c.win_emu.process.is_wow64_process && binary->machine == IMAGE_FILE_MACHINE_I386) + { + return STATUS_IMAGE_MACHINE_TYPE_MISMATCH; + } + + if (c.win_emu.mod_manager.get_module_load_count_by_path(section_entry->file_name) > 1) + { + return STATUS_IMAGE_NOT_AT_BASE; + } + return STATUS_SUCCESS; } diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index 185779e3..43e9e277 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -361,8 +361,8 @@ void windows_emulator::setup_process(const application_settings& app_settings) const auto apiset_data = apiset::obtain(this->emulation_root); - this->process.setup(this->emu(), this->memory, this->registry, this->version, app_settings, *executable, *ntdll, apiset_data, - this->mod_manager.wow64_modules_.ntdll32); + this->process.setup(this->emu(), this->memory, this->registry, this->file_sys, this->version, app_settings, *executable, *ntdll, + apiset_data, this->mod_manager.wow64_modules_.ntdll32); const auto ntdll_data = emu.read_memory(ntdll->image_base, static_cast(ntdll->size_of_image)); const auto win32u_data = emu.read_memory(win32u->image_base, static_cast(win32u->size_of_image)); diff --git a/src/windows-emulator/windows_objects.hpp b/src/windows-emulator/windows_objects.hpp index 60432ac0..3b30a203 100644 --- a/src/windows-emulator/windows_objects.hpp +++ b/src/windows-emulator/windows_objects.hpp @@ -5,6 +5,7 @@ #include #include #include +#include struct timer : ref_counted_object { @@ -248,33 +249,47 @@ struct section : ref_counted_object uint64_t maximum_size{}; uint32_t section_page_protection{}; uint32_t allocation_attributes{}; - - // Cached PE image information for image sections - struct image_info - { - uint64_t entry_point_rva{}; - uint64_t image_base{}; - uint64_t size_of_stack_reserve{}; - uint64_t size_of_stack_commit{}; - uint32_t size_of_code{}; - uint32_t loader_flags{}; - uint32_t checksum{}; - uint16_t machine{}; - uint16_t subsystem{}; - uint16_t subsystem_major_version{}; - uint16_t subsystem_minor_version{}; - uint16_t image_characteristics{}; - uint16_t dll_characteristics{}; - bool has_code{false}; - std::array _padding{}; - }; - std::optional cached_image_info{}; + std::optional cached_image_info{}; bool is_image() const { return this->allocation_attributes & SEC_IMAGE; } + void cache_image_info_from_filedata(const std::vector& file_data) + { + winpe::pe_image_basic_info info{}; + + // Read the PE magic to determine if it's 32-bit or 64-bit + bool parsed = false; + if (file_data.size() >= sizeof(PEDosHeader_t)) + { + const auto* dos_header = reinterpret_cast(file_data.data()); + if (dos_header->e_magic == PEDosHeader_t::k_Magic && + file_data.size() >= dos_header->e_lfanew + sizeof(uint32_t) + sizeof(PEFileHeader_t) + sizeof(uint16_t)) + { + const auto* magic_ptr = + reinterpret_cast(file_data.data() + dos_header->e_lfanew + sizeof(uint32_t) + sizeof(PEFileHeader_t)); + const uint16_t magic = *magic_ptr; + + // Parse based on the actual PE type + if (magic == PEOptionalHeader_t::k_Magic) + { + parsed = winpe::parse_pe_headers(file_data, info); + } + else if (magic == PEOptionalHeader_t::k_Magic) + { + parsed = winpe::parse_pe_headers(file_data, info); + } + } + } + + if (parsed) + { + this->cached_image_info = info; + } + } + void serialize_object(utils::buffer_serializer& buffer) const override { buffer.write(this->name); @@ -282,7 +297,7 @@ struct section : ref_counted_object buffer.write(this->maximum_size); buffer.write(this->section_page_protection); buffer.write(this->allocation_attributes); - buffer.write_optional(this->cached_image_info); + buffer.write_optional(this->cached_image_info); } void deserialize_object(utils::buffer_deserializer& buffer) override