aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLadislav Zezula <ladislav.zezula@avg.com>2016-09-30 11:23:29 +0200
committerLadislav Zezula <ladislav.zezula@avg.com>2016-09-30 11:23:29 +0200
commitb8fb98fcc4aa2d1c6ab6ce57b6b2e10a25861a56 (patch)
treecf732fe901659a7bb7e80c3aafd30bb813c0b28e
parent8a370dd9336540b8be585272182de0f74aac9241 (diff)
+ Yet another protector
-rw-r--r--src/SBaseCommon.cpp2
-rw-r--r--src/SBaseDumpData.cpp4
-rw-r--r--src/SBaseFileTable.cpp40
-rw-r--r--src/SBaseSubTypes.cpp4
-rw-r--r--src/StormLib.h7
-rw-r--r--storm_dll/storm_test.cpp12
-rw-r--r--test/StormTest.cpp80
7 files changed, 119 insertions, 30 deletions
diff --git a/src/SBaseCommon.cpp b/src/SBaseCommon.cpp
index 977664a..aa891df 100644
--- a/src/SBaseCommon.cpp
+++ b/src/SBaseCommon.cpp
@@ -721,7 +721,7 @@ TMPQHash * AllocateHashEntry(
pHash->dwName1 = dwName1;
pHash->dwName2 = dwName2;
pHash->lcLocale = (USHORT)lcLocale;
- pHash->wPlatform = 0;
+ pHash->Platform = 0;
pHash->dwBlockIndex = (DWORD)(pFileEntry - ha->pFileTable);
}
diff --git a/src/SBaseDumpData.cpp b/src/SBaseDumpData.cpp
index d156030..334561b 100644
--- a/src/SBaseDumpData.cpp
+++ b/src/SBaseDumpData.cpp
@@ -51,11 +51,11 @@ void DumpHashTable(TMPQHash * pHashTable, DWORD dwHashTableSize)
printf("== Hash Table =================================\n");
for(i = 0; i < dwHashTableSize; i++)
{
- printf("[%08x] %08X %08X %04X %04X %08X\n", i,
+ printf("[%08x] %08X %08X %04X %02X %08X\n", i,
pHashTable[i].dwName1,
pHashTable[i].dwName2,
pHashTable[i].lcLocale,
- pHashTable[i].wPlatform,
+ pHashTable[i].Platform,
pHashTable[i].dwBlockIndex);
}
printf("-----------------------------------------------\n\n");
diff --git a/src/SBaseFileTable.cpp b/src/SBaseFileTable.cpp
index fe5eb78..c7a26aa 100644
--- a/src/SBaseFileTable.cpp
+++ b/src/SBaseFileTable.cpp
@@ -612,32 +612,42 @@ static bool IsValidHashEntry1(TMPQArchive * ha, TMPQHash * pHash, TMPQBlock * pB
}
// Returns a hash table entry in the following order:
-// 1) A hash table entry with the preferred locale
-// 2) A hash table entry with the neutral locale
+// 1) A hash table entry with the preferred locale and platform
+// 2) A hash table entry with the neutral|matching locale and neutral|matching platform
// 3) NULL
-static TMPQHash * GetHashEntryLocale(TMPQArchive * ha, const char * szFileName, LCID lcLocale)
+// Storm_2016.dll: 15020940
+static TMPQHash * GetHashEntryLocale(TMPQArchive * ha, const char * szFileName, LCID lcLocale, BYTE Platform)
{
- TMPQHash * pHashNeutral = NULL;
TMPQHash * pFirstHash = GetFirstHashEntry(ha, szFileName);
+ TMPQHash * pBestEntry = NULL;
TMPQHash * pHash = pFirstHash;
// Parse the found hashes
while(pHash != NULL)
{
- // If the locales match, return it
- if(lcLocale == pHash->lcLocale)
+ // Storm_2016.dll: 150209CB
+ // If the hash entry matches both locale and platform, return it immediately
+ // Note: We only succeed this check if the locale is non-neutral, because
+ // some Warcraft III maps have several items with neutral locale&platform, which leads
+ // to wrong item being returned
+ if((lcLocale || Platform) && pHash->lcLocale == lcLocale && pHash->Platform == Platform)
return pHash;
-
- // If we found neutral hash, remember it
- if(pHash->lcLocale == 0)
- pHashNeutral = pHash;
+
+ // Storm_2016.dll: 150209D9
+ // If (locale matches or is neutral) OR (platform matches or is neutral)
+ // remember this as the best entry
+ if(pHash->lcLocale == 0 || pHash->lcLocale == lcLocale)
+ {
+ if(pHash->Platform == 0 || pHash->Platform == Platform)
+ pBestEntry = pHash;
+ }
// Get the next hash entry for that file
pHash = GetNextHashEntry(ha, pFirstHash, pHash);
}
// At the end, return neutral hash (if found), otherwise NULL
- return pHashNeutral;
+ return pBestEntry;
}
// Returns a hash table entry in the following order:
@@ -1803,7 +1813,7 @@ TFileEntry * GetFileEntryLocale2(TMPQArchive * ha, const char * szFileName, LCID
// we will need the pointer to hash table entry
if(ha->pHashTable != NULL)
{
- pHash = GetHashEntryLocale(ha, szFileName, lcLocale);
+ pHash = GetHashEntryLocale(ha, szFileName, lcLocale, 0);
if(pHash != NULL && MPQ_BLOCK_INDEX(pHash) < ha->dwFileTableSize)
{
if(PtrHashIndex != NULL)
@@ -1987,7 +1997,8 @@ int RenameFileEntry(
pHashEntry->dwName1 = 0xFFFFFFFF;
pHashEntry->dwName2 = 0xFFFFFFFF;
pHashEntry->lcLocale = 0xFFFF;
- pHashEntry->wPlatform = 0xFFFF;
+ pHashEntry->Platform = 0xFF;
+ pHashEntry->Reserved = 0xFF;
pHashEntry->dwBlockIndex = HASH_ENTRY_DELETED;
}
@@ -2027,7 +2038,8 @@ int DeleteFileEntry(TMPQArchive * ha, TMPQFile * hf)
pHashEntry->dwName1 = 0xFFFFFFFF;
pHashEntry->dwName2 = 0xFFFFFFFF;
pHashEntry->lcLocale = 0xFFFF;
- pHashEntry->wPlatform = 0xFFFF;
+ pHashEntry->Platform = 0xFF;
+ pHashEntry->Reserved = 0xFF;
pHashEntry->dwBlockIndex = HASH_ENTRY_DELETED;
}
diff --git a/src/SBaseSubTypes.cpp b/src/SBaseSubTypes.cpp
index 333b881..47c205e 100644
--- a/src/SBaseSubTypes.cpp
+++ b/src/SBaseSubTypes.cpp
@@ -216,7 +216,7 @@ TMPQHash * LoadSqpHashTable(TMPQArchive * ha)
// Store the rest. Note that this must be done last,
// because block index corresponds to pMpqHash->dwName2
pMpqHash->dwBlockIndex = MPQ_BLOCK_INDEX(pSqpHash);
- pMpqHash->wPlatform = 0;
+ pMpqHash->Platform = 0;
pMpqHash->lcLocale = 0;
}
}
@@ -544,7 +544,7 @@ TMPQHash * LoadMpkHashTable(TMPQArchive * ha)
// Copy the MPK hash entry to the hash table
pHash->dwBlockIndex = pMpkHash[i].dwBlockIndex;
- pHash->wPlatform = 0;
+ pHash->Platform = 0;
pHash->lcLocale = 0;
pHash->dwName1 = pMpkHash[i].dwName2;
pHash->dwName2 = pMpkHash[i].dwName3;
diff --git a/src/StormLib.h b/src/StormLib.h
index 3621096..b6df481 100644
--- a/src/StormLib.h
+++ b/src/StormLib.h
@@ -617,12 +617,13 @@ typedef struct _TMPQHash
// The platform the file is used for. 0 indicates the default platform.
// No other values have been observed.
- // Note: wPlatform is actually just BYTE, but since it has never been used, we don't care.
- USHORT wPlatform;
+ BYTE Platform;
+ BYTE Reserved;
#else
- USHORT wPlatform;
+ BYTE Platform;
+ BYTE Reserved;
USHORT lcLocale;
#endif
diff --git a/storm_dll/storm_test.cpp b/storm_dll/storm_test.cpp
index 5e498b3..2d1e6bc 100644
--- a/storm_dll/storm_test.cpp
+++ b/storm_dll/storm_test.cpp
@@ -22,22 +22,22 @@
//-----------------------------------------------------------------------------
// Main
-unsigned char szKoreanFileName[] = {0x77, 0x61, 0x72, 0x33, 0x6D, 0x61, 0x70, 0x49, 0x6D, 0x70, 0x6F, 0x72, 0x74, 0x65, 0x64, 0x5C, 0xBF, 0xD5, 0xB1, 0xB9, 0x2E, 0x6D, 0x70, 0x33, 0x00};
-
int main()
{
- LPCSTR szArchiveName = "e:\\MPQ_2016_v1_KoreanFile.w3m";
+ LPCSTR szArchiveName = "e:\\Multimedia\\MPQs\\1995 - Test MPQs\\MPQ_2016_v1_123.w3x";
HANDLE hMpq = NULL;
HANDLE hFile = NULL;
- char szFileName[MAX_PATH];
+ BYTE Buffer[0x100];
+ DWORD dwBytesRead = 0;
_asm int 3;
if(StormOpenArchive(szArchiveName, 0, 0, &hMpq))
{
- memcpy(szFileName, szKoreanFileName, _countof(szKoreanFileName));
- if(StormOpenFileEx(hMpq, szFileName, 0, &hFile))
+ if(StormOpenFileEx(hMpq, "war3map.j", 0, &hFile))
{
+ dwBytesRead = StormGetFileSize(hFile, NULL);
+ StormReadFile(hFile, Buffer, sizeof(Buffer), &dwBytesRead, NULL);
StormCloseFile(hFile);
}
diff --git a/test/StormTest.cpp b/test/StormTest.cpp
index 410dfd4..0feb003 100644
--- a/test/StormTest.cpp
+++ b/test/StormTest.cpp
@@ -308,6 +308,25 @@ static bool IsMpqExtension(const char * szFileName)
return false;
}
+static void BinaryFromString(const char * szBinary, LPBYTE pbBuffer, DWORD cbBuffer)
+{
+ LPBYTE pbBufferEnd = pbBuffer + cbBuffer;
+ char * szTemp;
+ char szHexaDigit[4];
+
+ while(szBinary[0] != 0 && pbBuffer < pbBufferEnd)
+ {
+ // Get the 2-byte chunk
+ szHexaDigit[0] = szBinary[0];
+ szHexaDigit[1] = szBinary[1];
+ szHexaDigit[2] = 0;
+
+ // Convert to integer
+ *pbBuffer++ = (BYTE)strtoul(szHexaDigit, &szTemp, 16);
+ szBinary += 2;
+ }
+}
+
static void AddStringBeforeExtension(char * szBuffer, const char * szFileName, const char * szExtraString)
{
const char * szExtension;
@@ -1675,7 +1694,7 @@ static int SearchArchive(
// Increment number of files
dwFileCount++;
-// if(!_stricmp(sf.cFileName, "Interface\\Glues\\CREDITS\\1024px-Blade3_final2.blp"))
+// if(!_stricmp(sf.cFileName, "war3map.j"))
// DebugBreak();
if(dwTestFlags & TEST_FLAG_MOST_PATCHED)
@@ -2634,6 +2653,60 @@ static int TestOpenArchive_SetPos(const char * szPlainName, const char * szFileN
return nError;
}
+static int TestOpenArchive_ProtectedMap(const char * szPlainName, const char * szListFile = NULL, DWORD dwExpectedFileCount = 0, const char * szExpectedMD5 = NULL)
+{
+ TLogHelper Logger("ProtectedMapTest", szPlainName);
+ HANDLE hMpq;
+ DWORD dwTestFlags = TEST_FLAG_LOAD_FILES | TEST_FLAG_HASH_FILES;
+ DWORD dwFileCount = 0;
+ BYTE ExpectedMD5[MD5_DIGEST_SIZE];
+ BYTE OverallMD5[MD5_DIGEST_SIZE];
+ char szListFileBuff[MAX_PATH];
+ int nError;
+
+ // Copy the archive so we won't fuck up the original one
+ nError = OpenExistingArchiveWithCopy(&Logger, szPlainName, szPlainName, &hMpq);
+ if(nError == ERROR_SUCCESS)
+ {
+ // If the listfile was given, add it to the MPQ
+ if(szListFile != NULL)
+ {
+ Logger.PrintProgress("Adding listfile %s ...", szListFile);
+ CreateFullPathName(szListFileBuff, szMpqSubDir, szListFile);
+ nError = SFileAddListFile(hMpq, szListFileBuff);
+ if(nError != ERROR_SUCCESS)
+ Logger.PrintMessage("Failed to add the listfile to the MPQ");
+ }
+
+ // Search the archive and load every file
+ nError = SearchArchive(&Logger, hMpq, dwTestFlags, &dwFileCount, OverallMD5);
+ SFileCloseArchive(hMpq);
+ }
+
+ // Check the file count and hash, if required
+ if(nError == ERROR_SUCCESS && dwExpectedFileCount != 0)
+ {
+ if(dwFileCount != dwExpectedFileCount)
+ {
+ Logger.PrintMessage("File count mismatch(expected: %u, found:%u)", dwExpectedFileCount, dwFileCount);
+ nError = ERROR_CAN_NOT_COMPLETE;
+ }
+ }
+
+ // Check the overall hash, if required
+ if(nError == ERROR_SUCCESS && szExpectedMD5 != NULL && szExpectedMD5[0] != 0)
+ {
+ BinaryFromString(szExpectedMD5, ExpectedMD5, MD5_DIGEST_SIZE);
+ if(memcmp(ExpectedMD5, OverallMD5, MD5_DIGEST_SIZE))
+ {
+ Logger.PrintMessage("Extracted files MD5 mismatch");
+ nError = ERROR_CAN_NOT_COMPLETE;
+ }
+ }
+
+ return nError;
+}
+
// Open an empty archive (found in WoW cache - it's just a header)
static int TestOpenArchive_WillFail(const char * szPlainName)
{
@@ -4470,9 +4543,12 @@ int main(int argc, char * argv[])
if(nError == ERROR_SUCCESS)
nError = TestOpenArchive("MPQ_2016_v1_ProtectedMap_1.4.w3x");
-*/
+
if(nError == ERROR_SUCCESS)
nError = TestOpenArchive("MPQ_2016_v1_KoreanFile.w3m");
+*/
+ if(nError == ERROR_SUCCESS)
+ nError = TestOpenArchive_ProtectedMap("MPQ_2016_v1_123.w3x", NULL, 17, "23b09ad3b8d89ec97df8860447abc7eb");
/*
// Open the multi-file archive with wrong prefix to see how StormLib deals with it
if(nError == ERROR_SUCCESS)