summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLadislav Zezula <ladislav.zezula@avg.com>2014-01-13 15:33:55 +0100
committerLadislav Zezula <ladislav.zezula@avg.com>2014-01-13 15:33:55 +0100
commit48dbf357a334725059dd7ab12c4af041417e4dc4 (patch)
tree2e07ded23c756614f677d2c6b5b07a30bbf2ae63
parent699180bf90ef4952dc7e0f57ce025f54424e30cd (diff)
+ Support for BOBA map protector
-rw-r--r--src/SBaseFileTable.cpp31
-rw-r--r--src/SBaseSubTypes.cpp1
-rw-r--r--src/SFileAttributes.cpp4
-rw-r--r--src/SFileOpenArchive.cpp17
-rw-r--r--test/Test.cpp7
5 files changed, 47 insertions, 13 deletions
diff --git a/src/SBaseFileTable.cpp b/src/SBaseFileTable.cpp
index 564287c..ff73bdc 100644
--- a/src/SBaseFileTable.cpp
+++ b/src/SBaseFileTable.cpp
@@ -382,6 +382,7 @@ int ConvertMpqHeaderToFormat4(
ULONGLONG HashTablePos64 = 0;
ULONGLONG ByteOffset;
USHORT wFormatVersion = BSWAP_INT16_UNSIGNED(pHeader->wFormatVersion);
+ DWORD dwByteOffset32;
DWORD dwTableSize;
int nError = ERROR_SUCCESS;
@@ -430,6 +431,16 @@ int ConvertMpqHeaderToFormat4(
pHeader->ArchiveSize64 = DetermineArchiveSize_V1(ha, pHeader, MpqOffset, FileSize);
pHeader->dwArchiveSize = (DWORD)pHeader->ArchiveSize64;
+ // Handle case when the block table is placed before the MPQ header
+ // Used by BOBA protector
+ dwByteOffset32 = (DWORD)MpqOffset + pHeader->dwBlockTablePos;
+ if(dwByteOffset32 < MpqOffset)
+ {
+ pHeader->BlockTableSize64 = (DWORD)MpqOffset - dwByteOffset32;
+ pHeader->dwBlockTableSize = (DWORD)(pHeader->BlockTableSize64 / sizeof(TMPQBlock));
+ break;
+ }
+
// Handle case when either the MPQ is cut in the middle of the block table
// or the MPQ is malformed so that block table size is greater than should be
ByteOffset = MpqOffset + pHeader->dwBlockTablePos;
@@ -438,6 +449,7 @@ int ConvertMpqHeaderToFormat4(
{
pHeader->BlockTableSize64 = FileSize - ByteOffset;
pHeader->dwBlockTableSize = (DWORD)(pHeader->BlockTableSize64 / sizeof(TMPQBlock));
+ break;
}
}
break;
@@ -577,8 +589,15 @@ int ConvertMpqHeaderToFormat4(
default:
- // Last resort: Check if it's a War of the Immortal data file (SQP)
- nError = ConvertSqpHeaderToFormat4(ha, FileSize, dwFlags);
+ // Check if it's a War of the Immortal data file (SQP)
+ // If not, we treat it as malformed MPQ version 1.0
+ if(ConvertSqpHeaderToFormat4(ha, FileSize, dwFlags) != ERROR_SUCCESS)
+ {
+ pHeader->wFormatVersion = MPQ_FORMAT_VERSION_1;
+ pHeader->dwHeaderSize = MPQ_HEADER_SIZE_V1;
+ ha->dwFlags |= MPQ_FLAG_MALFORMED;
+ goto Label_ArchiveVersion1;
+ }
break;
}
@@ -2262,12 +2281,14 @@ TMPQBlock * LoadBlockTable(TMPQArchive * ha, bool bDontFixEntries)
{
case MPQ_SUBTYPE_MPQ:
- // Calculate sizes of both tables
+ // Calculate byte position of the block table
ByteOffset = ha->MpqPos + MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos);
+ if((pHeader->wFormatVersion == MPQ_FORMAT_VERSION_1) && (ha->dwFlags & MPQ_FLAG_MALFORMED))
+ ByteOffset = (DWORD)ha->MpqPos + pHeader->dwBlockTablePos;
+
+ // Calculate full and compressed size of the block table
dwTableSize = pHeader->dwBlockTableSize * sizeof(TMPQBlock);
dwCmpSize = (DWORD)pHeader->BlockTableSize64;
-
- // If the the block table size was invalid, it should be fixed by now
assert((ByteOffset + dwCmpSize) <= (ha->MpqPos + ha->pHeader->ArchiveSize64));
//
diff --git a/src/SBaseSubTypes.cpp b/src/SBaseSubTypes.cpp
index b44cd9e..117221d 100644
--- a/src/SBaseSubTypes.cpp
+++ b/src/SBaseSubTypes.cpp
@@ -129,7 +129,6 @@ int ConvertSqpHeaderToFormat4(
Header.dwBlockTableSize = BSWAP_INT32_UNSIGNED(pSqpHeader->dwBlockTableSize);
Header.wFormatVersion = BSWAP_INT16_UNSIGNED(pSqpHeader->wFormatVersion);
Header.wSectorSize = BSWAP_INT16_UNSIGNED(pSqpHeader->wSectorSize);
- assert(Header.dwHeaderSize == sizeof(TSQPHeader));
// Verify the SQP header
if(Header.dwID == ID_MPQ && Header.dwHeaderSize == sizeof(TSQPHeader) && Header.dwArchiveSize == FileSize)
diff --git a/src/SFileAttributes.cpp b/src/SFileAttributes.cpp
index f947d79..a74b54f 100644
--- a/src/SFileAttributes.cpp
+++ b/src/SFileAttributes.cpp
@@ -328,6 +328,10 @@ int SAttrLoadAttributes(TMPQArchive * ha)
// File table must be initialized
assert(ha->pFileTable != NULL);
+ // Don't load the attributes file from malformer Warcraft III maps
+ if(ha->dwFlags & MPQ_FLAG_MALFORMED)
+ return ERROR_FILE_CORRUPT;
+
// Attempt to open the "(attributes)" file.
// If it's not there, then the archive doesn't support attributes
if(SFileOpenFileEx((HANDLE)ha, ATTRIBUTES_NAME, SFILE_OPEN_ANY_LOCALE, &hFile))
diff --git a/src/SFileOpenArchive.cpp b/src/SFileOpenArchive.cpp
index 356aa59..ceb4ce1 100644
--- a/src/SFileOpenArchive.cpp
+++ b/src/SFileOpenArchive.cpp
@@ -91,9 +91,18 @@ static int VerifyMpqTablePositions(TMPQArchive * ha, ULONGLONG FileSize)
// Check the begin of block table
if(pHeader->wBlockTablePosHi || pHeader->dwBlockTablePos)
{
- ByteOffset = ha->MpqPos + MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos);
- if(ByteOffset > FileSize)
- return ERROR_BAD_FORMAT;
+ if((pHeader->wFormatVersion == MPQ_FORMAT_VERSION_1) && (ha->dwFlags & MPQ_FLAG_MALFORMED))
+ {
+ ByteOffset = (DWORD)ha->MpqPos + pHeader->dwBlockTablePos;
+ if(ByteOffset > FileSize)
+ return ERROR_BAD_FORMAT;
+ }
+ else
+ {
+ ByteOffset = ha->MpqPos + MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos);
+ if(ByteOffset > FileSize)
+ return ERROR_BAD_FORMAT;
+ }
}
// Check the begin of hi-block table
@@ -252,7 +261,7 @@ bool WINAPI SFileOpenArchive(
// There must be MPQ header signature. Note that STORM.dll from Warcraft III actually
// tests the MPQ header size. It must be at least 0x20 bytes in order to load it
// Abused by Spazzler Map protector. Note that the size check is not present
- // in Storm.dll v 1.00, so Diablo I code would load the MPQ anyway.
+ // in Storm.dll v 1.00, so Diablo I code would load the MPQ anyway.
dwHeaderSize = BSWAP_INT32_UNSIGNED(ha->HeaderData[1]);
if(dwHeaderID == ID_MPQ && dwHeaderSize >= MPQ_HEADER_SIZE_V1)
{
diff --git a/test/Test.cpp b/test/Test.cpp
index 6b76848..a82a6e1 100644
--- a/test/Test.cpp
+++ b/test/Test.cpp
@@ -3427,9 +3427,6 @@ int main(int argc, char * argv[])
// if(nError == ERROR_SUCCESS)
// nError = FindFilePairs(ForEachFile_CreateArchiveLink, "2004 - WoW\\06080", "2004 - WoW\\06299");
- HANDLE hFile = NULL;
- SFileCreateFile(NULL, "huhu", 0, 260, 0, MPQ_FILE_COMPRESS, &hFile);
-
// Search all testing archives and verify their SHA1 hash
if(nError == ERROR_SUCCESS)
nError = FindFiles(ForEachFile_VerifyFileChecksum, szMpqSubDir);
@@ -3538,6 +3535,10 @@ int main(int argc, char * argv[])
if(nError == ERROR_SUCCESS)
nError = TestOpenArchive("MPQ_2002_v1_ProtectedMap_Spazzler.w3x");
+ // Open an Warcraft III map locked by the Spazzler protector
+ if(nError == ERROR_SUCCESS)
+ nError = TestOpenArchive("MPQ_2002_v1_ProtectedMap_BOBA.w3m");
+
// Open a MPQ archive v 3.0
if(nError == ERROR_SUCCESS)
nError = TestOpenArchive("MPQ_2010_v3_expansion-locale-frFR.MPQ");