From b13aaed6d0a940934dcb26aa3cb28ffc0dd06c48 Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Wed, 18 Nov 2020 19:12:53 +0100 Subject: Fixed some variants of NP_Protect-ed maps --- src/SBaseCommon.cpp | 2 +- src/SBaseFileTable.cpp | 97 ++++++++++++++++++++++++++++-------------------- src/SFileOpenArchive.cpp | 5 ++- src/StormLib.h | 20 ++++++---- 4 files changed, 73 insertions(+), 51 deletions(-) (limited to 'src') diff --git a/src/SBaseCommon.cpp b/src/SBaseCommon.cpp index 34a7a25..97ebc59 100644 --- a/src/SBaseCommon.cpp +++ b/src/SBaseCommon.cpp @@ -962,7 +962,7 @@ void * LoadMpqTable( } } - // If everything succeeded, read the raw table form the MPQ + // If everything succeeded, read the raw table from the MPQ if(FileStream_Read(ha->pStream, &ByteOffset, pbToRead, dwBytesToRead)) { // First of all, decrypt the table diff --git a/src/SBaseFileTable.cpp b/src/SBaseFileTable.cpp index e08daef..af8d290 100644 --- a/src/SBaseFileTable.cpp +++ b/src/SBaseFileTable.cpp @@ -57,11 +57,11 @@ static DWORD GetNecessaryBitCount(ULONGLONG MaxValue) } //----------------------------------------------------------------------------- -// Implementation of the TStormBits struc +// Implementation of the TMPQBits struct -struct TStormBits +struct TMPQBits { - static TStormBits * Create(DWORD NumberOfBits, BYTE FillValue); + static TMPQBits * Create(DWORD NumberOfBits, BYTE FillValue); void GetBits(unsigned int nBitPosition, unsigned int nBitLength, void * pvBuffer, int nResultSize); void SetBits(unsigned int nBitPosition, unsigned int nBitLength, void * pvBuffer, int nResultSize); @@ -73,17 +73,17 @@ struct TStormBits BYTE Elements[1]; // Array of elements (variable length) }; -const USHORT TStormBits::SetBitsMask[] = {0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF}; +const USHORT TMPQBits::SetBitsMask[] = {0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF}; -TStormBits * TStormBits::Create( +TMPQBits * TMPQBits::Create( DWORD NumberOfBits, BYTE FillValue) { - TStormBits * pBitArray; - size_t nSize = sizeof(TStormBits) + (NumberOfBits + 7) / 8; + TMPQBits * pBitArray; + size_t nSize = sizeof(TMPQBits) + (NumberOfBits + 7) / 8; // Allocate the bit array - pBitArray = (TStormBits *)STORM_ALLOC(BYTE, nSize); + pBitArray = (TMPQBits *)STORM_ALLOC(BYTE, nSize); if(pBitArray != NULL) { memset(pBitArray, FillValue, nSize); @@ -94,7 +94,7 @@ TStormBits * TStormBits::Create( return pBitArray; } -void TStormBits::GetBits( +void TMPQBits::GetBits( unsigned int nBitPosition, unsigned int nBitLength, void * pvBuffer, @@ -159,7 +159,7 @@ void TStormBits::GetBits( } } -void TStormBits::SetBits( +void TMPQBits::SetBits( unsigned int nBitPosition, unsigned int nBitLength, void * pvBuffer, @@ -225,6 +225,11 @@ void TStormBits::SetBits( } } +void GetMPQBits(TMPQBits * pBits, unsigned int nBitPosition, unsigned int nBitLength, void * pvBuffer, int nResultByteSize) +{ + pBits->GetBits(nBitPosition, nBitLength, pvBuffer, nResultByteSize); +} + //----------------------------------------------------------------------------- // Support for MPQ header @@ -234,19 +239,22 @@ static bool VerifyTablePosition64( ULONGLONG TableSize, // Size of the MPQ table, in bytes ULONGLONG FileSize) // Size of the entire file, in bytes { - // Verify overflows - if((MpqOffset + TableOffset) < MpqOffset) - return false; - if((MpqOffset + TableOffset + TableSize) < MpqOffset) - return false; - - // Verify sizes - if(TableOffset >= FileSize || TableSize >= FileSize) - return false; - if((MpqOffset + TableOffset) >= FileSize) - return false; - if((MpqOffset + TableOffset + TableSize) >= FileSize) - return false; + if(TableOffset != 0) + { + // Verify overflows + if((MpqOffset + TableOffset) < MpqOffset) + return false; + if((MpqOffset + TableOffset + TableSize) < MpqOffset) + return false; + + // Verify sizes + if(TableOffset >= FileSize || TableSize >= FileSize) + return false; + if((MpqOffset + TableOffset) >= FileSize) + return false; + if((MpqOffset + TableOffset + TableSize) >= FileSize) + return false; + } return true; } @@ -333,10 +341,21 @@ static ULONGLONG DetermineArchiveSize_V4( // This could only be called for MPQs version 4 assert(pHeader->wFormatVersion == MPQ_FORMAT_VERSION_4); - // Determine the archive size as the greatest of all valid values - EndOfTable = pHeader->BetTablePos64 + pHeader->BetTableSize64; - if(EndOfTable > ArchiveSize) - ArchiveSize = EndOfTable; + // Check position of BET table, if correct + if((pHeader->BetTablePos64 >> 0x20) == 0 && (pHeader->BetTableSize64 >> 0x20) == 0) + { + EndOfTable = pHeader->BetTablePos64 + pHeader->BetTableSize64; + if(EndOfTable > ArchiveSize) + ArchiveSize = EndOfTable; + } + + // Check position of HET table, if correct + if((pHeader->HetTablePos64 >> 0x20) == 0 && (pHeader->HetTableSize64 >> 0x20) == 0) + { + EndOfTable = pHeader->HetTablePos64 + pHeader->HetTableSize64; + if(EndOfTable > ArchiveSize) + ArchiveSize = EndOfTable; + } EndOfTable = pHeader->dwHashTablePos + pHeader->dwHashTableSize * sizeof(TMPQHash); if(EndOfTable > ArchiveSize) @@ -346,10 +365,6 @@ static ULONGLONG DetermineArchiveSize_V4( if(EndOfTable > ArchiveSize) ArchiveSize = EndOfTable; - EndOfTable = pHeader->HetTablePos64 + pHeader->HetTableSize64; - if(EndOfTable > ArchiveSize) - ArchiveSize = EndOfTable; - // Return the calculated archive size return ArchiveSize; } @@ -628,6 +643,8 @@ int ConvertMpqHeaderToFormat4( return ERROR_FAKE_MPQ_HEADER; if(!VerifyTablePosition64(MpqOffset, pHeader->HiBlockTablePos64, pHeader->HiBlockTableSize64, FileSize)) return ERROR_FAKE_MPQ_HEADER; + if(!VerifyTablePosition64(MpqOffset, pHeader->HetTablePos64, pHeader->HetTableSize64, FileSize)) + return ERROR_FAKE_MPQ_HEADER; // Check for malformed MPQs if(pHeader->wFormatVersion != MPQ_FORMAT_VERSION_4 || (ha->MpqPos + pHeader->ArchiveSize64) != FileSize || (ha->MpqPos + pHeader->HiBlockTablePos64) >= FileSize) @@ -1332,7 +1349,7 @@ TMPQHetTable * CreateHetTable(DWORD dwEntryCount, DWORD dwTotalCount, DWORD dwNa memset(pHetTable->pNameHashes, 0, dwTotalCount); // Allocate the bit array for file indexes - pHetTable->pBetIndexes = TStormBits::Create(dwTotalCount * pHetTable->dwIndexSizeTotal, 0xFF); + pHetTable->pBetIndexes = TMPQBits::Create(dwTotalCount * pHetTable->dwIndexSizeTotal, 0xFF); if(pHetTable->pBetIndexes != NULL) { // Initialize the HET table from the source data (if given) @@ -1732,7 +1749,7 @@ static TMPQBetTable * TranslateBetTable( } // Load the bit-based file table - pBetTable->pFileTable = TStormBits::Create(pBetTable->dwTableEntrySize * pBetHeader->dwEntryCount, 0); + pBetTable->pFileTable = TMPQBits::Create(pBetTable->dwTableEntrySize * pBetHeader->dwEntryCount, 0); if(pBetTable->pFileTable != NULL) { LengthInBytes = (pBetTable->pFileTable->NumberOfBits + 7) / 8; @@ -1746,7 +1763,7 @@ static TMPQBetTable * TranslateBetTable( pBetTable->dwBitCount_NameHash2 = pBetHeader->dwBitCount_NameHash2; // Create and load the array of BET hashes - pBetTable->pNameHashes = TStormBits::Create(pBetTable->dwBitTotal_NameHash2 * pBetHeader->dwEntryCount, 0); + pBetTable->pNameHashes = TMPQBits::Create(pBetTable->dwBitTotal_NameHash2 * pBetHeader->dwEntryCount, 0); if(pBetTable->pNameHashes != NULL) { LengthInBytes = (pBetTable->pNameHashes->NumberOfBits + 7) / 8; @@ -1771,7 +1788,7 @@ TMPQExtHeader * TranslateBetTable( TMPQBetHeader BetHeader; TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize; TFileEntry * pFileEntry; - TStormBits * pBitArray = NULL; + TMPQBits * pBitArray = NULL; LPBYTE pbLinearTable = NULL; LPBYTE pbTrgData; DWORD LengthInBytes; @@ -1791,7 +1808,7 @@ TMPQExtHeader * TranslateBetTable( pbTrgData = (LPBYTE)(pBetHeader + 1); // Save the bit-based block table - pBitArray = TStormBits::Create(BetHeader.dwEntryCount * BetHeader.dwTableEntrySize, 0); + pBitArray = TMPQBits::Create(BetHeader.dwEntryCount * BetHeader.dwTableEntrySize, 0); if(pBitArray != NULL) { DWORD dwFlagIndex = 0; @@ -1846,7 +1863,7 @@ TMPQExtHeader * TranslateBetTable( } // Create bit array for name hashes - pBitArray = TStormBits::Create(BetHeader.dwBitTotal_NameHash2 * BetHeader.dwEntryCount, 0); + pBitArray = TMPQBits::Create(BetHeader.dwBitTotal_NameHash2 * BetHeader.dwEntryCount, 0); if(pBitArray != NULL) { DWORD dwFileIndex = 0; @@ -2376,7 +2393,7 @@ TMPQHetTable * LoadHetTable(TMPQArchive * ha) TMPQHeader * pHeader = ha->pHeader; // If the HET table position is not 0, we expect the table to be present - if(pHeader->HetTablePos64 != 0 && pHeader->HetTableSize64 != 0) + if(pHeader->HetTablePos64 && pHeader->HetTableSize64) { // Attempt to load the HET table (Hash Extended Table) pExtTable = LoadExtTable(ha, pHeader->HetTablePos64, (size_t)pHeader->HetTableSize64, HET_TABLE_SIGNATURE, MPQ_KEY_HASH_TABLE); @@ -2398,7 +2415,7 @@ TMPQBetTable * LoadBetTable(TMPQArchive * ha) TMPQHeader * pHeader = ha->pHeader; // If the BET table position is not 0, we expect the table to be present - if(pHeader->BetTablePos64 != 0 && pHeader->BetTableSize64 != 0) + if(pHeader->BetTablePos64 && pHeader->BetTableSize64) { // Attempt to load the HET table (Hash Extended Table) pExtTable = LoadExtTable(ha, pHeader->BetTablePos64, (size_t)pHeader->BetTableSize64, BET_TABLE_SIGNATURE, MPQ_KEY_BLOCK_TABLE); @@ -2518,7 +2535,7 @@ static int BuildFileTable_HetBet(TMPQArchive * ha) TMPQHetTable * pHetTable = ha->pHetTable; TMPQBetTable * pBetTable; TFileEntry * pFileEntry = ha->pFileTable; - TStormBits * pBitArray; + TMPQBits * pBitArray; DWORD dwBitPosition = 0; DWORD i; int nError = ERROR_FILE_CORRUPT; diff --git a/src/SFileOpenArchive.cpp b/src/SFileOpenArchive.cpp index 2020e56..d1cc4d6 100644 --- a/src/SFileOpenArchive.cpp +++ b/src/SFileOpenArchive.cpp @@ -5,7 +5,7 @@ /* E-mail : ladik@zezula.net */ /* WWW : www.zezula.net */ /*---------------------------------------------------------------------------*/ -/* Archive functions of Storm.dll */ +/* Implementation of archive functions */ /*---------------------------------------------------------------------------*/ /* Date Ver Who Comment */ /* -------- ---- --- ------- */ @@ -100,6 +100,7 @@ static int VerifyMpqTablePositions(TMPQArchive * ha, ULONGLONG FileSize) { TMPQHeader * pHeader = ha->pHeader; ULONGLONG ByteOffset; + //bool bMalformed = (ha->dwFlags & MPQ_FLAG_MALFORMED) ? true : false; // Check the begin of HET table if(pHeader->HetTablePos64) @@ -298,7 +299,7 @@ bool WINAPI SFileOpenArchive( // If there is the MPQ user data, process it // Note that Warcraft III does not check for user data, which is abused by many map protectors dwHeaderID = BSWAP_INT32_UNSIGNED(ha->HeaderData[0]); - if(MapType == MapTypeNotRecognized && (dwFlags & MPQ_OPEN_FORCE_MPQ_V1) == 0) + if(MapType != MapTypeWarcraft3 && (dwFlags & MPQ_OPEN_FORCE_MPQ_V1) == 0) { if(ha->pUserData == NULL && dwHeaderID == ID_MPQ_USERDATA) { diff --git a/src/StormLib.h b/src/StormLib.h index 4f19772..d913a54 100644 --- a/src/StormLib.h +++ b/src/StormLib.h @@ -480,7 +480,7 @@ typedef void (WINAPI * SFILE_ADDFILE_CALLBACK)(void * pvUserData, DWORD dwBytesW typedef void (WINAPI * SFILE_COMPACT_CALLBACK)(void * pvUserData, DWORD dwWorkType, ULONGLONG BytesProcessed, ULONGLONG TotalBytes); struct TFileStream; -struct TStormBits; +struct TMPQBits; //----------------------------------------------------------------------------- // Structures related to MPQ format @@ -748,7 +748,7 @@ typedef struct _TMPQBetHeader // Structure for parsed HET table typedef struct _TMPQHetTable { - TStormBits * pBetIndexes; // Bit array of FileIndex values + TMPQBits * pBetIndexes; // Bit array of FileIndex values LPBYTE pNameHashes; // Array of NameHash1 values (NameHash1 = upper 8 bits of FileName hashe) ULONGLONG AndMask64; // AND mask used for calculating file name hash ULONGLONG OrMask64; // OR mask used for setting the highest bit of the file name hash @@ -764,8 +764,8 @@ typedef struct _TMPQHetTable // Structure for parsed BET table typedef struct _TMPQBetTable { - TStormBits * pNameHashes; // Array of NameHash2 entries (lower 24 bits of FileName hash) - TStormBits * pFileTable; // Bit-based file table + TMPQBits * pNameHashes; // Array of NameHash2 entries (lower 24 bits of FileName hash) + TMPQBits * pFileTable; // Bit-based file table LPDWORD pFileFlags; // Array of file flags DWORD dwTableEntrySize; // Size of one table entry, in bits @@ -924,11 +924,16 @@ typedef struct _SFILE_CREATE_MPQ } SFILE_CREATE_MPQ, *PSFILE_CREATE_MPQ; +//----------------------------------------------------------------------------- +// TMPQBits support - functions + +void GetMPQBits(TMPQBits * pBits, unsigned int nBitPosition, unsigned int nBitLength, void * pvBuffer, int nResultByteSize); + //----------------------------------------------------------------------------- // Stream support - functions // Structure used by FileStream_GetBitmap -typedef struct _TStreamBitmap +struct TStreamBitmap { ULONGLONG StreamSize; // Size of the stream, in bytes DWORD BitmapSize; // Size of the block map, in bytes @@ -937,8 +942,7 @@ typedef struct _TStreamBitmap DWORD IsComplete; // Nonzero if the file is complete // Followed by the BYTE array, each bit means availability of one block - -} TStreamBitmap; +}; // UNICODE versions of the file access functions TFileStream * FileStream_CreateFile(const TCHAR * szFileName, DWORD dwStreamFlags); @@ -948,7 +952,7 @@ size_t FileStream_Prefix(const TCHAR * szFileName, DWORD * pdwProvider); bool FileStream_SetCallback(TFileStream * pStream, SFILE_DOWNLOAD_CALLBACK pfnCallback, void * pvUserData); -bool FileStream_GetBitmap(TFileStream * pStream, void * pvBitmap, DWORD cbBitmap, LPDWORD pcbLengthNeeded); +bool FileStream_GetBitmap(TFileStream * pStream, void * pvBitmap, DWORD cbBitmap, DWORD * pcbLengthNeeded); bool FileStream_Read(TFileStream * pStream, ULONGLONG * pByteOffset, void * pvBuffer, DWORD dwBytesToRead); bool FileStream_Write(TFileStream * pStream, ULONGLONG * pByteOffset, const void * pvBuffer, DWORD dwBytesToWrite); bool FileStream_SetSize(TFileStream * pStream, ULONGLONG NewFileSize); -- cgit v1.2.3