mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-19 11:43:56 +00:00
Comprehensive WOW64 subsystem implementation
This commit is contained in:
@@ -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 =
|
||||
@@ -20,6 +21,7 @@ namespace
|
||||
return nt_headers_offset + (first_section_absolute - absolute_base);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::vector<std::byte> read_mapped_memory(const memory_manager& memory, const mapped_module& binary)
|
||||
{
|
||||
std::vector<std::byte> mem{};
|
||||
@@ -29,8 +31,9 @@ namespace
|
||||
return mem;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void collect_imports(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& import_directory_entry = optional_header.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
|
||||
if (import_directory_entry.VirtualAddress == 0 || import_directory_entry.Size == 0)
|
||||
@@ -48,13 +51,17 @@ namespace
|
||||
break;
|
||||
}
|
||||
|
||||
// Use architecture-specific thunk data type
|
||||
using thunk_traits = thunk_data_traits<T>;
|
||||
using thunk_type = typename thunk_traits::type;
|
||||
|
||||
const auto module_index = binary.imported_modules.size();
|
||||
binary.imported_modules.push_back(buffer.as_string(descriptor.Name));
|
||||
|
||||
auto original_thunk_data = buffer.as<IMAGE_THUNK_DATA64>(descriptor.FirstThunk);
|
||||
auto original_thunk_data = buffer.as<thunk_type>(descriptor.FirstThunk);
|
||||
if (descriptor.OriginalFirstThunk)
|
||||
{
|
||||
original_thunk_data = buffer.as<IMAGE_THUNK_DATA64>(descriptor.OriginalFirstThunk);
|
||||
original_thunk_data = buffer.as<thunk_type>(descriptor.OriginalFirstThunk);
|
||||
}
|
||||
|
||||
for (size_t j = 0;; ++j)
|
||||
@@ -65,16 +72,17 @@ namespace
|
||||
break;
|
||||
}
|
||||
|
||||
static_assert(sizeof(IMAGE_THUNK_DATA64) == sizeof(uint64_t));
|
||||
const auto thunk_rva = descriptor.FirstThunk + sizeof(IMAGE_THUNK_DATA64) * j;
|
||||
static_assert(sizeof(thunk_type) == sizeof(T));
|
||||
const auto thunk_rva = descriptor.FirstThunk + sizeof(thunk_type) * j;
|
||||
const auto thunk_address = thunk_rva + binary.image_base;
|
||||
|
||||
auto& sym = binary.imports[thunk_address];
|
||||
sym.module_index = module_index;
|
||||
|
||||
if (IMAGE_SNAP_BY_ORDINAL64(original_thunk.u1.Ordinal))
|
||||
// Use architecture-specific ordinal checking
|
||||
if (thunk_traits::snap_by_ordinal(original_thunk.u1.Ordinal))
|
||||
{
|
||||
sym.name = "#" + std::to_string(IMAGE_ORDINAL64(original_thunk.u1.Ordinal));
|
||||
sym.name = "#" + std::to_string(thunk_traits::ordinal_mask(original_thunk.u1.Ordinal));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -85,8 +93,9 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -134,8 +143,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)
|
||||
@@ -196,8 +206,9 @@ 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 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));
|
||||
@@ -250,6 +261,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)
|
||||
{
|
||||
mapped_module binary{};
|
||||
@@ -261,20 +273,43 @@ 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!");
|
||||
}
|
||||
|
||||
binary.image_base = optional_header.ImageBase;
|
||||
binary.image_base_file = optional_header.ImageBase;
|
||||
binary.size_of_image = page_align_up(optional_header.SizeOfImage); // TODO: Sanitize
|
||||
|
||||
// Store PE header fields
|
||||
binary.machine = static_cast<uint16_t>(nt_headers.FileHeader.Machine);
|
||||
binary.size_of_stack_reserve = optional_header.SizeOfStackReserve;
|
||||
binary.size_of_stack_commit = optional_header.SizeOfStackCommit;
|
||||
binary.size_of_heap_reserve = optional_header.SizeOfHeapReserve;
|
||||
binary.size_of_heap_commit = optional_header.SizeOfHeapCommit;
|
||||
|
||||
if (!memory.allocate_memory(binary.image_base, static_cast<size_t>(binary.size_of_image), memory_permission::all))
|
||||
{
|
||||
binary.image_base = memory.find_free_allocation_base(static_cast<size_t>(binary.size_of_image));
|
||||
// Check if this is a 32-bit module (WOW64)
|
||||
const bool is_32bit = (nt_headers.FileHeader.Machine == PEMachineType::I386);
|
||||
|
||||
if (is_32bit)
|
||||
{
|
||||
// Use 32-bit allocation for WOW64 modules
|
||||
binary.image_base =
|
||||
memory.find_free_allocation_base(static_cast<size_t>(binary.size_of_image), DEFAULT_ALLOCATION_ADDRESS_32BIT);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use 64-bit allocation for native modules
|
||||
binary.image_base =
|
||||
memory.find_free_allocation_base(static_cast<size_t>(binary.size_of_image), DEFAULT_ALLOCATION_ADDRESS_64BIT);
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -296,7 +331,7 @@ mapped_module map_module_from_data(memory_manager& memory, const std::span<const
|
||||
|
||||
map_sections(memory, binary, buffer, nt_headers, nt_headers_offset);
|
||||
|
||||
auto mapped_memory = read_mapped_memory(memory, binary);
|
||||
auto mapped_memory = read_mapped_memory<T>(memory, binary);
|
||||
utils::safe_buffer_accessor<std::byte> mapped_buffer{mapped_memory};
|
||||
|
||||
apply_relocations(binary, mapped_buffer, optional_header);
|
||||
@@ -308,6 +343,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);
|
||||
@@ -316,18 +352,20 @@ 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));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
mapped_module map_module_from_memory(memory_manager& memory, uint64_t base_address, uint64_t image_size, const std::string& module_name)
|
||||
{
|
||||
mapped_module binary{};
|
||||
binary.name = module_name;
|
||||
binary.path = module_name;
|
||||
binary.image_base = base_address;
|
||||
binary.image_base_file = base_address;
|
||||
binary.size_of_image = image_size;
|
||||
|
||||
auto mapped_memory = read_mapped_memory(memory, binary);
|
||||
auto mapped_memory = read_mapped_memory<T>(memory, binary);
|
||||
utils::safe_buffer_accessor<const std::byte> buffer{mapped_memory};
|
||||
|
||||
try
|
||||
@@ -339,6 +377,13 @@ mapped_module map_module_from_memory(memory_manager& memory, uint64_t base_addre
|
||||
|
||||
binary.entry_point = binary.image_base + optional_header.AddressOfEntryPoint;
|
||||
|
||||
// Store PE header fields
|
||||
binary.machine = static_cast<uint16_t>(nt_headers.FileHeader.Machine);
|
||||
binary.size_of_stack_reserve = optional_header.SizeOfStackReserve;
|
||||
binary.size_of_stack_commit = optional_header.SizeOfStackCommit;
|
||||
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 sections = buffer.as<IMAGE_SECTION_HEADER>(static_cast<size_t>(section_offset));
|
||||
|
||||
@@ -390,3 +435,15 @@ 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);
|
||||
|
||||
template mapped_module map_module_from_memory<std::uint32_t>(memory_manager& memory, uint64_t base_address, uint64_t image_size,
|
||||
const std::string& module_name);
|
||||
template mapped_module map_module_from_memory<std::uint64_t>(memory_manager& memory, uint64_t base_address, uint64_t image_size,
|
||||
const std::string& module_name);
|
||||
Reference in New Issue
Block a user