mirror of
				https://github.com/hedge-dev/XenonRecomp.git
				synced 2025-11-03 22:37:09 +00:00 
			
		
		
		
	Added handling of normal compression for patching xex files (#126)
* Added handling of normal compression for patching xex files * Added normal compression handling to XenonAnalyse * Swap calloc for unique_ptr, tidied up code layout
This commit is contained in:
		@@ -5,6 +5,8 @@
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include <aes.hpp>
 | 
			
		||||
#include <TinySHA1.hpp>
 | 
			
		||||
#include <xex_patcher.h>
 | 
			
		||||
 | 
			
		||||
#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<uint8_t[]> decryptedData;
 | 
			
		||||
        const uint8_t* srcData = nullptr;
 | 
			
		||||
@@ -192,6 +194,67 @@ Image Xex2LoadImage(const uint8_t* data, size_t dataSize)
 | 
			
		||||
                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;
 | 
			
		||||
 | 
			
		||||
            auto compressBuffer = std::make_unique<uint8_t[]>(exeLength);
 | 
			
		||||
            const uint8_t* p = NULL;
 | 
			
		||||
            uint8_t* d = NULL;
 | 
			
		||||
            sha1::SHA1 s;
 | 
			
		||||
 | 
			
		||||
            p = exeBuffer;
 | 
			
		||||
            d = compressBuffer.get();
 | 
			
		||||
 | 
			
		||||
            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)
 | 
			
		||||
                    return {};
 | 
			
		||||
 | 
			
		||||
                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;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            int resultCode = 0;
 | 
			
		||||
            uint32_t uncompressedSize = security->imageSize;
 | 
			
		||||
            uint8_t* buffer = destData;
 | 
			
		||||
 | 
			
		||||
            resultCode = lzxDecompress(compressBuffer.get(), d - compressBuffer.get(), buffer, uncompressedSize, ((const Xex2FileNormalCompressionInfo*)(fileFormatInfo + 1))->windowSize, nullptr, 0);
 | 
			
		||||
 | 
			
		||||
            if (resultCode)
 | 
			
		||||
                return {};
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    image.data = std::move(result);
 | 
			
		||||
 
 | 
			
		||||
@@ -403,7 +403,63 @@ XexPatcher::Result XexPatcher::apply(const uint8_t* xexBytes, size_t xexBytesSiz
 | 
			
		||||
            memmove(outDataCursor, srcDataCursor, blocks[i].dataSize);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else if (fileFormatInfo->compressionType == XEX_COMPRESSION_NORMAL || fileFormatInfo->compressionType == XEX_COMPRESSION_DELTA)
 | 
			
		||||
    else if (fileFormatInfo->compressionType == XEX_COMPRESSION_NORMAL)
 | 
			
		||||
    {
 | 
			
		||||
        const Xex2CompressedBlockInfo* blocks = &((const Xex2FileNormalCompressionInfo*)(fileFormatInfo + 1))->firstBlock;
 | 
			
		||||
        const uint32_t exeLength = xexBytesSize - xexHeader->headerSize.get();
 | 
			
		||||
        const uint8_t* exeBuffer = &outBytes[headerTargetSize];
 | 
			
		||||
 | 
			
		||||
        auto compressBuffer = std::make_unique<uint8_t[]>(exeLength);
 | 
			
		||||
        const uint8_t* p = NULL;
 | 
			
		||||
        uint8_t* d = NULL;
 | 
			
		||||
        sha1::SHA1 s;
 | 
			
		||||
 | 
			
		||||
        p = exeBuffer;
 | 
			
		||||
        d = compressBuffer.get();
 | 
			
		||||
 | 
			
		||||
        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)
 | 
			
		||||
                return Result::PatchFailed;
 | 
			
		||||
 | 
			
		||||
            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;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        int resultCode = 0;
 | 
			
		||||
        uint32_t uncompressedSize = originalSecurityInfo->imageSize;
 | 
			
		||||
        uint8_t* buffer = outBytes.data() + newXexHeaderSize;
 | 
			
		||||
 | 
			
		||||
        resultCode = lzxDecompress(compressBuffer.get(), d - compressBuffer.get(), buffer, uncompressedSize, ((const Xex2FileNormalCompressionInfo*)(fileFormatInfo + 1))->windowSize, nullptr, 0);
 | 
			
		||||
 | 
			
		||||
        if (resultCode)
 | 
			
		||||
            return Result::PatchFailed;
 | 
			
		||||
    }
 | 
			
		||||
    else if (fileFormatInfo->compressionType == XEX_COMPRESSION_DELTA)
 | 
			
		||||
    {
 | 
			
		||||
        return Result::XexFileUnsupported;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,8 @@
 | 
			
		||||
#include <span>
 | 
			
		||||
#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
 | 
			
		||||
{
 | 
			
		||||
    enum class Result {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user