diff options
-rw-r--r-- | StormLib_test.vcxproj | 2 | ||||
-rw-r--r-- | src/SBaseCommon.cpp | 16 | ||||
-rw-r--r-- | src/SBaseFileTable.cpp | 13 | ||||
-rw-r--r-- | src/SFileAddFile.cpp | 2 | ||||
-rw-r--r-- | src/SFileReadFile.cpp | 6 | ||||
-rwxr-xr-x | test/StormTest.cpp | 68 | ||||
-rw-r--r-- | test/TLogHelper.cpp | 13 | ||||
-rw-r--r-- | test/stormlib-test-001.txt | 18 |
8 files changed, 103 insertions, 35 deletions
diff --git a/StormLib_test.vcxproj b/StormLib_test.vcxproj index e7703c4..cfa4d65 100644 --- a/StormLib_test.vcxproj +++ b/StormLib_test.vcxproj @@ -46,7 +46,7 @@ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <ConfigurationType>Application</ConfigurationType> <PlatformToolset>v143</PlatformToolset> - <CharacterSet>Unicode</CharacterSet> + <CharacterSet>MultiByte</CharacterSet> </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <ImportGroup Label="ExtensionSettings"> diff --git a/src/SBaseCommon.cpp b/src/SBaseCommon.cpp index ecbfc05..0d9598a 100644 --- a/src/SBaseCommon.cpp +++ b/src/SBaseCommon.cpp @@ -1026,12 +1026,19 @@ void * LoadMpqTable( // and the table is loaded from the current file offset
if(ByteOffset == SFILE_INVALID_POS)
FileStream_GetPos(ha->pStream, &ByteOffset);
+ FileStream_GetSize(ha->pStream, &FileSize);
+
+ // Is the sector table within the file?
+ if(ByteOffset >= FileSize)
+ {
+ STORM_FREE(pbMpqTable);
+ return NULL;
+ }
// The hash table and block table can go beyond EOF.
// Storm.dll reads as much as possible, then fills the missing part with zeros.
// Abused by Spazzler map protector which sets hash table size to 0x00100000
// Abused by NP_Protect in MPQs v4 as well
- FileStream_GetSize(ha->pStream, &FileSize);
if((ByteOffset + dwBytesToRead) > FileSize)
{
// Fill the extra data with zeros
@@ -1358,14 +1365,17 @@ DWORD AllocateSectorOffsets(TMPQFile * hf, bool bLoadFromFile) if((hf->SectorOffsets[0] & 0xFFFFFFFC) > dwSectorOffsLen)
{
// MPQ protectors put some ridiculous values there. We must limit the extra bytes
- if(hf->SectorOffsets[0] > (dwSectorOffsLen + 0x400)) {
+ if(hf->SectorOffsets[0] > (dwSectorOffsLen + 0x400))
+ {
STORM_FREE(hf->SectorOffsets);
hf->SectorOffsets = NULL;
return ERROR_FILE_CORRUPT;
}
+ // The new length of the sector offset must be aligned to DWORD
+ dwSectorOffsLen = (hf->SectorOffsets[0] & 0xFFFFFFFC);
+
// Free the old sector offset table
- dwSectorOffsLen = hf->SectorOffsets[0];
STORM_FREE(hf->SectorOffsets);
goto __LoadSectorOffsets;
}
diff --git a/src/SBaseFileTable.cpp b/src/SBaseFileTable.cpp index 843f81e..e4ce6f6 100644 --- a/src/SBaseFileTable.cpp +++ b/src/SBaseFileTable.cpp @@ -586,6 +586,9 @@ DWORD ConvertMpqHeaderToFormat4( pHeader->BlockTableSize64 = (pHeader->dwBlockTableSize * sizeof(TMPQBlock));
BlockTablePos64 = MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos);
+ // Supply the 64-bit archive size for signature verification
+ pHeader->ArchiveSize64 = pHeader->dwArchiveSize;
+
// We require the block table to follow hash table
if(BlockTablePos64 >= HashTablePos64)
{
@@ -600,7 +603,6 @@ DWORD ConvertMpqHeaderToFormat4( }
else
{
- pHeader->ArchiveSize64 = pHeader->dwArchiveSize;
ha->dwFlags |= MPQ_FLAG_MALFORMED;
}
@@ -651,7 +653,7 @@ DWORD ConvertMpqHeaderToFormat4( // Size of the block table
if(BlockTablePos64)
{
- if(BlockTablePos64 > FileSize)
+ if(BlockTablePos64 > FileSize || BlockTablePos64 >= MaxOffset)
return ERROR_FILE_CORRUPT;
pHeader->BlockTableSize64 = MaxOffset - BlockTablePos64;
MaxOffset = BlockTablePos64;
@@ -660,7 +662,7 @@ DWORD ConvertMpqHeaderToFormat4( // Size of the hash table
if(HashTablePos64)
{
- if(HashTablePos64 > FileSize)
+ if(HashTablePos64 > FileSize || HashTablePos64 >= MaxOffset)
return ERROR_FILE_CORRUPT;
pHeader->HashTableSize64 = MaxOffset - HashTablePos64;
MaxOffset = HashTablePos64;
@@ -2560,12 +2562,7 @@ DWORD LoadAnyHashTable(TMPQArchive * ha) // Note that we load the classic hash table even when HET table exists,
// because if the MPQ gets modified and saved, hash table must be there
if(pHeader->dwHashTableSize)
- {
- // hash-table size must be a power or 2
- if ((pHeader->dwHashTableSize & (pHeader->dwHashTableSize - 1)) != 0)
- return ERROR_FILE_CORRUPT;
ha->pHashTable = LoadHashTable(ha);
- }
// At least one of the tables must be present
if(ha->pHetTable == NULL && ha->pHashTable == NULL)
diff --git a/src/SFileAddFile.cpp b/src/SFileAddFile.cpp index 54dcbc5..f98a185 100644 --- a/src/SFileAddFile.cpp +++ b/src/SFileAddFile.cpp @@ -443,7 +443,7 @@ DWORD SFileAddFile_Init( // Allocate the TMPQFile entry for newly added file
hf = CreateWritableHandle(ha, dwFileSize);
if(hf == NULL)
- return false;
+ return GetLastError();
// Allocate file entry in the MPQ
if(dwErrCode == ERROR_SUCCESS)
diff --git a/src/SFileReadFile.cpp b/src/SFileReadFile.cpp index 180d428..f2c17ba 100644 --- a/src/SFileReadFile.cpp +++ b/src/SFileReadFile.cpp @@ -73,8 +73,8 @@ static DWORD ReadMpqSectors(TMPQFile * hf, LPBYTE pbBuffer, DWORD dwByteOffset, // or not, we won't try that again for the given file. // - AllocateSectorChecksums(hf, true); - hf->bLoadedSectorCRCs = true; + if(AllocateSectorChecksums(hf, true) == ERROR_SUCCESS) + hf->bLoadedSectorCRCs = true; } // TODO: If the raw data MD5s are not loaded yet, load them now @@ -310,7 +310,7 @@ static DWORD ReadMpqFileSingleUnit(TMPQFile * hf, void * pvBuffer, DWORD dwFileP // deDE\DBFilesClient\MountCapability.dbc 0x93->0x77 0x77 0x77 No // - if(pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) + if(pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE && cbInBuffer > sizeof(TPatchInfo)) cbInBuffer = cbInBuffer - sizeof(TPatchInfo); // Is the file compressed by Blizzard's multiple compression ? diff --git a/test/StormTest.cpp b/test/StormTest.cpp index f9f2a03..c4eff22 100755 --- a/test/StormTest.cpp +++ b/test/StormTest.cpp @@ -3866,9 +3866,48 @@ static DWORD TestUtf8Conversions(const BYTE * szTestString, const TCHAR * szList static void Test_PlayingSpace()
{
- HANDLE hFile = NULL;
- HANDLE hMpq = NULL;
+ HANDLE SFileOpenArchivevar0 = NULL;
+ LPCSTR fuzzData = "c:\\segv";
+
+ for(DWORD i = 0; i < 1000; i++)
+ {
+ char NewName[128];
+
+ sprintf(NewName, "c:\\segv%04u", i);
+ CopyFileA(fuzzData, NewName, FALSE);
+ SFileOpenArchivevar0 = NULL;
+
+ bool SFileOpenArchiveval1 = SFileOpenArchive(NewName, i, 0, &SFileOpenArchivevar0);
+ if(!SFileOpenArchiveval1)
+ {
+ fprintf(stderr, "err2");
+ exit(0);
+ }
+
+ bool SFileAddWaveval1 = SFileAddWave(SFileOpenArchivevar0, fuzzData, fuzzData, i, 1);
+ if(!SFileAddWaveval1)
+ {
+ SFileCloseArchive(SFileOpenArchivevar0);
+ fprintf(stderr, "err4");
+ exit(0);
+ }
+ }
+
+ bool SFileRemoveFileval1 = SFileRemoveFile(SFileOpenArchivevar0, fuzzData, (DWORD)_tcslen(fuzzData));
+ if(!SFileRemoveFileval1)
+ {
+ fprintf(stderr, "err6");
+ exit(0);
+ }
+
+ DWORD SFileVerifyArchiveval1 = SFileVerifyArchive(SFileOpenArchivevar0);
+ if(!SFileVerifyArchiveval1)
+ {
+ fprintf(stderr, "err7");
+ exit(0);
+ }
+/*
if(SFileOpenArchive(_T("E:\\DIABDAT.MPQ"), 0, 0, &hMpq))
{
if(SFileOpenFileEx(hMpq, "d1221a.mpq", 0, &hFile))
@@ -3881,15 +3920,19 @@ static void Test_PlayingSpace() }
SFileCloseArchive(hMpq);
}
+*/
}
//-----------------------------------------------------------------------------
// Tables
static LPCTSTR szSigned1 = _T("STANDARD.SNP");
-static LPCTSTR szSigned2 = _T("War2Patch_202.exe");
-static LPCTSTR szSigned3 = _T("WoW-1.2.3.4211-enUS-patch.exe");
+static LPCTSTR szSigned2 = _T("StarDat.mpq");
+static LPCTSTR szSigned3 = _T("War2Patch_202.exe");
static LPCTSTR szSigned4 = _T("(10)DustwallowKeys.w3m");
+static LPCTSTR szSigned5 = _T("WoW-1.2.3.4211-enUS-patch.exe");
+static LPCTSTR szSigned6 = _T("WoW-3.0.1.8337-to-3.0.1.8392-enGB-patch.exe");
+static LPCTSTR szSigned7 = _T("wow-final.MPQ");
static LPCTSTR szDiabdatMPQ = _T("MPQ_1997_v1_Diablo1_DIABDAT.MPQ");
@@ -4140,7 +4183,7 @@ static const TEST_INFO1 TestList_MasterMirror[] = static const TEST_INFO1 Test_OpenMpqs[] =
{
- // PoC's by Gabe Sherman from FuturesLab
+ // PoC's by Gabe Sherman, tinh0.
{_T("pocs/MPQ_2024_01_HeapOverrun.mpq"), NULL, "7008f95dcbc4e5d840830c176dec6969", 14},
{_T("pocs/MPQ_2024_02_StackOverflow.mpq"), NULL, "7093fcbcc9674b3e152e74e8e8a937bb", 4},
{_T("pocs/MPQ_2024_03_TooBigAlloc.mpq"), NULL, "--------------------------------", TFLG_WILL_FAIL},
@@ -4153,6 +4196,11 @@ static const TEST_INFO1 Test_OpenMpqs[] = {_T("pocs/MPQ_2024_10_HuffDecompressError.mpq"), NULL, "--------------------------------", TFLG_WILL_FAIL},
{_T("pocs/MPQ_2024_10_SparseDecompressError.mpq"), NULL, "--------------------------------", TFLG_WILL_FAIL},
{_T("pocs/MPQ_2024_11_HiBlockTablePosInvalid.mpq"), NULL, "--------------------------------", TFLG_WILL_FAIL},
+ {_T("pocs/MPQ_2025_01_SectorTableBeyondEOF.mpq"), NULL, "--------------------------------", TFLG_WILL_FAIL},
+ {_T("pocs/MPQ_2025_02_SectorOffsetSizeNotAligned.mpq"), NULL, "0cc175b9c0f1b6a831c399e269772661", TFLG_WILL_FAIL},
+ {_T("pocs/MPQ_2025_03_InvalidPatchInfo.mpq"), NULL, "93b885adfe0da089cdf634904fd59f71", TFLG_WILL_FAIL},
+ {_T("pocs/MPQ_2025_04_InvalidArchiveSize64.mpq"), NULL, "--------------------------------", TFLG_WILL_FAIL},
+ {_T("pocs/MPQ_2025_05_AddFileError.mpq"), NULL, "ce9b8afed4221a53663d391f10691ba6", TFLG_WILL_FAIL},
// Correct or damaged archives
{_T("MPQ_1997_v1_Diablo1_DIABDAT.MPQ"), NULL, "554b538541e42170ed41cb236483489e", 2910, &TwoFilesD1}, // Base MPQ from Diablo 1
@@ -4246,11 +4294,13 @@ static const TEST_INFO1 Test_OpenMpqs[] = // Signed archives
{_T("MPQ_1997_v1_Diablo1_STANDARD.SNP"), szSigned1, "5ef18ef9a26b5704d8d46a344d976c89", 2 | TFLG_SIGCHECK_BEFORE},
- {_T("MPQ_1999_v1_WeakSignature.exe"), szSigned2, "c1084033d0bd5f7e2b9b78b600c0bba8", 24 | TFLG_SIGCHECK_BEFORE},
- {_T("MPQ_2003_v1_WeakSignatureEmpty.exe"), szSigned3, "97580f9f6d98ffc50191c2f07773e818", 12259 | TFLG_SIGCHECK_BEFORE},
+ {_T("MPQ_1998_v1_StarDat.mpq"), szSigned2, "2530cb937565fd41b1dc0443697096a2", 2925 | TFLG_SIGN_ARCHIVE | TFLG_SIGCHECK_AFTER},
+ {_T("MPQ_1999_v1_WeakSignature.exe"), szSigned3, "c1084033d0bd5f7e2b9b78b600c0bba8", 24 | TFLG_SIGCHECK_BEFORE},
+ {_T("MPQ_1999_v1_WeakSignature.exe"), szSigned3, "807fe2e4d38eccf5ee6bc88f5ee5940d", 25 | TFLG_SIGCHECK_BEFORE | TFLG_MODIFY | TFLG_SIGCHECK_AFTER},
{_T("MPQ_2002_v1_StrongSignature.w3m"), szSigned4, "7b725d87e07a2173c42fe2314b95fa6c", 17 | TFLG_SIGCHECK_BEFORE},
- {_T("MPQ_1998_v1_StarDat.mpq"), _T("MPQ_1998_v1_StarDat.mpq"), "2530cb937565fd41b1dc0443697096a2", 2925 | TFLG_SIGN_ARCHIVE | TFLG_SIGCHECK_AFTER},
- {_T("MPQ_1999_v1_WeakSignature.exe"), szSigned2, "807fe2e4d38eccf5ee6bc88f5ee5940d", 25 | TFLG_SIGCHECK_BEFORE | TFLG_MODIFY | TFLG_SIGCHECK_AFTER},
+ {_T("MPQ_2003_v1_WeakSignatureEmpty.exe"), szSigned5, "97580f9f6d98ffc50191c2f07773e818", 12259 | TFLG_SIGCHECK_BEFORE},
+ {_T("MPQ_2007_v2_StrongSignature1.exe"), szSigned6, "e82bc35366d5f1c588143e5bd35919c0", 23 | TFLG_SIGCHECK_BEFORE},
+ {_T("MPQ_2007_v2_StrongSignature2.MPQ"), szSigned7, "53cedaf7ba8c67b2e2ca95d5eb2b9380", 1622 | TFLG_SIGCHECK_BEFORE},
// Multi-file archive with wrong prefix to see how StormLib deals with it
{_T("flat-file://streaming/model.MPQ.0"), _T("flat-file://model.MPQ.0"), NULL, 0 | TFLG_WILL_FAIL},
diff --git a/test/TLogHelper.cpp b/test/TLogHelper.cpp index 6eb97f6..ad8a067 100644 --- a/test/TLogHelper.cpp +++ b/test/TLogHelper.cpp @@ -17,6 +17,7 @@ #endif
#ifdef _MSC_VER
+#define fmt_I64u_w L"%I64u"
#define fmt_I64u_t _T("%I64u")
#define fmt_I64u_a "%I64u"
#define fmt_I64X_t _T("%I64X")
@@ -65,25 +66,25 @@ inline DWORD Test_GetLastError() #ifdef STORMLIB_WINDOWS
wchar_t * CopyFormatCharacter(wchar_t * szBuffer, const wchar_t *& szFormat)
{
- static const wchar_t * szStringFormat = _T("%s");
- static const wchar_t * szUint64Format = fmt_I64u_t;
+ static const wchar_t * szStringFormat = L"%s";
+ static const wchar_t * szUint64Format = fmt_I64u_w;
// String format
if(szFormat[0] == '%')
{
if(szFormat[1] == 's')
{
- _tcscpy(szBuffer, szStringFormat);
+ wcscpy(szBuffer, szStringFormat);
szFormat += 2;
- return szBuffer + _tcslen(szStringFormat);
+ return szBuffer + wcslen(szStringFormat);
}
// Replace %I64u with the proper platform-dependent suffix
if(szFormat[1] == 'I' && szFormat[2] == '6' && szFormat[3] == '4' && szFormat[4] == 'u')
{
- _tcscpy(szBuffer, szUint64Format);
+ wcscpy(szBuffer, szUint64Format);
szFormat += 5;
- return szBuffer + _tcslen(szUint64Format);
+ return szBuffer + wcslen(szUint64Format);
}
}
diff --git a/test/stormlib-test-001.txt b/test/stormlib-test-001.txt index a1b2449..8e3770c 100644 --- a/test/stormlib-test-001.txt +++ b/test/stormlib-test-001.txt @@ -28,6 +28,14 @@ TestReadingMpq (pocs/MPQ_2024_09_InvalidSectorSize.mpq) succeeded. TestReadingMpq (pocs/MPQ_2024_10_HuffDecompressError.mpq) succeeded. TestReadingMpq (pocs/MPQ_2024_10_SparseDecompressError.mpq) succeeded. TestReadingMpq (pocs/MPQ_2024_11_HiBlockTablePosInvalid.mpq) succeeded. +TestReadingMpq: Error loading the file (listfile) (error code: 38) +TestReadingMpq (pocs/MPQ_2025_01_SectorTableBeyondEOF.mpq) succeeded. +TestReadingMpq: Warning: CRC32 error on (listfile) +TestReadingMpq: Warning: CRC32 error on (listfile) +TestReadingMpq (pocs/MPQ_2025_02_SectorOffsetSizeNotAligned.mpq) succeeded. +TestReadingMpq (pocs/MPQ_2025_03_InvalidPatchInfo.mpq) succeeded. +TestReadingMpq (pocs/MPQ_2025_04_InvalidArchiveSize64.mpq) succeeded. +TestReadingMpq (pocs/MPQ_2025_05_AddFileError.mpq) succeeded. TestReadingMpq (MPQ_1997_v1_Diablo1_DIABDAT.MPQ) succeeded. TestReadingMpq (MPQ_1997_v1_patch_rt_SC1B.mpq) succeeded. TestReadingMpq (MPQ_1997_v1_StarDat_SC1B.mpq) succeeded. @@ -114,11 +122,13 @@ TestReadingMpq (MPQ_2013_v4_Mods#Liberty.SC2Mod#enGB.SC2Data) succeeded. TestReadingMpq (MPQ_2014_v4_base-Win.MPQ) succeeded. TestReadingMpq (MPQ_2014_v4_base-Win.MPQ) succeeded. TestReadingMpq (MPQ_1997_v1_Diablo1_STANDARD.SNP) succeeded. -TestReadingMpq (MPQ_1999_v1_WeakSignature.exe) succeeded. -TestReadingMpq (MPQ_2003_v1_WeakSignatureEmpty.exe) succeeded. -TestReadingMpq (MPQ_2002_v1_StrongSignature.w3m) succeeded. TestReadingMpq (MPQ_1998_v1_StarDat.mpq) succeeded. TestReadingMpq (MPQ_1999_v1_WeakSignature.exe) succeeded. +TestReadingMpq (MPQ_1999_v1_WeakSignature.exe) succeeded. +TestReadingMpq (MPQ_2002_v1_StrongSignature.w3m) succeeded. +TestReadingMpq (MPQ_2003_v1_WeakSignatureEmpty.exe) succeeded. +TestReadingMpq (MPQ_2007_v2_StrongSignature1.exe) succeeded. +TestReadingMpq (MPQ_2007_v2_StrongSignature2.MPQ) succeeded. TestReadingMpq (flat-file://streaming/model.MPQ.0) succeeded. TestReadingMpq (MPQ_2013_vX_Battle.net.MPQ) succeeded. TestReadingMpq (MPQ_1997_v1_Diablo1_DIABDAT.MPQ) succeeded. @@ -144,7 +154,7 @@ CreateNewMpq (StormLibTest_EmptyMpq_v2.mpq) succeeded. CreateNewMpq (StormLibTest_EmptyMpq_v4.mpq) succeeded. CreateNewMpq (StormLibTest_Český.mpq) succeeded. . CreateNewMpq (StormLibTest_Русский.mpq) succeeded. ... -CreateNewMpq (StormLibTest_ελληνικά.mpq) succeeded. +CreateNewMpq (StormLibTest_ελληνικά.mpq) succeeded.... CreateNewMpq (StormLibTest_日本語.mpq) succeeded. .. CreateNewMpq (StormLibTest_简体中文.mpq) succeeded.... CreateNewMpq (StormLibTest_الععربية.mpq) succeeded.... |