+ Updated for protectors fiddling with too big block table index

This commit is contained in:
Ladislav Zezula
2016-06-18 20:32:15 +02:00
parent 47b6b6eb4a
commit 303631f9d7
8 changed files with 36 additions and 43 deletions

View File

@@ -581,11 +581,9 @@ int ConvertMpqHeaderToFormat4(
// Hash entry verification when the file table does not exist yet
bool IsValidHashEntry(TMPQArchive * ha, TMPQHash * pHash)
{
TFileEntry * pFileEntry = ha->pFileTable + MPQ_BLOCK_INDEX(pHash->dwBlockIndex);
DWORD dwBlockIndex = MPQ_BLOCK_INDEX(pHash->dwBlockIndex);
TFileEntry * pFileEntry = ha->pFileTable + MPQ_BLOCK_INDEX(pHash);
pFileEntry = ha->pFileTable + dwBlockIndex;
return ((dwBlockIndex < ha->dwFileTableSize) && (pFileEntry->dwFlags & MPQ_FILE_EXISTS)) ? true : false;
return ((MPQ_BLOCK_INDEX(pHash) < ha->dwFileTableSize) && (pFileEntry->dwFlags & MPQ_FILE_EXISTS)) ? true : false;
}
// Hash entry verification when the file table does not exist yet
@@ -593,20 +591,12 @@ static bool IsValidHashEntry1(TMPQArchive * ha, TMPQHash * pHash, TMPQBlock * pB
{
ULONGLONG ByteOffset;
TMPQBlock * pBlock;
DWORD dwBlockIndex;
// We need to mask out the upper 4 bits of the block table index.
// This is because it gets shifted out when calculating block table offset
// BlockTableOffset = pHash->dwBlockIndex * 0x10
// Malformed MPQ maps may contain invalid entries
// Note that Storm.dll does not perfom this check
dwBlockIndex = MPQ_BLOCK_INDEX(pHash->dwBlockIndex);
// The block index is considered valid if it's less than block table size
if(dwBlockIndex < ha->pHeader->dwBlockTableSize)
if(MPQ_BLOCK_INDEX(pHash) < ha->pHeader->dwBlockTableSize)
{
// Calculate the block table position
pBlock = pBlockTable + dwBlockIndex;
pBlock = pBlockTable + MPQ_BLOCK_INDEX(pHash);
// Check whether this is an existing file
// Also we do not allow to be file size greater than 2GB
@@ -787,28 +777,28 @@ static int BuildFileTableFromBlockTable(
// - Multiple hash entries (different file name) point to the same block entry
//
// Ignore all hash table entries where:
// - dwBlockIndex >= BlockTableSize
// - Block Index >= BlockTableSize
// - Flags of the appropriate block table entry
//
if(IsValidHashEntry1(ha, pHash, pBlockTable))
{
DWORD dwBlockIndex = MPQ_BLOCK_INDEX(pHash->dwBlockIndex);
DWORD dwNewIndex = MPQ_BLOCK_INDEX(pHash->dwBlockIndex);
DWORD dwOldIndex = MPQ_BLOCK_INDEX(pHash);
DWORD dwNewIndex = MPQ_BLOCK_INDEX(pHash);
// Determine the new block index
if(DefragmentTable != NULL)
{
// Need to handle case when multiple hash
// entries point to the same block entry
if(DefragmentTable[dwBlockIndex] == HASH_ENTRY_FREE)
if(DefragmentTable[dwOldIndex] == HASH_ENTRY_FREE)
{
DefragmentTable[dwBlockIndex] = dwItemCount;
DefragmentTable[dwOldIndex] = dwItemCount;
dwNewIndex = dwItemCount++;
}
else
{
dwNewIndex = DefragmentTable[dwBlockIndex];
dwNewIndex = DefragmentTable[dwOldIndex];
}
// Fix the pointer in the hash entry
@@ -820,7 +810,7 @@ static int BuildFileTableFromBlockTable(
// Get the pointer to the file entry and the block entry
pFileEntry = ha->pFileTable + dwNewIndex;
pBlock = pBlockTable + dwBlockIndex;
pBlock = pBlockTable + dwOldIndex;
// ByteOffset is only valid if file size is not zero
pFileEntry->ByteOffset = pBlock->dwFilePos;
@@ -1814,11 +1804,11 @@ TFileEntry * GetFileEntryLocale2(TMPQArchive * ha, const char * szFileName, LCID
if(ha->pHashTable != NULL)
{
pHash = GetHashEntryLocale(ha, szFileName, lcLocale);
if(pHash != NULL && pHash->dwBlockIndex < ha->dwFileTableSize)
if(pHash != NULL && MPQ_BLOCK_INDEX(pHash) < ha->dwFileTableSize)
{
if(PtrHashIndex != NULL)
PtrHashIndex[0] = (DWORD)(pHash - ha->pHashTable);
return ha->pFileTable + pHash->dwBlockIndex;
return ha->pFileTable + MPQ_BLOCK_INDEX(pHash);
}
}
@@ -1848,11 +1838,11 @@ TFileEntry * GetFileEntryExact(TMPQArchive * ha, const char * szFileName, LCID l
if(ha->pHashTable != NULL)
{
pHash = GetHashEntryExact(ha, szFileName, lcLocale);
if(pHash != NULL && pHash->dwBlockIndex < ha->dwFileTableSize)
if(pHash != NULL && MPQ_BLOCK_INDEX(pHash) < ha->dwFileTableSize)
{
if(PtrHashIndex != NULL)
PtrHashIndex[0] = (DWORD)(pHash - ha->pHashTable);
return ha->pFileTable + pHash->dwBlockIndex;
return ha->pFileTable + MPQ_BLOCK_INDEX(pHash);
}
}
@@ -2640,11 +2630,11 @@ int DefragmentFileTable(TMPQArchive * ha)
for(pHash = ha->pHashTable; pHash < pHashTableEnd; pHash++)
{
if(pHash->dwBlockIndex < ha->dwFileTableSize)
if(MPQ_BLOCK_INDEX(pHash) < ha->dwFileTableSize)
{
// If that block entry is there, set it to the hash entry
// If not, set it as DELETED
dwNewBlockIndex = DefragmentTable[pHash->dwBlockIndex];
dwNewBlockIndex = DefragmentTable[MPQ_BLOCK_INDEX(pHash)];
pHash->dwBlockIndex = (dwNewBlockIndex != HASH_ENTRY_FREE) ? dwNewBlockIndex : HASH_ENTRY_DELETED;
}
}
@@ -2753,7 +2743,7 @@ int RebuildFileTable(TMPQArchive * ha, DWORD dwNewHashTableSize)
{
if(IsValidHashEntry(ha, pHash))
{
pFileEntry = ha->pFileTable + pHash->dwBlockIndex;
pFileEntry = ha->pFileTable + MPQ_BLOCK_INDEX(pHash);
AllocateHashEntry(ha, pFileEntry, pHash->lcLocale);
}
}