mirror of
				https://github.com/hedge-dev/XenonRecomp.git
				synced 2025-10-30 07:11:38 +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:
		
							parent
							
								
									0bfeaed44a
								
							
						
					
					
						commit
						49c5e3b4f5
					
				
					 3 changed files with 123 additions and 2 deletions
				
			
		|  | @ -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 { | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 The Spicy Chef
						The Spicy Chef