diff --git a/src/common/platform/win_pefile.hpp b/src/common/platform/win_pefile.hpp index d73222af..46702454 100644 --- a/src/common/platform/win_pefile.hpp +++ b/src/common/platform/win_pefile.hpp @@ -1,6 +1,10 @@ #pragma once #include +#include +#include +#include +#include // NOLINTBEGIN(modernize-use-using,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) @@ -342,4 +346,63 @@ struct SECTION_IMAGE_INFORMATION ULONG CheckSum; }; +namespace winpe +{ + + enum class pe_arch + { + pe32, + pe64 + }; + + inline std::variant get_pe_arch(const std::filesystem::path& file) + { + std::ifstream f(file, std::ios::binary); + if (!f) + { + return std::make_error_code(std::errc::no_such_file_or_directory); + } + + PEDosHeader_t dos{}; + f.read(reinterpret_cast(&dos), sizeof(dos)); + if (!f || dos.e_magic != PEDosHeader_t::k_Magic) + { + return std::make_error_code(std::errc::executable_format_error); + } + + f.seekg(dos.e_lfanew, std::ios::beg); + uint32_t nt_signature = 0; + f.read(reinterpret_cast(&nt_signature), sizeof(nt_signature)); + if (!f || nt_signature != PENTHeaders_t::k_Signature) + { + return std::make_error_code(std::errc::executable_format_error); + } + + PEFileHeader_t file_header{}; + f.read(reinterpret_cast(&file_header), sizeof(file_header)); + if (!f) + { + return std::make_error_code(std::errc::executable_format_error); + } + + uint16_t magic = 0; + f.read(reinterpret_cast(&magic), sizeof(magic)); + if (!f) + { + return std::make_error_code(std::errc::executable_format_error); + } + + if (magic == PEOptionalHeader_t::k_Magic) + { + return pe_arch::pe32; + } + if (magic == PEOptionalHeader_t::k_Magic) + { + return pe_arch::pe64; + } + + return std::make_error_code(std::errc::executable_format_error); + } +} + // NOLINTEND(modernize-use-using,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) diff --git a/src/windows-emulator/module/module_manager.cpp b/src/windows-emulator/module/module_manager.cpp index 6e20e135..31262857 100644 --- a/src/windows-emulator/module/module_manager.cpp +++ b/src/windows-emulator/module/module_manager.cpp @@ -1,6 +1,7 @@ #include "../std_include.hpp" #include "module_manager.hpp" #include "module_mapping.hpp" +#include "platform/win_pefile.hpp" #include "windows-emulator/logger.hpp" #include @@ -119,7 +120,28 @@ mapped_module* module_manager::map_local_module(const std::filesystem::path& fil try { - auto mod = map_module_from_file(*this->memory_, std::move(local_file)); + mapped_module mod; + auto petype_result = winpe::get_pe_arch(file); + if (std::holds_alternative(petype_result)) + { + if (std::get(petype_result) == winpe::pe_arch::pe32) + { + mod = map_module_from_file(*this->memory_, std::move(local_file)); + } + else if (std::get(petype_result) == winpe::pe_arch::pe64) + { + mod = map_module_from_file(*this->memory_, std::move(local_file)); + } + else + { + throw std::runtime_error("Unknown PE architecture"); + } + } + else + { + throw std::runtime_error("Unknown PE architecture"); + } + mod.is_static = is_static; logger.log("Mapped %s at 0x%" PRIx64 "\n", mod.path.generic_string().c_str(), mod.image_base); diff --git a/src/windows-emulator/module/module_mapping.cpp b/src/windows-emulator/module/module_mapping.cpp index 8f433809..58cd53c1 100644 --- a/src/windows-emulator/module/module_mapping.cpp +++ b/src/windows-emulator/module/module_mapping.cpp @@ -7,7 +7,8 @@ namespace { - uint64_t get_first_section_offset(const PENTHeaders_t& nt_headers, const uint64_t nt_headers_offset) + 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 = @@ -29,8 +30,9 @@ namespace return mem; } + template void collect_exports(mapped_module& binary, const utils::safe_buffer_accessor buffer, - const PEOptionalHeader_t& optional_header) + const PEOptionalHeader_t& optional_header) { const auto& export_directory_entry = optional_header.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; if (export_directory_entry.VirtualAddress == 0 || export_directory_entry.Size == 0) @@ -79,8 +81,9 @@ namespace obj.set(new_value); } + template void apply_relocations(const mapped_module& binary, const utils::safe_buffer_accessor buffer, - const PEOptionalHeader_t& optional_header) + const PEOptionalHeader_t& optional_header) { const auto delta = binary.image_base - optional_header.ImageBase; if (delta == 0) @@ -141,9 +144,10 @@ namespace } } + template 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 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 sections = buffer.as(static_cast(first_section_offset)); @@ -196,6 +200,7 @@ namespace } } +template mapped_module map_module_from_data(memory_manager& memory, const std::span data, std::filesystem::path file) { @@ -208,10 +213,10 @@ mapped_module map_module_from_data(memory_manager& memory, const std::span(0).get(); const auto nt_headers_offset = dos_header.e_lfanew; - const auto nt_headers = buffer.as>(nt_headers_offset).get(); + const auto nt_headers = buffer.as>(nt_headers_offset).get(); const auto& optional_header = nt_headers.OptionalHeader; - if (nt_headers.FileHeader.Machine != PEMachineType::AMD64) + if (nt_headers.FileHeader.Machine != PEMachineType::I386 && nt_headers.FileHeader.Machine != PEMachineType::AMD64) { throw std::runtime_error("Unsupported architecture!"); } @@ -254,6 +259,7 @@ mapped_module map_module_from_data(memory_manager& memory, const std::span mapped_module map_module_from_file(memory_manager& memory, std::filesystem::path file) { const auto data = utils::io::read_file(file); @@ -262,10 +268,19 @@ mapped_module map_module_from_file(memory_manager& memory, std::filesystem::path throw std::runtime_error("Bad file data: " + file.string()); } - return map_module_from_data(memory, data, std::move(file)); + return map_module_from_data(memory, data, std::move(file)); } bool unmap_module(memory_manager& memory, const mapped_module& mod) { return memory.release_memory(mod.image_base, static_cast(mod.size_of_image)); } + +template mapped_module map_module_from_data(memory_manager& memory, + const std::span data, + std::filesystem::path file); +template mapped_module map_module_from_data(memory_manager& memory, + const std::span data, + std::filesystem::path file); +template mapped_module map_module_from_file(memory_manager& memory, std::filesystem::path file); +template mapped_module map_module_from_file(memory_manager& memory, std::filesystem::path file); \ No newline at end of file diff --git a/src/windows-emulator/module/module_mapping.hpp b/src/windows-emulator/module/module_mapping.hpp index 60f0a553..d1d8482d 100644 --- a/src/windows-emulator/module/module_mapping.hpp +++ b/src/windows-emulator/module/module_mapping.hpp @@ -4,6 +4,6 @@ #include "../memory_manager.hpp" mapped_module map_module_from_data(memory_manager& memory, std::span data, std::filesystem::path file); +template mapped_module map_module_from_file(memory_manager& memory, std::filesystem::path file); - bool unmap_module(memory_manager& memory, const mapped_module& mod);