support mapping 32bit files

This commit is contained in:
robert-yates
2025-04-25 22:13:31 +02:00
parent 9c2a0d946e
commit 4b5d82079c
4 changed files with 110 additions and 10 deletions

View File

@@ -1,6 +1,10 @@
#pragma once
#include <cstdint>
#include <filesystem>
#include <fstream>
#include <system_error>
#include <variant>
// 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<pe_arch, std::error_code> 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<char*>(&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<char*>(&nt_signature), sizeof(nt_signature));
if (!f || nt_signature != PENTHeaders_t<std::uint32_t>::k_Signature)
{
return std::make_error_code(std::errc::executable_format_error);
}
PEFileHeader_t file_header{};
f.read(reinterpret_cast<char*>(&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<char*>(&magic), sizeof(magic));
if (!f)
{
return std::make_error_code(std::errc::executable_format_error);
}
if (magic == PEOptionalHeader_t<std::uint32_t>::k_Magic)
{
return pe_arch::pe32;
}
if (magic == PEOptionalHeader_t<std::uint64_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)

View File

@@ -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 <serialization_helper.hpp>
@@ -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<winpe::pe_arch>(petype_result))
{
if (std::get<winpe::pe_arch>(petype_result) == winpe::pe_arch::pe32)
{
mod = map_module_from_file<std::uint32_t>(*this->memory_, std::move(local_file));
}
else if (std::get<winpe::pe_arch>(petype_result) == winpe::pe_arch::pe64)
{
mod = map_module_from_file<std::uint64_t>(*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);

View File

@@ -7,7 +7,8 @@
namespace
{
uint64_t get_first_section_offset(const PENTHeaders_t<std::uint64_t>& nt_headers, const uint64_t nt_headers_offset)
template <typename T>
uint64_t get_first_section_offset(const PENTHeaders_t<T>& nt_headers, const uint64_t nt_headers_offset)
{
const auto* nt_headers_addr = reinterpret_cast<const uint8_t*>(&nt_headers);
const size_t optional_header_offset =
@@ -29,8 +30,9 @@ namespace
return mem;
}
template <typename T>
void collect_exports(mapped_module& binary, const utils::safe_buffer_accessor<const std::byte> buffer,
const PEOptionalHeader_t<std::uint64_t>& optional_header)
const PEOptionalHeader_t<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 <typename T>
void apply_relocations(const mapped_module& binary, const utils::safe_buffer_accessor<std::byte> buffer,
const PEOptionalHeader_t<std::uint64_t>& optional_header)
const PEOptionalHeader_t<T>& optional_header)
{
const auto delta = binary.image_base - optional_header.ImageBase;
if (delta == 0)
@@ -141,9 +144,10 @@ namespace
}
}
template <typename T>
void map_sections(memory_manager& memory, mapped_module& binary,
const utils::safe_buffer_accessor<const std::byte> buffer,
const PENTHeaders_t<std::uint64_t>& nt_headers, const uint64_t nt_headers_offset)
const utils::safe_buffer_accessor<const std::byte> buffer, const PENTHeaders_t<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<IMAGE_SECTION_HEADER>(static_cast<size_t>(first_section_offset));
@@ -196,6 +200,7 @@ namespace
}
}
template <typename T>
mapped_module map_module_from_data(memory_manager& memory, const std::span<const std::byte> data,
std::filesystem::path file)
{
@@ -208,10 +213,10 @@ mapped_module map_module_from_data(memory_manager& memory, const std::span<const
const auto dos_header = buffer.as<PEDosHeader_t>(0).get();
const auto nt_headers_offset = dos_header.e_lfanew;
const auto nt_headers = buffer.as<PENTHeaders_t<std::uint64_t>>(nt_headers_offset).get();
const auto nt_headers = buffer.as<PENTHeaders_t<T>>(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<const
return binary;
}
template <typename T>
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<T>(memory, data, std::move(file));
}
bool unmap_module(memory_manager& memory, const mapped_module& mod)
{
return memory.release_memory(mod.image_base, static_cast<size_t>(mod.size_of_image));
}
template mapped_module map_module_from_data<std::uint32_t>(memory_manager& memory,
const std::span<const std::byte> data,
std::filesystem::path file);
template mapped_module map_module_from_data<std::uint64_t>(memory_manager& memory,
const std::span<const std::byte> data,
std::filesystem::path file);
template mapped_module map_module_from_file<std::uint32_t>(memory_manager& memory, std::filesystem::path file);
template mapped_module map_module_from_file<std::uint64_t>(memory_manager& memory, std::filesystem::path file);

View File

@@ -4,6 +4,6 @@
#include "../memory_manager.hpp"
mapped_module map_module_from_data(memory_manager& memory, std::span<const uint8_t> data, std::filesystem::path file);
template <typename T>
mapped_module map_module_from_file(memory_manager& memory, std::filesystem::path file);
bool unmap_module(memory_manager& memory, const mapped_module& mod);