From 5903b40f960965bec5846bdba6d180e09fe3dde6 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Fri, 2 Dec 2022 22:14:46 +0100 Subject: [PATCH] Implement LZHAM compression for the signature cache map --- r5dev/public/utility/sigcache.cpp | 115 +++++++++++++++++++++++++----- r5dev/public/utility/sigcache.h | 21 +++++- 2 files changed, 115 insertions(+), 21 deletions(-) diff --git a/r5dev/public/utility/sigcache.cpp b/r5dev/public/utility/sigcache.cpp index 7e0793ee..27ee0318 100644 --- a/r5dev/public/utility/sigcache.cpp +++ b/r5dev/public/utility/sigcache.cpp @@ -5,7 +5,7 @@ //===========================================================================// #include "core/stdafx.h" #include "public/utility/binstream.h" -#include "sigcache.h" +#include "public/utility/sigcache.h" //----------------------------------------------------------------------------- // Purpose: creates a pair of a pattern (key) and relative virtual address (value) @@ -59,30 +59,44 @@ bool CSigCache::LoadCache(const string& svCacheFile) return false; } - SigDBHeader_t sigDbHeader; - sigDbHeader.m_nMagic = reader.Read(); + SigDBHeader_t header; + header.m_nMagic = reader.Read(); - if (sigDbHeader.m_nMagic != SIGDB_MAGIC) + if (header.m_nMagic != SIGDB_MAGIC) { return false; } - sigDbHeader.m_nVersion = reader.Read(); - if (sigDbHeader.m_nVersion != SIGDB_VERSION) + header.m_nMajorVersion = reader.Read(); + if (header.m_nMajorVersion != SIGDB_MAJOR_VERSION) { return false; } - sigDbHeader.m_FileTime = reader.Read(); + header.m_nMinorVersion = reader.Read(); + if (header.m_nMinorVersion != SIGDB_MINOR_VERSION) + { + return false; + } - vector vData; - size_t nSize = (static_cast(reader.GetSize()) - sizeof(SigDBHeader_t)); + header.m_nBlobSizeMem = reader.Read(); + header.m_nBlobSizeDisk = reader.Read(); + header.m_nBlobHash = reader.Read(); - vData.resize(nSize); - uint8_t* pBuf = vData.data(); - reader.Read(*pBuf, nSize); + uint32_t nCrc32; - if (!m_Cache.ParseFromArray(pBuf, nSize)) + std::unique_ptr pSrcBuf(new uint8_t[header.m_nBlobSizeDisk]); + std::unique_ptr pDstBuf(new uint8_t[header.m_nBlobSizeMem]); + + reader.Read(*pSrcBuf.get(), header.m_nBlobSizeDisk); + DecompressBlob(header.m_nBlobSizeDisk, header.m_nBlobSizeMem, nCrc32, pSrcBuf.get(), pDstBuf.get()); + + if (header.m_nBlobHash != nCrc32) + { + return false; + } + + if (!m_Cache.ParseFromArray(pDstBuf.get(), header.m_nBlobSizeMem)) { return false; } @@ -106,19 +120,84 @@ bool CSigCache::WriteCache(const string& svCacheFile) CIOStream writer(svCacheFile, CIOStream::Mode_t::WRITE); if (!writer.IsWritable()) { - // Error message.. + Error(eDLL_T::COMMON, NO_ERROR, "Failed to write cache file: (read-only?)\n"); return false; } SigDBHeader_t header; - header.m_nMagic = SIGDB_MAGIC; - header.m_nVersion = SIGDB_VERSION; - GetSystemTimeAsFileTime(&header.m_FileTime); + header.m_nMajorVersion = SIGDB_MAJOR_VERSION; + header.m_nMinorVersion = SIGDB_MINOR_VERSION; + const string svBuffer = m_Cache.SerializeAsString(); + std::unique_ptr pBuffer(new uint8_t[svBuffer.size()]); + + header.m_nBlobSizeMem = svBuffer.size(); + uint64_t nCompSize = svBuffer.size(); + + if (!CompressBlob(svBuffer.size(), nCompSize, header.m_nBlobHash, reinterpret_cast(svBuffer.data()), pBuffer.get())) + { + return false; + } + + header.m_nBlobSizeDisk = nCompSize; writer.Write(header); - writer.Write(svBuffer.data(), svBuffer.size()); + writer.Write(pBuffer.get(), nCompSize); + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: decompresses the blob containing the signature map +// Input : nSrcLen - +// &nDstSize - +// &nCrc32 - +// *pSrcBuf - +// *pDstBuf - +// Output : true on success, false otherwise +//----------------------------------------------------------------------------- +bool CSigCache::DecompressBlob(size_t nSrcLen, size_t& nDstLen, uint32_t& nCrc32, const uint8_t* pSrcBuf, uint8_t* pDstBuf) const +{ + lzham_decompress_params lzDecompParams{}; + lzDecompParams.m_dict_size_log2 = SIGDB_DICT_SIZE; + lzDecompParams.m_decompress_flags = lzham_decompress_flags::LZHAM_DECOMP_FLAG_OUTPUT_UNBUFFERED | lzham_decompress_flags::LZHAM_DECOMP_FLAG_COMPUTE_CRC32; + lzDecompParams.m_struct_size = sizeof(lzham_decompress_params); + + lzham_decompress_status_t lzDecompStatus = lzham_decompress_memory(&lzDecompParams, pDstBuf, &nDstLen, pSrcBuf, nSrcLen, NULL, &nCrc32); + + if (lzDecompStatus != lzham_decompress_status_t::LZHAM_DECOMP_STATUS_SUCCESS) + { + Error(eDLL_T::COMMON, NO_ERROR, "Failed to decompress blob: status = %08x\n", lzDecompStatus); + return false; + } + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: compresses the blob containing the signature map +// Input : nSrcLen - +// &nDstSize - +// &nCrc32 - +// *pSrcBuf - +// *pDstBuf - +// Output : true on success, false otherwise +//----------------------------------------------------------------------------- +bool CSigCache::CompressBlob(size_t nSrcLen, size_t& nDstSize, uint32_t& nCrc32, const uint8_t* pSrcBuf, uint8_t* pDstBuf) const +{ + lzham_compress_params lzCompParams{}; + lzCompParams.m_dict_size_log2 = SIGDB_DICT_SIZE; + lzCompParams.m_level = lzham_compress_level::LZHAM_COMP_LEVEL_FASTEST; + lzCompParams.m_compress_flags = lzham_compress_flags::LZHAM_COMP_FLAG_DETERMINISTIC_PARSING; + + lzham_compress_status_t lzCompStatus = lzham_compress_memory(&lzCompParams, pDstBuf, &nDstSize, pSrcBuf, nSrcLen, NULL, &nCrc32); + + if (lzCompStatus != lzham_compress_status_t::LZHAM_COMP_STATUS_SUCCESS) + { + Warning(eDLL_T::COMMON, NO_ERROR, "Failed to compress blob: status = %08x\n", lzCompStatus); + return false; + } return true; } diff --git a/r5dev/public/utility/sigcache.h b/r5dev/public/utility/sigcache.h index 38a639b7..db5a189b 100644 --- a/r5dev/public/utility/sigcache.h +++ b/r5dev/public/utility/sigcache.h @@ -4,7 +4,10 @@ #include "protoc/sig_map.pb.h" #define SIGDB_MAGIC (('p'<<24)+('a'<<16)+('M'<<8)+'S') -#define SIGDB_VERSION 0x1 +#define SIGDB_DICT_SIZE 20 + +#define SIGDB_MAJOR_VERSION 0x1 // Increment when library changes are made. +#define SIGDB_MINOR_VERSION 0x1 // Increment when SDK updates are released. #ifdef DEDICATED #define SIGDB_FILE "cfg\\server\\startup.bin" @@ -15,21 +18,33 @@ class CSigCache { public: + CSigCache() { m_bInitialized = false; }; + ~CSigCache() {}; + void AddEntry(const string& svPattern, const uint64_t nRVA); bool FindEntry(const string& svPattern, uint64_t& nRVA) const; bool LoadCache(const string& svCacheFile); bool WriteCache(const string& svCacheFile); +private: + bool CompressBlob(size_t nSrcLen, size_t& nDstSize, uint32_t& nCrc32, const uint8_t* pSrcBuf, uint8_t* pDstBuf) const; + bool DecompressBlob(size_t nSrcLen, size_t& nDstSize, uint32_t& nCrc32, const uint8_t* pSrcBuf, uint8_t* pDstBuf) const; + SigMap_Pb m_Cache; bool m_bInitialized; }; +#pragma pack(push, 1) struct SigDBHeader_t { int m_nMagic; - int m_nVersion; - FILETIME m_FileTime; + uint16_t m_nMajorVersion; + uint16_t m_nMinorVersion; + uint64_t m_nBlobSizeMem; + uint64_t m_nBlobSizeDisk; + uint32_t m_nBlobHash; }; +#pragma pack(pop) #endif // !SIGCACHE_H