From fa1203489cee0009f1526c2717caea157da41f07 Mon Sep 17 00:00:00 2001 From: Ghabry Date: Sat, 21 Dec 2024 13:38:04 +0100 Subject: [PATCH] ExeReader: Support 64 Bit executables Maniac Patch is now detected when the new exe is used. --- src/exe_reader.cpp | 28 ++++++++++++++++++++-------- src/exe_reader.h | 14 +++++++++++++- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src/exe_reader.cpp b/src/exe_reader.cpp index efb2ab6e23..5d0b28d4fc 100644 --- a/src/exe_reader.cpp +++ b/src/exe_reader.cpp @@ -34,19 +34,31 @@ namespace { EXEReader::EXEReader(Filesystem_Stream::InputStream core) : corefile(std::move(core)) { // The Incredibly Dumb PE parser (tm) // Extracts data from the resource section for engine detection and can read ExFont. - uint32_t ofs = GetU32(0x3C); + uint32_t ofs = GetU32(0x3C); // PE header offset uint16_t machine = GetU16(ofs + 4); - if (machine != 0x14c) { + if (machine != 0x14c && machine != 0x8664) { // FIXME: Newer versions of Maniac Patch can be 64 Bit - Output::Debug("EXEReader: Machine type is not i386 ({:#x})", machine); - file_info.is_i386 = false; + Output::Debug("EXEReader: Machine type is not i386 or amd64 ({:#x})", machine); + file_info.machine_type = MachineType::Unknown; return; } + if (machine == 0x14c) { + file_info.machine_type = MachineType::i386; + } else { + file_info.machine_type = MachineType::amd64; + } + // The largest known exe has 11 segments, guard against bogus section data here uint16_t sections = std::min(GetU16(ofs + 6), 11); - uint32_t sectionsOfs = ofs + 0x18 + GetU16(ofs + 0x14); - resource_rva = GetU32(ofs + 0x88); + uint32_t optional_header = ofs + 0x18; + uint32_t oh_magic = GetU16(optional_header); + + bool format_pe32 = (oh_magic == 0x10b); // 0x20b is PE32+ (64 bit) + + uint32_t sectionsOfs = optional_header + GetU16(ofs + 0x14); // skip opt header + uint32_t data_directory_ofs = (format_pe32 ? 0x60 : 0x70); + resource_rva = GetU32(optional_header + data_directory_ofs + 16); if (!resource_rva) { // Is some kind of encrypted EXE -> Give up return; @@ -379,13 +391,13 @@ bool EXEReader::ResNameCheck(uint32_t i, const char* p) { } void EXEReader::FileInfo::Print() const { - Output::Debug("RPG_RT information: version={} logos={} code={:#x} cherry={:#x} geep={:#x} i386={} easyrpg={}", version_str, logos, code_size, cherry_size, geep_size, is_i386, is_easyrpg_player); + Output::Debug("RPG_RT information: version={} logos={} code={:#x} cherry={:#x} geep={:#x} arch={} easyrpg={}", version_str, logos, code_size, cherry_size, geep_size, kMachineTypes[machine_type], is_easyrpg_player); } int EXEReader::FileInfo::GetEngineType(bool& is_maniac_patch) const { is_maniac_patch = false; - if (is_easyrpg_player || !is_i386) { + if (is_easyrpg_player || machine_type == MachineType::Unknown) { return Player::EngineNone; } diff --git a/src/exe_reader.h b/src/exe_reader.h index 41f1c8625f..80899cfc7e 100644 --- a/src/exe_reader.h +++ b/src/exe_reader.h @@ -43,6 +43,18 @@ class EXEReader { std::vector GetExFont(); std::vector> GetLogos(); + enum class MachineType { + Unknown, + i386, + amd64 + }; + + static constexpr auto kMachineTypes = lcf::makeEnumTags( + "Unknown", + "i386", + "amd64" + ); + struct FileInfo { uint64_t version = 0; int logos = 0; @@ -50,7 +62,7 @@ class EXEReader { uint32_t code_size = 0; uint32_t cherry_size = 0; uint32_t geep_size = 0; - bool is_i386 = true; + MachineType machine_type = MachineType::Unknown; bool is_easyrpg_player = false; int GetEngineType(bool& is_maniac_patch) const;