From 5bfb1b06ee1819b58ba3279fa5cc31128a56c89b Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 5 Jan 2025 09:42:14 +0100 Subject: [PATCH 1/3] Show errors if module mapping fails --- .../module/module_manager.cpp | 28 +++-- .../module/module_mapping.cpp | 111 ++++++++---------- .../module/module_mapping.hpp | 4 +- 3 files changed, 69 insertions(+), 74 deletions(-) diff --git a/src/windows-emulator/module/module_manager.cpp b/src/windows-emulator/module/module_manager.cpp index 3f37fadd..f487b1f0 100644 --- a/src/windows-emulator/module/module_manager.cpp +++ b/src/windows-emulator/module/module_manager.cpp @@ -68,7 +68,7 @@ module_manager::module_manager(emulator& emu) mapped_module* module_manager::map_module(const std::filesystem::path& file, logger& logger) { - const auto canonical_file = canonicalize_module_path(file); + auto canonical_file = canonicalize_module_path(file); for (auto& mod : this->modules_) { @@ -78,18 +78,26 @@ mapped_module* module_manager::map_module(const std::filesystem::path& file, log } } - auto mod = map_module_from_file(*this->emu_, std::move(canonical_file)); - if (!mod) + try { - logger.error("Failed to map %s\n", file.generic_string().c_str()); + auto mod = map_module_from_file(*this->emu_, std::move(canonical_file)); + + logger.log("Mapped %s at 0x%llX\n", mod.path.generic_string().c_str(), mod.image_base); + + const auto image_base = mod.image_base; + const auto entry = this->modules_.try_emplace(image_base, std::move(mod)); + return &entry.first->second; + } + catch (const std::exception& e) + { + logger.error("Failed to map %s: %s\n", file.generic_string().c_str(), e.what()); + return nullptr; + } + catch (...) + { + logger.error("Failed to map %s: Unknown error\n", file.generic_string().c_str()); return nullptr; } - - logger.log("Mapped %s at 0x%llX\n", mod->path.generic_string().c_str(), mod->image_base); - - const auto image_base = mod->image_base; - const auto entry = this->modules_.try_emplace(image_base, std::move(*mod)); - return &entry.first->second; } void module_manager::serialize(utils::buffer_serializer& buffer) const diff --git a/src/windows-emulator/module/module_mapping.cpp b/src/windows-emulator/module/module_mapping.cpp index 626cdb69..8e486658 100644 --- a/src/windows-emulator/module/module_mapping.cpp +++ b/src/windows-emulator/module/module_mapping.cpp @@ -185,79 +185,66 @@ namespace binary.sections.push_back(std::move(section_info)); } } - - std::optional map_module(emulator& emu, const std::span data, - std::filesystem::path file) - { - mapped_module binary{}; - binary.path = std::move(file); - binary.name = binary.path.filename().string(); - - utils::safe_buffer_accessor buffer{data}; - - const auto dos_header = buffer.as(0).get(); - const auto nt_headers_offset = dos_header.e_lfanew; - - const auto nt_headers = buffer.as(nt_headers_offset).get(); - auto& optional_header = nt_headers.OptionalHeader; - - binary.image_base = optional_header.ImageBase; - binary.size_of_image = page_align_up(optional_header.SizeOfImage); // TODO: Sanitize - - if (!emu.allocate_memory(binary.image_base, binary.size_of_image, memory_permission::read)) - { - binary.image_base = emu.find_free_allocation_base(binary.size_of_image); - const auto is_dll = nt_headers.FileHeader.Characteristics & IMAGE_FILE_DLL; - const auto has_dynamic_base = - optional_header.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE; - const auto is_relocatable = is_dll || has_dynamic_base; - - if (!is_relocatable || !emu.allocate_memory(binary.image_base, binary.size_of_image, - memory_permission::read)) - { - return {}; - } - } - - binary.entry_point = binary.image_base + optional_header.AddressOfEntryPoint; - - const auto* header_buffer = buffer.get_pointer_for_range(0, optional_header.SizeOfHeaders); - emu.write_memory(binary.image_base, header_buffer, - optional_header.SizeOfHeaders); - - map_sections(emu, binary, buffer, nt_headers, nt_headers_offset); - - auto mapped_memory = read_mapped_memory(emu, binary); - utils::safe_buffer_accessor mapped_buffer{mapped_memory}; - - apply_relocations(binary, mapped_buffer, optional_header); - collect_exports(binary, mapped_buffer, optional_header); - - emu.write_memory(binary.image_base, mapped_memory.data(), mapped_memory.size()); - - return binary; - } } -std::optional map_module_from_data(emulator& emu, const std::span data, - std::filesystem::path file) +mapped_module map_module_from_data(emulator& emu, const std::span data, + std::filesystem::path file) { - try + mapped_module binary{}; + binary.path = std::move(file); + binary.name = binary.path.filename().string(); + + utils::safe_buffer_accessor buffer{data}; + + const auto dos_header = buffer.as(0).get(); + const auto nt_headers_offset = dos_header.e_lfanew; + + const auto nt_headers = buffer.as(nt_headers_offset).get(); + auto& optional_header = nt_headers.OptionalHeader; + + binary.image_base = optional_header.ImageBase; + binary.size_of_image = page_align_up(optional_header.SizeOfImage); // TODO: Sanitize + + if (!emu.allocate_memory(binary.image_base, binary.size_of_image, memory_permission::read)) { - return map_module(emu, data, std::move(file)); - } - catch (...) - { - return {}; + binary.image_base = emu.find_free_allocation_base(binary.size_of_image); + const auto is_dll = nt_headers.FileHeader.Characteristics & IMAGE_FILE_DLL; + const auto has_dynamic_base = + optional_header.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE; + const auto is_relocatable = is_dll || has_dynamic_base; + + if (!is_relocatable || !emu.allocate_memory(binary.image_base, binary.size_of_image, + memory_permission::read)) + { + throw std::runtime_error("Memory range not allocatable"); + } } + + binary.entry_point = binary.image_base + optional_header.AddressOfEntryPoint; + + const auto* header_buffer = buffer.get_pointer_for_range(0, optional_header.SizeOfHeaders); + emu.write_memory(binary.image_base, header_buffer, + optional_header.SizeOfHeaders); + + map_sections(emu, binary, buffer, nt_headers, nt_headers_offset); + + auto mapped_memory = read_mapped_memory(emu, binary); + utils::safe_buffer_accessor mapped_buffer{mapped_memory}; + + apply_relocations(binary, mapped_buffer, optional_header); + collect_exports(binary, mapped_buffer, optional_header); + + emu.write_memory(binary.image_base, mapped_memory.data(), mapped_memory.size()); + + return binary; } -std::optional map_module_from_file(emulator& emu, std::filesystem::path file) +mapped_module map_module_from_file(emulator& emu, std::filesystem::path file) { const auto data = utils::io::read_file(file); if (data.empty()) { - return {}; + throw std::runtime_error("Bad file data"); } return map_module_from_data(emu, data, std::move(file)); diff --git a/src/windows-emulator/module/module_mapping.hpp b/src/windows-emulator/module/module_mapping.hpp index a88f285d..8d69db80 100644 --- a/src/windows-emulator/module/module_mapping.hpp +++ b/src/windows-emulator/module/module_mapping.hpp @@ -3,8 +3,8 @@ #include #include "mapped_module.hpp" -std::optional map_module_from_data(emulator& emu, std::span data, +mapped_module map_module_from_data(emulator& emu, std::span data, std::filesystem::path file); -std::optional map_module_from_file(emulator& emu, std::filesystem::path file); +mapped_module map_module_from_file(emulator& emu, std::filesystem::path file); bool unmap_module(emulator& emu, const mapped_module& mod); From d93120a1223af68ba41d2ee1679c80620e3002cd Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 5 Jan 2025 09:58:06 +0100 Subject: [PATCH 2/3] Assert correct PE machine type --- src/windows-emulator/module/module_mapping.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/windows-emulator/module/module_mapping.cpp b/src/windows-emulator/module/module_mapping.cpp index 8e486658..31e9d00e 100644 --- a/src/windows-emulator/module/module_mapping.cpp +++ b/src/windows-emulator/module/module_mapping.cpp @@ -202,6 +202,11 @@ mapped_module map_module_from_data(emulator& emu, const std::span const auto nt_headers = buffer.as(nt_headers_offset).get(); auto& optional_header = nt_headers.OptionalHeader; + if (nt_headers.FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64) + { + throw std::runtime_error("Unsupported architecture!"); + } + binary.image_base = optional_header.ImageBase; binary.size_of_image = page_align_up(optional_header.SizeOfImage); // TODO: Sanitize From 6f736808ba899429591eeb79eae661c9bbbc857b Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 5 Jan 2025 10:19:19 +0100 Subject: [PATCH 3/3] Small cleanup --- src/windows-emulator/module/module_mapping.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/windows-emulator/module/module_mapping.cpp b/src/windows-emulator/module/module_mapping.cpp index 31e9d00e..d9adb256 100644 --- a/src/windows-emulator/module/module_mapping.cpp +++ b/src/windows-emulator/module/module_mapping.cpp @@ -35,20 +35,24 @@ namespace const auto export_directory = buffer.as(export_directory_entry. VirtualAddress).get(); - //const auto function_count = export_directory->NumberOfFunctions; const auto names_count = export_directory.NumberOfNames; + //const auto function_count = export_directory.NumberOfFunctions; const auto names = buffer.as(export_directory.AddressOfNames); const auto ordinals = buffer.as(export_directory.AddressOfNameOrdinals); const auto functions = buffer.as(export_directory.AddressOfFunctions); + binary.exports.reserve(names_count); + for (DWORD i = 0; i < names_count; i++) { + const auto ordinal = ordinals.get(i); + exported_symbol symbol{}; - symbol.ordinal = ordinals.get(i); - symbol.name = buffer.as_string(names.get(i)); - symbol.rva = functions.get(symbol.ordinal); + symbol.ordinal = export_directory.Base + ordinal; + symbol.rva = functions.get(ordinal); symbol.address = binary.image_base + symbol.rva; + symbol.name = buffer.as_string(names.get(i)); binary.exports.push_back(std::move(symbol)); }