aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLadislav Zezula <zezula@volny.cz>2020-08-09 11:24:16 +0200
committerLadislav Zezula <zezula@volny.cz>2020-08-09 11:24:16 +0200
commitac0dfb94b0a2482f06c2dbff11104448857640a1 (patch)
treefd351cbe15de7badbaf70d8984fd59562db490f3
parentefa7e50ef7d25bcbb15007deed9453b3002aa8aa (diff)
Loading of MPQs v 4.0 with fake MPQ headers
-rw-r--r--src/SBaseFileTable.cpp9
-rw-r--r--src/SFileOpenArchive.cpp7
-rw-r--r--src/StormLib.h1
-rw-r--r--test/StormTest.cpp8
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