From 53d4effacc7e0f48ca532f4e8c20df92f2fa7d63 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Wed, 28 Aug 2024 19:35:41 +0200 Subject: [PATCH] Extract module mapping --- src/windows_emulator/main.cpp | 108 +----------------------- src/windows_emulator/module_mapper.cpp | 112 +++++++++++++++++++++++++ src/windows_emulator/module_mapper.hpp | 6 ++ 3 files changed, 119 insertions(+), 107 deletions(-) create mode 100644 src/windows_emulator/module_mapper.cpp create mode 100644 src/windows_emulator/module_mapper.hpp diff --git a/src/windows_emulator/main.cpp b/src/windows_emulator/main.cpp index d7eeeed5..d3035c7f 100644 --- a/src/windows_emulator/main.cpp +++ b/src/windows_emulator/main.cpp @@ -12,6 +12,7 @@ #include #include "gdb_stub.hpp" +#include "module_mapper.hpp" #define GS_SEGMENT_ADDR 0x6000000ULL #define GS_SEGMENT_SIZE (20 << 20) // 20 MB @@ -76,101 +77,6 @@ namespace return kusd_object; } - mapped_binary map_module(x64_emulator& emu, const std::vector& module_data, - const std::string& name) - { - mapped_binary binary{}; - - // TODO: Range checks - auto* ptr = module_data.data(); - auto* dos_header = reinterpret_cast(ptr); - auto* nt_headers = reinterpret_cast(ptr + dos_header->e_lfanew); - auto& optional_header = nt_headers->OptionalHeader; - - binary.image_base = optional_header.ImageBase; - binary.size_of_image = optional_header.SizeOfImage; - - 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); - if ((optional_header.DllCharacteristics & - IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) == 0 || // - !emu.allocate_memory( - binary.image_base, binary.size_of_image, memory_permission::read)) - { - throw std::runtime_error("Failed to map binary"); - } - } - - printf("Mapping %s at %llX\n", name.c_str(), binary.image_base); - - emu.write_memory(binary.image_base, ptr, optional_header.SizeOfHeaders); - - const std::span sections(IMAGE_FIRST_SECTION(nt_headers), nt_headers->FileHeader.NumberOfSections); - - for (const auto& section : sections) - { - const auto target_ptr = binary.image_base + section.VirtualAddress; - - if (section.SizeOfRawData > 0) - { - const void* source_ptr = ptr + section.PointerToRawData; - - const auto size_of_data = std::min(section.SizeOfRawData, section.Misc.VirtualSize); - emu.write_memory(target_ptr, source_ptr, size_of_data); - } - auto permissions = memory_permission::none; - - if (section.Characteristics & IMAGE_SCN_MEM_EXECUTE) - { - permissions |= memory_permission::exec; - } - - if (section.Characteristics & IMAGE_SCN_MEM_READ) - { - permissions |= memory_permission::read; - } - - if (section.Characteristics & IMAGE_SCN_MEM_WRITE) - { - permissions |= memory_permission::write; - } - - const auto size_of_section = page_align_up(std::max(section.SizeOfRawData, section.Misc.VirtualSize)); - - emu.protect_memory(target_ptr, size_of_section, permissions, nullptr); - } - - auto& export_directory_entry = optional_header.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; - if (export_directory_entry.VirtualAddress == 0 || export_directory_entry.Size == 0) - { - return binary; - } - - const auto* export_directory = reinterpret_cast(ptr + export_directory_entry. - VirtualAddress); - - //const auto function_count = export_directory->NumberOfFunctions; - const auto names_count = export_directory->NumberOfNames; - - const auto* names = reinterpret_cast(ptr + export_directory->AddressOfNames); - const auto* ordinals = reinterpret_cast(ptr + export_directory->AddressOfNameOrdinals); - const auto* functions = reinterpret_cast(ptr + export_directory->AddressOfFunctions); - - for (DWORD i = 0; i < names_count; i++) - { - exported_symbol symbol{}; - symbol.ordinal = ordinals[i]; - symbol.name = reinterpret_cast(ptr + names[i]); - symbol.rva = functions[symbol.ordinal]; - symbol.address = binary.image_base + symbol.rva; - - binary.exports.push_back(std::move(symbol)); - } - - return binary; - } - process_context setup_context(x64_emulator& emu) { setup_stack(emu, STACK_ADDRESS, STACK_SIZE); @@ -215,18 +121,6 @@ namespace return context; } - std::vector load_file(const std::filesystem::path& file) - { - std::ifstream stream(file, std::ios::in | std::ios::binary); - return {(std::istreambuf_iterator(stream)), std::istreambuf_iterator()}; - } - - mapped_binary map_file(x64_emulator& emu, const std::filesystem::path& file) - { - const auto data = load_file(file); - return map_module(emu, data, file.generic_string()); - } - template class type_info { diff --git a/src/windows_emulator/module_mapper.cpp b/src/windows_emulator/module_mapper.cpp new file mode 100644 index 00000000..9525924b --- /dev/null +++ b/src/windows_emulator/module_mapper.cpp @@ -0,0 +1,112 @@ +#include "std_include.hpp" +#include "module_mapper.hpp" + +namespace +{ + mapped_binary map_module(x64_emulator& emu, const std::vector& module_data, + const std::string& name) + { + mapped_binary binary{}; + + // TODO: Range checks + auto* ptr = module_data.data(); + auto* dos_header = reinterpret_cast(ptr); + auto* nt_headers = reinterpret_cast(ptr + dos_header->e_lfanew); + auto& optional_header = nt_headers->OptionalHeader; + + binary.image_base = optional_header.ImageBase; + binary.size_of_image = optional_header.SizeOfImage; + + 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); + if ((optional_header.DllCharacteristics & + IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) == 0 || // + !emu.allocate_memory( + binary.image_base, binary.size_of_image, memory_permission::read)) + { + throw std::runtime_error("Failed to map binary"); + } + } + + printf("Mapping %s at %llX\n", name.c_str(), binary.image_base); + + emu.write_memory(binary.image_base, ptr, optional_header.SizeOfHeaders); + + const std::span sections(IMAGE_FIRST_SECTION(nt_headers), nt_headers->FileHeader.NumberOfSections); + + for (const auto& section : sections) + { + const auto target_ptr = binary.image_base + section.VirtualAddress; + + if (section.SizeOfRawData > 0) + { + const void* source_ptr = ptr + section.PointerToRawData; + + const auto size_of_data = std::min(section.SizeOfRawData, section.Misc.VirtualSize); + emu.write_memory(target_ptr, source_ptr, size_of_data); + } + auto permissions = memory_permission::none; + + if (section.Characteristics & IMAGE_SCN_MEM_EXECUTE) + { + permissions |= memory_permission::exec; + } + + if (section.Characteristics & IMAGE_SCN_MEM_READ) + { + permissions |= memory_permission::read; + } + + if (section.Characteristics & IMAGE_SCN_MEM_WRITE) + { + permissions |= memory_permission::write; + } + + const auto size_of_section = page_align_up(std::max(section.SizeOfRawData, section.Misc.VirtualSize)); + + emu.protect_memory(target_ptr, size_of_section, permissions, nullptr); + } + + auto& export_directory_entry = optional_header.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; + if (export_directory_entry.VirtualAddress == 0 || export_directory_entry.Size == 0) + { + return binary; + } + + const auto* export_directory = reinterpret_cast(ptr + export_directory_entry. + VirtualAddress); + + //const auto function_count = export_directory->NumberOfFunctions; + const auto names_count = export_directory->NumberOfNames; + + const auto* names = reinterpret_cast(ptr + export_directory->AddressOfNames); + const auto* ordinals = reinterpret_cast(ptr + export_directory->AddressOfNameOrdinals); + const auto* functions = reinterpret_cast(ptr + export_directory->AddressOfFunctions); + + for (DWORD i = 0; i < names_count; i++) + { + exported_symbol symbol{}; + symbol.ordinal = ordinals[i]; + symbol.name = reinterpret_cast(ptr + names[i]); + symbol.rva = functions[symbol.ordinal]; + symbol.address = binary.image_base + symbol.rva; + + binary.exports.push_back(std::move(symbol)); + } + + return binary; + } + + std::vector load_file(const std::filesystem::path& file) + { + std::ifstream stream(file, std::ios::in | std::ios::binary); + return {(std::istreambuf_iterator(stream)), std::istreambuf_iterator()}; + } +} + +mapped_binary map_file(x64_emulator& emu, const std::filesystem::path& file) +{ + const auto data = load_file(file); + return map_module(emu, data, file.generic_string()); +} diff --git a/src/windows_emulator/module_mapper.hpp b/src/windows_emulator/module_mapper.hpp new file mode 100644 index 00000000..309ae76c --- /dev/null +++ b/src/windows_emulator/module_mapper.hpp @@ -0,0 +1,6 @@ +#pragma once + +#include "process_context.hpp" +#include + +mapped_binary map_file(x64_emulator& emu, const std::filesystem::path& file); \ No newline at end of file