diff options
author | Ladislav Zezula <ladislav.zezula@avg.com> | 2014-01-13 15:33:55 +0100 |
---|---|---|
committer | Ladislav Zezula <ladislav.zezula@avg.com> | 2014-01-13 15:33:55 +0100 |
commit | 48dbf357a334725059dd7ab12c4af041417e4dc4 (patch) | |
tree | 2e07ded23c756614f677d2c6b5b07a30bbf2ae63 | |
parent | 699180bf90ef4952dc7e0f57ce025f54424e30cd (diff) |
+ Support for BOBA map protector
-rw-r--r-- | src/SBaseFileTable.cpp | 31 | ||||
-rw-r--r-- | src/SBaseSubTypes.cpp | 1 | ||||
-rw-r--r-- | src/SFileAttributes.cpp | 4 | ||||
-rw-r--r-- | src/SFileOpenArchive.cpp | 17 | ||||
-rw-r--r-- | test/Test.cpp | 7 |
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"); |