Added normal compression handling to XenonAnalyse

This commit is contained in:
The Spicy Chef 2025-03-26 13:00:52 +00:00
parent 51ae35da02
commit fda7d86aec
3 changed files with 104 additions and 27 deletions

View file

@ -5,6 +5,8 @@
#include <vector> #include <vector>
#include <unordered_map> #include <unordered_map>
#include <aes.hpp> #include <aes.hpp>
#include <TinySHA1.hpp>
#include <xex_patcher.h>
#define STRINGIFY(X) #X #define STRINGIFY(X) #X
#define XE_EXPORT(MODULE, ORDINAL, NAME, TYPE) { (ORDINAL), "__imp__" STRINGIFY(NAME) } #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 // Decompress image
if (fileFormatInfo != nullptr) if (fileFormatInfo != nullptr)
{ {
assert(fileFormatInfo->compressionType <= XEX_COMPRESSION_BASIC); assert(fileFormatInfo->compressionType <= XEX_COMPRESSION_NORMAL);
std::unique_ptr<uint8_t[]> decryptedData; std::unique_ptr<uint8_t[]> decryptedData;
const uint8_t* srcData = nullptr; const uint8_t* srcData = nullptr;
@ -192,6 +194,79 @@ Image Xex2LoadImage(const uint8_t* data, size_t dataSize)
destData += blocks[i].zeroSize; destData += blocks[i].zeroSize;
} }
} }
else if (fileFormatInfo->compressionType == XEX_COMPRESSION_NORMAL)
{
result = std::make_unique<uint8_t[]>(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); image.data = std::move(result);

View file

@ -406,32 +406,32 @@ XexPatcher::Result XexPatcher::apply(const uint8_t* xexBytes, size_t xexBytesSiz
else if (fileFormatInfo->compressionType == XEX_COMPRESSION_NORMAL) else if (fileFormatInfo->compressionType == XEX_COMPRESSION_NORMAL)
{ {
const Xex2CompressedBlockInfo* blocks = &((const Xex2FileNormalCompressionInfo*)(fileFormatInfo + 1))->firstBlock; const Xex2CompressedBlockInfo* blocks = &((const Xex2FileNormalCompressionInfo*)(fileFormatInfo + 1))->firstBlock;
const uint32_t exe_length = xexBytesSize - xexHeader->headerSize.get(); const uint32_t exeLength = xexBytesSize - xexHeader->headerSize.get();
const uint8_t* exe_buffer = &outBytes[headerTargetSize]; const uint8_t* exeBuffer = &outBytes[headerTargetSize];
uint8_t* compress_buffer = NULL; uint8_t* compressBuffer = NULL;
const uint8_t* p = NULL; const uint8_t* p = NULL;
uint8_t* d = NULL; uint8_t* d = NULL;
sha1::SHA1 s; sha1::SHA1 s;
compress_buffer = (uint8_t*)calloc(1, exe_length); compressBuffer = (uint8_t*)calloc(1, exeLength);
p = exe_buffer; p = exeBuffer;
d = compress_buffer; d = compressBuffer;
int result_code = 0; int resultCode = 0;
uint8_t block_calced_digest[0x14]; uint8_t blockCalcedDigest[0x14];
while (blocks->blockSize) { while (blocks->blockSize) {
const uint8_t* pnext = p + blocks->blockSize; const uint8_t* pNext = p + blocks->blockSize;
const auto* next_block = (const Xex2CompressedBlockInfo*)p; const auto* nextBlock = (const Xex2CompressedBlockInfo*)p;
s.reset(); s.reset();
s.processBytes(p, blocks->blockSize); s.processBytes(p, blocks->blockSize);
s.finalize(block_calced_digest); s.finalize(blockCalcedDigest);
if (memcmp(block_calced_digest, blocks->blockHash, 0x14) != 0) { if (memcmp(blockCalcedDigest, blocks->blockHash, 0x14) != 0) {
result_code = 2; resultCode = 2;
break; break;
} }
@ -439,32 +439,32 @@ XexPatcher::Result XexPatcher::apply(const uint8_t* xexBytes, size_t xexBytesSiz
p += 20; p += 20;
while (true) { while (true) {
const size_t chunk_size = (p[0] << 8) | p[1]; const size_t chunkSize = (p[0] << 8) | p[1];
p += 2; p += 2;
if (!chunk_size) { if (!chunkSize) {
break; break;
} }
memcpy(d, p, chunk_size); memcpy(d, p, chunkSize);
p += chunk_size; p += chunkSize;
d += chunk_size; d += chunkSize;
} }
p = pnext; p = pNext;
blocks = next_block; blocks = nextBlock;
} }
if (!result_code) if (!resultCode)
{ {
uint32_t uncompressed_size = originalSecurityInfo->imageSize; uint32_t uncompressedSize = originalSecurityInfo->imageSize;
uint8_t* buffer = outBytes.data() + newXexHeaderSize; 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) if (compressBuffer)
free((void*)compress_buffer); free((void*)compressBuffer);
if (result_code) if (resultCode)
return Result::PatchFailed; return Result::PatchFailed;
} }
else if (fileFormatInfo->compressionType == XEX_COMPRESSION_DELTA) else if (fileFormatInfo->compressionType == XEX_COMPRESSION_DELTA)

View file

@ -16,6 +16,8 @@
#include <span> #include <span>
#include <vector> #include <vector>
extern int lzxDecompress(const void* lzxData, size_t lzxLength, void* dst, size_t dstLength, uint32_t windowSize, void* windowData, size_t windowDataLength);
struct XexPatcher struct XexPatcher
{ {
enum class Result { enum class Result {