aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLadislav Zezula <zezula@volny.cz>2023-06-06 09:54:12 +0200
committerGitHub <noreply@github.com>2023-06-06 09:54:12 +0200
commit51ba11c5b78752852023fd6156cd8842c1c3e336 (patch)
tree161b1c1622d5d43e333bd73272173f83cc6e910e /src
parent1e436d61fe963d58235af5b898f0e70a18bbb550 (diff)
parentafd304b180607a68edc1613074eeaca5e8805153 (diff)
Merge pull request #294 from ladislav-zezula/LZ_MemoryCorruption
Fixed loading of corrupt MPQ version 2
Diffstat (limited to 'src')
-rw-r--r--src/SBaseFileTable.cpp58
1 files changed, 42 insertions, 16 deletions
diff --git a/src/SBaseFileTable.cpp b/src/SBaseFileTable.cpp
index 43202d0..20d7cc4 100644
--- a/src/SBaseFileTable.cpp
+++ b/src/SBaseFileTable.cpp
@@ -317,29 +317,54 @@ static ULONGLONG DetermineArchiveSize_V2(
ULONGLONG MpqOffset,
ULONGLONG FileSize)
{
- ULONGLONG EndOfMpq = FileSize;
- DWORD dwArchiveSize32;
+ ULONGLONG TableOffset;
+ ULONGLONG TableSize;
+ ULONGLONG MaxOffset = 0;
// This could only be called for MPQs version 2.0
assert(pHeader->wFormatVersion == MPQ_FORMAT_VERSION_2);
- // Check if we can rely on the archive size in the header
- if((FileSize >> 0x20) == 0)
+ // Is the hash table end greater than max offset?
+ TableOffset = MAKE_OFFSET64(pHeader->wHashTablePosHi, pHeader->dwHashTablePos);
+ TableSize = (ULONGLONG)pHeader->dwHashTableSize * sizeof(TMPQHash);
+ if((TableOffset + TableSize) > MaxOffset)
+ MaxOffset = TableOffset + TableSize;
+
+ // Is the block table end greater than max offset?
+ TableOffset = MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos);
+ TableSize = (ULONGLONG)pHeader->dwBlockTableSize * sizeof(TMPQBlock);
+ if((TableOffset + TableSize) > MaxOffset)
+ MaxOffset = TableOffset + TableSize;
+
+ // Is the hi-block table end greater than max offset?
+ if((TableOffset = pHeader->HiBlockTablePos64) != 0)
{
- if(pHeader->dwBlockTablePos < pHeader->dwArchiveSize)
- {
- if((pHeader->dwArchiveSize - pHeader->dwBlockTablePos) <= (pHeader->dwBlockTableSize * sizeof(TMPQBlock)))
- return pHeader->dwArchiveSize;
+ TableSize = (ULONGLONG)pHeader->dwBlockTableSize * sizeof(USHORT);
+ if((TableOffset + TableSize) > MaxOffset)
+ MaxOffset = TableOffset + TableSize;
+ }
+
+ // Cut to the file size
+ if(MaxOffset > (FileSize - MpqOffset))
+ MaxOffset = FileSize - MpqOffset;
+ return MaxOffset;
+}
+
+static ULONGLONG DetermineBlockTableSize_V2(TMPQHeader * pHeader)
+{
+ ULONGLONG BlockTableOffset = MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos);
+ ULONGLONG TableOffset;
+ ULONGLONG TableSize = (pHeader->ArchiveSize64 - BlockTableOffset);
- // If the archive size in the header is less than real file size
- dwArchiveSize32 = (DWORD)(FileSize - MpqOffset);
- if(pHeader->dwArchiveSize <= dwArchiveSize32)
- return pHeader->dwArchiveSize;
+ // Subtract the offset of the hi-block table
+ if((TableOffset = pHeader->HiBlockTablePos64) != 0)
+ {
+ if(TableOffset > BlockTableOffset)
+ {
+ TableSize = TableOffset - BlockTableOffset;
}
}
-
- // Return the calculated archive size
- return (EndOfMpq - MpqOffset);
+ return TableSize;
}
static ULONGLONG DetermineArchiveSize_V4(
@@ -564,9 +589,10 @@ DWORD ConvertMpqHeaderToFormat4(
{
// Determine real archive size
pHeader->ArchiveSize64 = DetermineArchiveSize_V2(pHeader, ByteOffset, FileSize);
+ pHeader->dwArchiveSize = (DWORD)(pHeader->ArchiveSize64);
// Calculate size of the block table
- pHeader->BlockTableSize64 = pHeader->ArchiveSize64 - BlockTablePos64;
+ pHeader->BlockTableSize64 = DetermineBlockTableSize_V2(pHeader);
assert(pHeader->BlockTableSize64 <= (pHeader->dwBlockTableSize * sizeof(TMPQBlock)));
}
}