From 131503f68d4b34811154437ae224960ba15b5007 Mon Sep 17 00:00:00 2001 From: The-Little-Wolf <116989599+The-Little-Wolf@users.noreply.github.com> Date: Sat, 28 Mar 2026 19:18:23 -0700 Subject: [PATCH] [XEX] - add more file signatures - Add older xex file signatures - Add xex1 devkit key - Add xex1 support --- src/xenia/cpu/xex_module.cc | 106 ++++++++++++++++++++---------- src/xenia/cpu/xex_module.h | 9 +++ src/xenia/emulator.cc | 23 +++++++ src/xenia/emulator.h | 5 ++ src/xenia/kernel/user_module.cc | 6 +- src/xenia/kernel/util/xex2_info.h | 2 +- 6 files changed, 115 insertions(+), 36 deletions(-) diff --git a/src/xenia/cpu/xex_module.cc b/src/xenia/cpu/xex_module.cc index 7cbc60ac5..900a5af91 100644 --- a/src/xenia/cpu/xex_module.cc +++ b/src/xenia/cpu/xex_module.cc @@ -54,6 +54,9 @@ DECLARE_bool(disable_context_promotion); static constexpr uint8_t xe_xex1_retail_key[16] = { 0xA2, 0x6C, 0x10, 0xF7, 0x1F, 0xD9, 0x35, 0xE9, 0x8B, 0x99, 0x92, 0x2C, 0xE9, 0x32, 0x15, 0x72}; +static constexpr uint8_t xe_xex1_devkit_key[16] = { + 0xA8, 0xB0, 0x05, 0x12, 0xED, 0xE3, 0x63, 0x8D, + 0xC6, 0x58, 0xB3, 0x10, 0x1F, 0x9F, 0x50, 0xD1}; static constexpr uint8_t xe_xex2_retail_key[16] = { 0x20, 0xB1, 0x85, 0xA5, 0x9D, 0x28, 0xFD, 0xC3, 0x40, 0x58, 0x3F, 0xBB, 0x08, 0x96, 0xBF, 0x91}; @@ -884,32 +887,37 @@ int XexModule::ReadPEHeaders() { } void XexModule::ReadSecurityInfo() { - if (xex_format_ == kFormatXex1) { - const xex1_security_info* xex1_sec_info = - reinterpret_cast( - GetSecurityInfo(xex_header())); + switch (xex_format_) { + case kFormatXex1: { + const xex1_security_info* xex1_sec_info = + reinterpret_cast( + GetSecurityInfo(xex_header())); - security_info_.rsa_signature = xex1_sec_info->rsa_signature; - security_info_.aes_key = xex1_sec_info->aes_key; - security_info_.image_size = xex1_sec_info->image_size; - security_info_.image_flags = xex1_sec_info->image_flags; - security_info_.export_table = xex1_sec_info->export_table; - security_info_.load_address = xex1_sec_info->load_address; - security_info_.page_descriptor_count = xex1_sec_info->page_descriptor_count; - security_info_.page_descriptors = xex1_sec_info->page_descriptors; - } else if (xex_format_ == kFormatXex2) { - const xex2_security_info* xex2_sec_info = - reinterpret_cast( - GetSecurityInfo(xex_header())); + security_info_.rsa_signature = xex1_sec_info->rsa_signature; + security_info_.aes_key = xex1_sec_info->aes_key; + security_info_.image_size = xex1_sec_info->image_size; + security_info_.image_flags = xex1_sec_info->image_flags; + security_info_.export_table = xex1_sec_info->export_table; + security_info_.load_address = xex1_sec_info->load_address; + security_info_.page_descriptor_count = + xex1_sec_info->page_descriptor_count; + security_info_.page_descriptors = xex1_sec_info->page_descriptors; + } break; + case kFormatXex2: { + const xex2_security_info* xex2_sec_info = + reinterpret_cast( + GetSecurityInfo(xex_header())); - security_info_.rsa_signature = xex2_sec_info->rsa_signature; - security_info_.aes_key = xex2_sec_info->aes_key; - security_info_.image_size = xex2_sec_info->image_size; - security_info_.image_flags = xex2_sec_info->image_flags; - security_info_.export_table = xex2_sec_info->export_table; - security_info_.load_address = xex2_sec_info->load_address; - security_info_.page_descriptor_count = xex2_sec_info->page_descriptor_count; - security_info_.page_descriptors = xex2_sec_info->page_descriptors; + security_info_.rsa_signature = xex2_sec_info->rsa_signature; + security_info_.aes_key = xex2_sec_info->aes_key; + security_info_.image_size = xex2_sec_info->image_size; + security_info_.image_flags = xex2_sec_info->image_flags; + security_info_.export_table = xex2_sec_info->export_table; + security_info_.load_address = xex2_sec_info->load_address; + security_info_.page_descriptor_count = + xex2_sec_info->page_descriptor_count; + security_info_.page_descriptors = xex2_sec_info->page_descriptors; + } break; } } @@ -917,12 +925,32 @@ bool XexModule::Load(const std::string_view name, const std::string_view path, const void* xex_addr, size_t xex_length) { auto src_header = reinterpret_cast(xex_addr); - if (src_header->magic == kXEX1Signature) { - xex_format_ = kFormatXex1; - } else if (src_header->magic == kXEX2Signature) { - xex_format_ = kFormatXex2; - } else { - return false; + switch (src_header->magic) { + case kXEX0Signature: + XELOGE("XEX0 format not supported"); + return false; + break; + case kXEXQSignature: + XELOGE("XEX? format not supported"); + return false; + break; + case kXEXHSignature: + XELOGE("XEX- format not supported"); + return false; + break; + case kXEXPSignature: + XELOGE("XEX% format not supported"); + return false; + break; + case kXEX1Signature: + xex_format_ = kFormatXex1; + break; + case kXEX2Signature: + xex_format_ = kFormatXex2; + break; + default: + XELOGE("XEX format not supported"); + return false; } assert_false(loaded_); @@ -958,13 +986,23 @@ bool XexModule::Load(const std::string_view name, const std::string_view path, result_code = ReadImage(xex_addr, xex_length, xe_xex2_devkit_key); if (result_code) { - XELOGE("XEX load failed with code {}, trying with xex1 encryption key...", - result_code); + XELOGE( + "XEX load failed with code {}, trying with xex1 retail encryption " + "key...", + result_code); result_code = ReadImage(xex_addr, xex_length, xe_xex1_retail_key); if (result_code) { - XELOGE("XEX load failed with code {}", result_code); - return false; + XELOGE( + "XEX load failed with code {}, trying with xex1 devkit encryption " + "key...", + result_code); + + result_code = ReadImage(xex_addr, xex_length, xe_xex1_devkit_key); + if (result_code) { + XELOGE("XEX load failed with code {}", result_code); + return false; + } } } } diff --git a/src/xenia/cpu/xex_module.h b/src/xenia/cpu/xex_module.h index 7272874e3..7f0ac364f 100644 --- a/src/xenia/cpu/xex_module.h +++ b/src/xenia/cpu/xex_module.h @@ -25,9 +25,14 @@ class KernelState; namespace xe { namespace cpu { +constexpr fourcc_t kXEX0Signature = make_fourcc("XEX0"); +constexpr fourcc_t kXEXQSignature = make_fourcc("XEX?"); +constexpr fourcc_t kXEXHSignature = make_fourcc("XEX-"); +constexpr fourcc_t kXEXPSignature = make_fourcc("XEX%"); constexpr fourcc_t kXEX1Signature = make_fourcc("XEX1"); constexpr fourcc_t kXEX2Signature = make_fourcc("XEX2"); constexpr fourcc_t kElfSignature = make_fourcc(0x7F, 'E', 'L', 'F'); +constexpr fourcc_t kXBESignature = make_fourcc("XBEH"); class Runtime; struct InfoCacheFlags { @@ -115,6 +120,10 @@ class XexModule : public xe::cpu::Module { }; enum XexFormat { kFormatUnknown, + kFormatXex0, + kFormatXexQ, // ? + kFormatXexH, // - + kFormatXexP, // % kFormatXex1, kFormatXex2, }; diff --git a/src/xenia/emulator.cc b/src/xenia/emulator.cc index 4a59fc4fd..9074b1073 100644 --- a/src/xenia/emulator.cc +++ b/src/xenia/emulator.cc @@ -370,6 +370,10 @@ const std::unique_ptr Emulator::CreateVfsDevice( const std::filesystem::path& path, const std::string_view mount_path) { // Must check if the type has changed e.g. XamSwapDisc switch (GetFileSignature(path)) { + case FileSignatureType::XEX0: + case FileSignatureType::XEXQ: + case FileSignatureType::XEXH: + case FileSignatureType::XEXP: case FileSignatureType::XEX1: case FileSignatureType::XEX2: case FileSignatureType::ELF: { @@ -389,6 +393,7 @@ const std::unique_ptr Emulator::CreateVfsDevice( case FileSignatureType::ZAR: { return std::make_unique(mount_path, path); } break; + case FileSignatureType::XBE: case FileSignatureType::EXE: case FileSignatureType::Unknown: default: @@ -488,6 +493,14 @@ Emulator::FileSignatureType Emulator::GetFileSignature( fclose(file); switch (magic_value) { + case xe::cpu::kXEX0Signature: + return FileSignatureType::XEX0; + case xe::cpu::kXEXQSignature: + return FileSignatureType::XEXQ; + case xe::cpu::kXEXHSignature: + return FileSignatureType::XEXH; + case xe::cpu::kXEXPSignature: + return FileSignatureType::XEXP; case xe::cpu::kXEX1Signature: return FileSignatureType::XEX1; case xe::cpu::kXEX2Signature: @@ -500,6 +513,8 @@ Emulator::FileSignatureType Emulator::GetFileSignature( return FileSignatureType::PIRS; case xe::vfs::kXSFSignature: return FileSignatureType::XISO; + case xe::cpu::kXBESignature: + return FileSignatureType::XBE; case xe::cpu::kElfSignature: return FileSignatureType::ELF; default: @@ -542,6 +557,10 @@ X_STATUS Emulator::LaunchPath(const std::filesystem::path& path) { X_STATUS mount_result = X_STATUS_SUCCESS; switch (GetFileSignature(path)) { + case FileSignatureType::XEX0: + case FileSignatureType::XEXQ: + case FileSignatureType::XEXH: + case FileSignatureType::XEXP: case FileSignatureType::XEX1: case FileSignatureType::XEX2: case FileSignatureType::ELF: { @@ -558,6 +577,10 @@ X_STATUS Emulator::LaunchPath(const std::filesystem::path& path) { mount_result = MountPath(path, "\\Device\\Cdrom0"); return mount_result ? mount_result : LaunchDiscImage(path); } break; + case FileSignatureType::XBE: { + XELOGE("OG Xbox games are not supported"); + return X_STATUS_NOT_SUPPORTED; + } break; case FileSignatureType::ZAR: { mount_result = MountPath(path, "\\Device\\Cdrom0"); return mount_result ? mount_result : LaunchDiscArchive(path); diff --git a/src/xenia/emulator.h b/src/xenia/emulator.h index f6c94536e..7416338d9 100644 --- a/src/xenia/emulator.h +++ b/src/xenia/emulator.h @@ -201,6 +201,10 @@ class Emulator { const std::string_view mount_path); enum class FileSignatureType { + XEX0, + XEXQ, + XEXH, + XEXP, XEX1, XEX2, ELF, @@ -208,6 +212,7 @@ class Emulator { LIVE, PIRS, XISO, + XBE, ZAR, EXE, Unknown diff --git a/src/xenia/kernel/user_module.cc b/src/xenia/kernel/user_module.cc index c2c034276..1493abd81 100644 --- a/src/xenia/kernel/user_module.cc +++ b/src/xenia/kernel/user_module.cc @@ -132,7 +132,9 @@ X_STATUS UserModule::LoadFromMemory(const void* addr, const size_t length) { be magic; magic.value = xe::load(addr); - if (magic == xe::cpu::kXEX2Signature || magic == xe::cpu::kXEX1Signature) { + if (magic == xe::cpu::kXEX2Signature || magic == xe::cpu::kXEX1Signature || + magic == xe::cpu::kXEXQSignature || magic == xe::cpu::kXEXHSignature || + magic == xe::cpu::kXEXPSignature || magic == xe::cpu::kXEX0Signature) { module_format_ = kModuleFormatXex; } else if (magic == xe::cpu::kElfSignature) { module_format_ = kModuleFormatElf; @@ -146,6 +148,8 @@ X_STATUS UserModule::LoadFromMemory(const void* addr, const size_t length) { XELOGE("XNA executables are not yet implemented"); return X_STATUS_NOT_IMPLEMENTED; } else { + // restore it back + magic.value = xe::load(addr); XELOGE("Unknown module magic: {:08X}", magic.get()); return X_STATUS_NOT_IMPLEMENTED; } diff --git a/src/xenia/kernel/util/xex2_info.h b/src/xenia/kernel/util/xex2_info.h index 69e8f20ff..82641fc97 100644 --- a/src/xenia/kernel/util/xex2_info.h +++ b/src/xenia/kernel/util/xex2_info.h @@ -794,7 +794,7 @@ struct xex2_security_info { xe::be header_size; // 0x0 xe::be image_size; // 0x4 char rsa_signature[0x100]; // 0x8 - xe::be unk_108; // 0x108 unk length + xe::be info_size; // 0x108 xe::be image_flags; // 0x10C xe::be load_address; // 0x110 char section_digest[0x14]; // 0x114