From fda7d86aec5d709e4de57d2a45cbeae26a99cf4d Mon Sep 17 00:00:00 2001 From: The Spicy Chef Date: Wed, 26 Mar 2025 13:00:52 +0000 Subject: [PATCH] Added normal compression handling to XenonAnalyse --- XenonUtils/xex.cpp | 77 +++++++++++++++++++++++++++++++++++++- XenonUtils/xex_patcher.cpp | 52 ++++++++++++------------- XenonUtils/xex_patcher.h | 2 + 3 files changed, 104 insertions(+), 27 deletions(-) diff --git a/XenonUtils/xex.cpp b/XenonUtils/xex.cpp index d1972c0..284edae 100644 --- a/XenonUtils/xex.cpp +++ b/XenonUtils/xex.cpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include #define STRINGIFY(X) #X #define XE_EXPORT(MODULE, ORDINAL, NAME, TYPE) { (ORDINAL), "__imp__" STRINGIFY(NAME) } @@ -135,7 +137,7 @@ Image Xex2LoadImage(const uint8_t* data, size_t dataSize) // Decompress image if (fileFormatInfo != nullptr) { - assert(fileFormatInfo->compressionType <= XEX_COMPRESSION_BASIC); + assert(fileFormatInfo->compressionType <= XEX_COMPRESSION_NORMAL); std::unique_ptr decryptedData; const uint8_t* srcData = nullptr; @@ -192,6 +194,79 @@ Image Xex2LoadImage(const uint8_t* data, size_t dataSize) destData += blocks[i].zeroSize; } } + else if (fileFormatInfo->compressionType == XEX_COMPRESSION_NORMAL) + { + result = std::make_unique(imageSize); + auto* destData = result.get(); + + const Xex2CompressedBlockInfo* blocks = &((const Xex2FileNormalCompressionInfo*)(fileFormatInfo + 1))->firstBlock; + const uint32_t headerSize = header->headerSize.get(); + + const uint32_t exeLength = dataSize - headerSize; + const uint8_t* exeBuffer = srcData; + + uint8_t* compressBuffer = NULL; + const uint8_t* p = NULL; + uint8_t* d = NULL; + sha1::SHA1 s; + + compressBuffer = (uint8_t*)calloc(1, exeLength); + + p = exeBuffer; + d = compressBuffer; + + int resultCode = 0; + + uint8_t blockCalcedDigest[0x14]; + while (blocks->blockSize) { + const uint8_t* pNext = p + blocks->blockSize; + const auto* nextBlock = (const Xex2CompressedBlockInfo*)p; + + s.reset(); + s.processBytes(p, blocks->blockSize); + s.finalize(blockCalcedDigest); + + if (memcmp(blockCalcedDigest, blocks->blockHash, 0x14) != 0) { + resultCode = 2; + break; + } + + p += 4; + p += 20; + + while (true) { + const size_t chunkSize = (p[0] << 8) | p[1]; + p += 2; + if (!chunkSize) { + break; + } + + memcpy(d, p, chunkSize); + p += chunkSize; + d += chunkSize; + } + + p = pNext; + blocks = nextBlock; + } + + if (!resultCode) + { + uint32_t uncompressedSize = security->imageSize; + uint8_t* buffer = destData; + + resultCode = lzxDecompress(compressBuffer, d - compressBuffer, buffer, uncompressedSize, ((const Xex2FileNormalCompressionInfo*)(fileFormatInfo + 1))->windowSize, nullptr, 0); + } + + if (compressBuffer) + free((void*)compressBuffer); + + if (resultCode) + { + return {}; + } + + } } image.data = std::move(result); diff --git a/XenonUtils/xex_patcher.cpp b/XenonUtils/xex_patcher.cpp index 7fc7e9b..3b648ea 100644 --- a/XenonUtils/xex_patcher.cpp +++ b/XenonUtils/xex_patcher.cpp @@ -406,32 +406,32 @@ XexPatcher::Result XexPatcher::apply(const uint8_t* xexBytes, size_t xexBytesSiz else if (fileFormatInfo->compressionType == XEX_COMPRESSION_NORMAL) { const Xex2CompressedBlockInfo* blocks = &((const Xex2FileNormalCompressionInfo*)(fileFormatInfo + 1))->firstBlock; - const uint32_t exe_length = xexBytesSize - xexHeader->headerSize.get(); - const uint8_t* exe_buffer = &outBytes[headerTargetSize]; + const uint32_t exeLength = xexBytesSize - xexHeader->headerSize.get(); + const uint8_t* exeBuffer = &outBytes[headerTargetSize]; - uint8_t* compress_buffer = NULL; + uint8_t* compressBuffer = NULL; const uint8_t* p = NULL; uint8_t* d = NULL; sha1::SHA1 s; - compress_buffer = (uint8_t*)calloc(1, exe_length); + compressBuffer = (uint8_t*)calloc(1, exeLength); - p = exe_buffer; - d = compress_buffer; + p = exeBuffer; + d = compressBuffer; - int result_code = 0; + int resultCode = 0; - uint8_t block_calced_digest[0x14]; + uint8_t blockCalcedDigest[0x14]; while (blocks->blockSize) { - const uint8_t* pnext = p + blocks->blockSize; - const auto* next_block = (const Xex2CompressedBlockInfo*)p; + const uint8_t* pNext = p + blocks->blockSize; + const auto* nextBlock = (const Xex2CompressedBlockInfo*)p; s.reset(); s.processBytes(p, blocks->blockSize); - s.finalize(block_calced_digest); + s.finalize(blockCalcedDigest); - if (memcmp(block_calced_digest, blocks->blockHash, 0x14) != 0) { - result_code = 2; + if (memcmp(blockCalcedDigest, blocks->blockHash, 0x14) != 0) { + resultCode = 2; break; } @@ -439,32 +439,32 @@ XexPatcher::Result XexPatcher::apply(const uint8_t* xexBytes, size_t xexBytesSiz p += 20; while (true) { - const size_t chunk_size = (p[0] << 8) | p[1]; + const size_t chunkSize = (p[0] << 8) | p[1]; p += 2; - if (!chunk_size) { + if (!chunkSize) { break; } - memcpy(d, p, chunk_size); - p += chunk_size; - d += chunk_size; + memcpy(d, p, chunkSize); + p += chunkSize; + d += chunkSize; } - p = pnext; - blocks = next_block; + p = pNext; + blocks = nextBlock; } - if (!result_code) + if (!resultCode) { - uint32_t uncompressed_size = originalSecurityInfo->imageSize; + uint32_t uncompressedSize = originalSecurityInfo->imageSize; uint8_t* buffer = outBytes.data() + newXexHeaderSize; - result_code = lzxDecompress(compress_buffer, d - compress_buffer, buffer, uncompressed_size, ((const Xex2FileNormalCompressionInfo*)(fileFormatInfo + 1))->windowSize, nullptr, 0); + resultCode = lzxDecompress(compressBuffer, d - compressBuffer, buffer, uncompressedSize, ((const Xex2FileNormalCompressionInfo*)(fileFormatInfo + 1))->windowSize, nullptr, 0); } - if (compress_buffer) - free((void*)compress_buffer); + if (compressBuffer) + free((void*)compressBuffer); - if (result_code) + if (resultCode) return Result::PatchFailed; } else if (fileFormatInfo->compressionType == XEX_COMPRESSION_DELTA) diff --git a/XenonUtils/xex_patcher.h b/XenonUtils/xex_patcher.h index b8c5728..44b2bf0 100644 --- a/XenonUtils/xex_patcher.h +++ b/XenonUtils/xex_patcher.h @@ -16,6 +16,8 @@ #include #include +extern int lzxDecompress(const void* lzxData, size_t lzxLength, void* dst, size_t dstLength, uint32_t windowSize, void* windowData, size_t windowDataLength); + struct XexPatcher { enum class Result {