From ac0dfb94b0a2482f06c2dbff11104448857640a1 Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Sun, 9 Aug 2020 11:24:16 +0200 Subject: Loading of MPQs v 4.0 with fake MPQ headers --- src/SBaseFileTable.cpp | 9 ++++++--- src/SFileOpenArchive.cpp | 7 +++++-- src/StormLib.h | 1 + test/StormTest.cpp | 8 ++++++-- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/SBaseFileTable.cpp b/src/SBaseFileTable.cpp index a54f152..7f67533 100644 --- a/src/SBaseFileTable.cpp +++ b/src/SBaseFileTable.cpp @@ -553,8 +553,11 @@ int ConvertMpqHeaderToFormat4( // Verify header MD5. Header MD5 is calculated from the MPQ header since the 'MPQ\x1A' // signature until the position of header MD5 at offset 0xC0 BSWAP_TMPQHEADER(pHeader, MPQ_FORMAT_VERSION_4); + + // Apparently, Starcraft II only accepts MPQ headers where the MPQ header hash matches + // If MD5 doesn't match, we ignore this offset if(!VerifyDataBlockHash(pHeader, MPQ_HEADER_SIZE_V4 - MD5_DIGEST_SIZE, pHeader->MD5_MpqHeader)) - nError = ERROR_FILE_CORRUPT; + return ERROR_FAKE_MPQ_HEADER; // Calculate the block table position BlockTablePos64 = MpqOffset + MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos); @@ -2214,7 +2217,7 @@ static TMPQHash * LoadHashTable(TMPQArchive * ha) break; } - // Remember the size of the hash table + // Return the loaded hash table return pHashTable; } @@ -2337,7 +2340,7 @@ int LoadAnyHashTable(TMPQArchive * ha) ha->pHetTable = LoadHetTable(ha); // Try to load classic hash table - if(pHeader->dwHashTableSize) + if(pHeader->dwHashTableSize && ha->pHetTable == NULL) ha->pHashTable = LoadHashTable(ha); // At least one of the tables must be present diff --git a/src/SFileOpenArchive.cpp b/src/SFileOpenArchive.cpp index 9e6f5d6..7755eaf 100644 --- a/src/SFileOpenArchive.cpp +++ b/src/SFileOpenArchive.cpp @@ -317,8 +317,11 @@ bool WINAPI SFileOpenArchive( { // Now convert the header to version 4 nError = ConvertMpqHeaderToFormat4(ha, SearchOffset, FileSize, dwFlags, bIsWarcraft3Map); - bSearchComplete = true; - break; + if(nError != ERROR_FAKE_MPQ_HEADER) + { + bSearchComplete = true; + break; + } } // Check for MPK archives (Longwu Online - MPQ fork) diff --git a/src/StormLib.h b/src/StormLib.h index bd8ea94..81f8c59 100644 --- a/src/StormLib.h +++ b/src/StormLib.h @@ -158,6 +158,7 @@ extern "C" { #define ERROR_FILE_INCOMPLETE 10006 // The required file part is missing #define ERROR_UNKNOWN_FILE_NAMES 10007 // A name of at least one file is unknown #define ERROR_CANT_FIND_PATCH_PREFIX 10008 // StormLib was unable to find patch prefix for the patches +#define ERROR_FAKE_MPQ_HEADER 10009 // The header at this position is fake header // Values for SFileCreateArchive #define HASH_TABLE_SIZE_MIN 0x00000004 // Verified: If there is 1 file, hash table size is 4 diff --git a/test/StormTest.cpp b/test/StormTest.cpp index 3723b6d..9766fd0 100644 --- a/test/StormTest.cpp +++ b/test/StormTest.cpp @@ -36,7 +36,7 @@ // Defines #ifdef PLATFORM_WINDOWS -#define WORK_PATH_ROOT _T("E:\\Multimedia\\MPQs") +#define WORK_PATH_ROOT _T("\\Multimedia\\MPQs") static const TCHAR szListFileDir[] = { '1', '9', '9', '5', ' ', '-', ' ', 'T', 'e', 's', 't', ' ', 'M', 'P', 'Q', 's', '\\', 'l', 'i', 's', 't', 'f', 'i', 'l', 'e', 's', '-', (TCHAR)0x65B0, (TCHAR)0x5EFA, (TCHAR)0x6587, (TCHAR)0x4EF6, (TCHAR)0x5939, 0 }; #endif @@ -4654,6 +4654,10 @@ int _tmain(int argc, TCHAR * argv[]) if(nError == ERROR_SUCCESS) nError = TestOpenArchive_Corrupt(_T("MPQ_2013_vX_Battle.net.MPQ")); */ + // Test on an archive that has two fake headers before the real one + if (nError == ERROR_SUCCESS) + nError = TestOpenArchive_Corrupt(_T("MPQ_2020_v4_FakeMpqHeaders.SC2Mod")); +/* // Open a patched archive if(nError == ERROR_SUCCESS) nError = TestOpenArchive_Patched(PatchList_StarCraft, "music\\terran1.wav", 0); @@ -4848,7 +4852,7 @@ int _tmain(int argc, TCHAR * argv[]) // Test replacing a file with zero size file if(nError == ERROR_SUCCESS) nError = TestModifyArchive_ReplaceFile(_T("MPQ_2014_v4_Base.StormReplay"), _T("AddFile-replay.message.events")); - +*/ #ifdef _MSC_VER _CrtDumpMemoryLeaks(); #endif // _MSC_VER -- cgit v1.2.3