diff --git a/README.md b/README.md index 1621434..f516354 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ Property|Description restgprlr_14_address|Start address of the `__restgprlr_14` function. It starts with `ld r14, -0x98(r1)`, repeating the same operation for the rest of the non-volatile registers and restoring the link register at the end. savegprlr_14_address|Start address of the `__savegprlr_14` function. It starts with `std r14, -0x98(r1)`, repeating the same operation for the rest of the non-volatile registers and saving the link register at the end. restfpr_14_address|Start address of the `__restfpr_14` function. It starts with `lfd f14, -0x90(r12)`, repeating the same operation for the rest of the non-volatile FPU registers. -savefpr_14_address|Start address of the `__savefpr_14` function. It starts with `stfd r14, -0x90(r12)`, repeating the same operation for the rest of the non-volatile FPU registers. +savefpr_14_address|Start address of the `__savefpr_14` function. It starts with `stfd f14, -0x90(r12)`, repeating the same operation for the rest of the non-volatile FPU registers. restvmx_14_address|Start address of the `__restvmx_14` function. It starts with `li r11, -0x120` and `lvx v14, r11, r12`, repeating the same operation for the rest of the non-volatile VMX registers until `v31`. savevmx_14_address|Start address of the `__savevmx_14` function. It starts with `li r11, -0x120` and `stvx v14, r11, r12`, repeating the same operation for the rest of the non-volatile VMX registers until `v31`. restvmx_64_address|Start address of the `__restvmx_64` function. It starts with `li r11, -0x400` and `lvx128 v64, r11, r12`, repeating the same operation for the rest of the non-volatile VMX registers. diff --git a/XenonUtils/byteswap.h b/XenonUtils/byteswap.h index 33e959f..46d1734 100644 --- a/XenonUtils/byteswap.h +++ b/XenonUtils/byteswap.h @@ -2,24 +2,31 @@ #include -template -inline T ByteSwap(T value) +#ifdef __clang__ +#define _byte_swap16(value) __builtin_bswap16(static_cast(value)) +#define _byte_swap32(value) __builtin_bswap32(static_cast(value)) +#define _byte_swap64(value) __builtin_bswap64(static_cast(value)) +#elif defined(_MSC_VER) +#define _byte_swap16(value) _byteswap_ushort(static_cast(value)) +#define _byte_swap32(value) _byteswap_ulong(static_cast(value)) +#define _byte_swap64(value) _byteswap_uint64(static_cast(value)) +#endif + +template T ByteSwap(T value) { if constexpr (sizeof(T) == 1) return value; - else if constexpr (sizeof(T) == 2) - return static_cast(__builtin_bswap16(static_cast(value))); - else if constexpr (sizeof(T) == 4) - return static_cast(__builtin_bswap32(static_cast(value))); - else if constexpr (sizeof(T) == 8) - return static_cast(__builtin_bswap64(static_cast(value))); + if constexpr (sizeof(T) == 2) + return static_cast(_byte_swap16(value)); + if constexpr (sizeof(T) == 4) + return static_cast(_byte_swap32(value)); + if constexpr (sizeof(T) == 8) + return static_cast(_byte_swap64(value)); assert(false && "Unexpected byte size."); - return value; } -template -inline void ByteSwapInplace(T& value) +template void ByteSwapInplace(T& value) { value = ByteSwap(value); } diff --git a/XenonUtils/xex.cpp b/XenonUtils/xex.cpp index d1972c0..ac2a7d9 100644 --- a/XenonUtils/xex.cpp +++ b/XenonUtils/xex.cpp @@ -126,7 +126,8 @@ Image Xex2LoadImage(const uint8_t* data, size_t dataSize) { auto* header = reinterpret_cast(data); auto* security = reinterpret_cast(data + header->securityOffset); - const auto* fileFormatInfo = reinterpret_cast(getOptHeaderPtr(data, XEX_HEADER_FILE_FORMAT_INFO)); + const auto* fileFormatInfo = static_cast(getOptHeaderPtr(data, XEX_HEADER_FILE_FORMAT_INFO)); + const auto* execInfo = static_cast(getOptHeaderPtr(data, XEX_HEADER_EXECUTION_INFO)); Image image{}; std::unique_ptr result{}; @@ -147,7 +148,11 @@ Image Xex2LoadImage(const uint8_t* data, size_t dataSize) uint8_t decryptedKey[KeySize]; memcpy(decryptedKey, security->aesKey, KeySize); - AES_init_ctx_iv(&aesContext, Xex2RetailKey, AESBlankIV); + if (!execInfo || !execInfo->titleId) { + AES_init_ctx_iv(&aesContext, Xex2DevkitKey, AESBlankIV); + } else { + AES_init_ctx_iv(&aesContext, Xex2RetailKey, AESBlankIV); + } AES_CBC_decrypt_buffer(&aesContext, decryptedKey, KeySize); decryptedData = std::make_unique(dataSize - header->headerSize); diff --git a/XenonUtils/xex.h b/XenonUtils/xex.h index 9ab831e..4da99df 100644 --- a/XenonUtils/xex.h +++ b/XenonUtils/xex.h @@ -3,6 +3,7 @@ #include "xbox.h" inline constexpr uint8_t Xex2RetailKey[16] = { 0x20, 0xB1, 0x85, 0xA5, 0x9D, 0x28, 0xFD, 0xC3, 0x40, 0x58, 0x3F, 0xBB, 0x08, 0x96, 0xBF, 0x91 }; +inline constexpr uint8_t Xex2DevkitKey[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; inline constexpr uint8_t AESBlankIV[16] = {}; enum Xex2ModuleFlags @@ -186,6 +187,19 @@ struct Xex2OptFileFormatInfo be compressionType; }; +struct Xex2OptExecutionInfo +{ + be mediaId; + be version; + be versionBase; + be titleId; + uint8_t platform; + uint8_t executableTable; + uint8_t discNumber; + uint8_t discTotal; + be savedGameId; +}; + struct Xex2ImportHeader { be sizeOfHeader; @@ -204,10 +218,20 @@ struct Xex2ImportLibrary be numberOfImports; }; +// https://github.com/emoose/idaxex/blob/198b1d52414d35926644bbeec607b3feac5f44e7/formats/pe_structs.hpp#L140-L150 struct Xex2ImportDescriptor { - be firstThunk; // VA XEX_THUNK_DATA + union + { + be characteristics; + be originalFirstThunk; + }; + be timeDateStamp; + be forwarderChainId; + be moduleName; + be firstThunk; }; +static_assert(sizeof(Xex2ImportDescriptor) == 0x14, "Xex2ImportDescriptor"); struct Xex2ThunkData {