[XEX] - add more file signatures

- Add older xex file signatures
- Add xex1 devkit key
- Add xex1 support
This commit is contained in:
The-Little-Wolf
2026-03-28 19:18:23 -07:00
committed by Radosław Gliński
parent 8486e97a06
commit 131503f68d
6 changed files with 115 additions and 36 deletions

View File

@@ -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<const xex1_security_info*>(
GetSecurityInfo(xex_header()));
switch (xex_format_) {
case kFormatXex1: {
const xex1_security_info* xex1_sec_info =
reinterpret_cast<const xex1_security_info*>(
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<const xex2_security_info*>(
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<const xex2_security_info*>(
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<const xex2_header*>(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;
}
}
}
}

View File

@@ -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,
};

View File

@@ -370,6 +370,10 @@ const std::unique_ptr<vfs::Device> 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<vfs::Device> Emulator::CreateVfsDevice(
case FileSignatureType::ZAR: {
return std::make_unique<vfs::DiscZarchiveDevice>(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);

View File

@@ -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

View File

@@ -132,7 +132,9 @@ X_STATUS UserModule::LoadFromMemory(const void* addr, const size_t length) {
be<fourcc_t> magic;
magic.value = xe::load<fourcc_t>(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<fourcc_t>(addr);
XELOGE("Unknown module magic: {:08X}", magic.get());
return X_STATUS_NOT_IMPLEMENTED;
}

View File

@@ -794,7 +794,7 @@ struct xex2_security_info {
xe::be<uint32_t> header_size; // 0x0
xe::be<uint32_t> image_size; // 0x4
char rsa_signature[0x100]; // 0x8
xe::be<uint32_t> unk_108; // 0x108 unk length
xe::be<uint32_t> info_size; // 0x108
xe::be<xex2_image_flags> image_flags; // 0x10C
xe::be<uint32_t> load_address; // 0x110
char section_digest[0x14]; // 0x114