diff options
| author | Ladislav Zezula <E:\Ladik\Mail> | 2016-05-27 16:50:50 +0200 | 
|---|---|---|
| committer | Ladislav Zezula <E:\Ladik\Mail> | 2016-05-27 16:50:50 +0200 | 
| commit | 47b6b6eb4addd82a89d6bcd8fa92f9c0a09a5781 (patch) | |
| tree | 5fb9c92f6352c9275d27d6ebb9aee87e20c75151 | |
| parent | f1655f8afe2ef76d4906eb3e94dfd3c2b5241eb4 (diff) | |
+ Support for MPQs that have invalid (and ignored) flags in the block table
+ Support for MPQs that have malformed block indexes (0x8000xxxx or 0x4000xxxx)
| -rw-r--r-- | src/SBaseFileTable.cpp | 22 | ||||
| -rw-r--r-- | src/SFileOpenArchive.cpp | 4 | ||||
| -rw-r--r-- | src/SFileOpenFileEx.cpp | 6 | ||||
| -rw-r--r-- | src/StormLib.h | 3 | ||||
| -rw-r--r-- | test/StormTest.cpp | 17 | 
5 files changed, 36 insertions, 16 deletions
diff --git a/src/SBaseFileTable.cpp b/src/SBaseFileTable.cpp index b38dbc3..9d37ff1 100644 --- a/src/SBaseFileTable.cpp +++ b/src/SBaseFileTable.cpp @@ -581,23 +581,33 @@ int ConvertMpqHeaderToFormat4(  // Hash entry verification when the file table does not exist yet
  bool IsValidHashEntry(TMPQArchive * ha, TMPQHash * pHash)
  {
 -    TFileEntry * pFileEntry = ha->pFileTable + pHash->dwBlockIndex;
 -    return ((pHash->dwBlockIndex < ha->dwFileTableSize) && (pFileEntry->dwFlags & MPQ_FILE_EXISTS)) ? true : false;
 +    TFileEntry * pFileEntry = ha->pFileTable + MPQ_BLOCK_INDEX(pHash->dwBlockIndex);
 +    DWORD dwBlockIndex = MPQ_BLOCK_INDEX(pHash->dwBlockIndex);
 +    
 +    pFileEntry = ha->pFileTable + dwBlockIndex;
 +    return ((dwBlockIndex < ha->dwFileTableSize) && (pFileEntry->dwFlags & MPQ_FILE_EXISTS)) ? true : false;
  }
  // Hash entry verification when the file table does not exist yet
  static bool IsValidHashEntry1(TMPQArchive * ha, TMPQHash * pHash, TMPQBlock * pBlockTable)
  {
      ULONGLONG ByteOffset;    
 -    TMPQBlock * pBlock = pBlockTable + pHash->dwBlockIndex;
 +    TMPQBlock * pBlock;
 +    DWORD dwBlockIndex;
      // We need to mask out the upper 4 bits of the block table index.
      // This is because it gets shifted out when calculating block table offset
      // BlockTableOffset = pHash->dwBlockIndex * 0x10
      // Malformed MPQ maps may contain invalid entries
      // Note that Storm.dll does not perfom this check
 -    if((pHash->dwBlockIndex & 0x0FFFFFFF) < ha->pHeader->dwBlockTableSize)
 +    dwBlockIndex = MPQ_BLOCK_INDEX(pHash->dwBlockIndex);
 +
 +    // The block index is considered valid if it's less than block table size
 +    if(dwBlockIndex < ha->pHeader->dwBlockTableSize)
      {
 +        // Calculate the block table position
 +        pBlock = pBlockTable + dwBlockIndex;
 +
          // Check whether this is an existing file
          // Also we do not allow to be file size greater than 2GB
          if((pBlock->dwFlags & MPQ_FILE_EXISTS) && (pBlock->dwFSize & 0x8000000) == 0)
 @@ -783,8 +793,8 @@ static int BuildFileTableFromBlockTable(          if(IsValidHashEntry1(ha, pHash, pBlockTable))
          {
 -            DWORD dwBlockIndex = pHash->dwBlockIndex;
 -            DWORD dwNewIndex = pHash->dwBlockIndex;
 +            DWORD dwBlockIndex = MPQ_BLOCK_INDEX(pHash->dwBlockIndex);
 +            DWORD dwNewIndex = MPQ_BLOCK_INDEX(pHash->dwBlockIndex);
              // Determine the new block index
              if(DefragmentTable != NULL)
 diff --git a/src/SFileOpenArchive.cpp b/src/SFileOpenArchive.cpp index 6a249f2..2cb6698 100644 --- a/src/SFileOpenArchive.cpp +++ b/src/SFileOpenArchive.cpp @@ -369,8 +369,8 @@ bool WINAPI SFileOpenArchive(          // higher than 0x10000000, it would overflow in 32-bit version          // Observed in the malformed Warcraft III maps          // Example map: MPQ_2016_v1_ProtectedMap_TableSizeOverflow.w3x -        ha->pHeader->dwHashTableSize &= 0x0FFFFFFF; -        ha->pHeader->dwBlockTableSize &= 0x0FFFFFFF; +        ha->pHeader->dwBlockTableSize = MPQ_BLOCK_INDEX(ha->pHeader->dwBlockTableSize); +        ha->pHeader->dwHashTableSize = MPQ_BLOCK_INDEX(ha->pHeader->dwHashTableSize);          // Both MPQ_OPEN_NO_LISTFILE or MPQ_OPEN_NO_ATTRIBUTES trigger read only mode          if(dwFlags & (MPQ_OPEN_NO_LISTFILE | MPQ_OPEN_NO_ATTRIBUTES)) diff --git a/src/SFileOpenFileEx.cpp b/src/SFileOpenFileEx.cpp index 3794680..afbfc78 100644 --- a/src/SFileOpenFileEx.cpp +++ b/src/SFileOpenFileEx.cpp @@ -309,8 +309,10 @@ bool WINAPI SFileOpenFileEx(HANDLE hMpq, const char * szFileName, DWORD dwSearch      {          if(pFileEntry == NULL || (pFileEntry->dwFlags & MPQ_FILE_EXISTS) == 0)              nError = ERROR_FILE_NOT_FOUND; -        if(pFileEntry != NULL && pFileEntry->dwFlags & ~MPQ_FILE_VALID_FLAGS) -            nError = ERROR_NOT_SUPPORTED; + +        // Ignore unknown loading flags (example: MPQ_2016_v1_WME4_4.w3x) +//      if(pFileEntry != NULL && pFileEntry->dwFlags & ~MPQ_FILE_VALID_FLAGS) +//          nError = ERROR_NOT_SUPPORTED;      }      // Did the caller just wanted to know if the file exists? diff --git a/src/StormLib.h b/src/StormLib.h index 22658bd..c25a1a8 100644 --- a/src/StormLib.h +++ b/src/StormLib.h @@ -218,7 +218,6 @@ extern "C" {  #define MPQ_FILE_REPLACEEXISTING    0x80000000  // Replace when the file exist (SFileAddFile)  #define MPQ_FILE_COMPRESS_MASK      0x0000FF00  // Mask for a file being compressed -#define MPQ_FILE_EXISTS_MASK        0xF00000FF  // These must be either zero or MPQ_FILE_EXISTS  #define MPQ_FILE_VALID_FLAGS     (MPQ_FILE_IMPLODE       |  \                                    MPQ_FILE_COMPRESS      |  \ @@ -231,6 +230,8 @@ extern "C" {                                    MPQ_FILE_SIGNATURE     |  \                                    MPQ_FILE_EXISTS) +#define MPQ_BLOCK_INDEX(bi) ((bi) & 0x0FFFFFFF) // Index mask for block table index +  // Compression types for multiple compressions  #define MPQ_COMPRESSION_HUFFMANN          0x01  // Huffmann compression (used on WAVE files only)  #define MPQ_COMPRESSION_ZLIB              0x02  // ZLIB compression diff --git a/test/StormTest.cpp b/test/StormTest.cpp index f0456e7..2d73bd9 100644 --- a/test/StormTest.cpp +++ b/test/StormTest.cpp @@ -4273,11 +4273,11 @@ int main(int argc, char * argv[])      // Not a test, but rather a tool for creating links to duplicated files
  //  if(nError == ERROR_SUCCESS)
  //      nError = FindFilePairs(ForEachFile_CreateArchiveLink, "2004 - WoW\\06080", "2004 - WoW\\06299");
 -
 -    // Search all testing archives and verify their SHA1 hash
 -//  if(nError == ERROR_SUCCESS)
 -//      nError = FindFiles(ForEachFile_VerifyFileChecksum, szMpqSubDir);
  /*
 +    // Search all testing archives and verify their SHA1 hash
 +    if(nError == ERROR_SUCCESS)
 +        nError = FindFiles(ForEachFile_VerifyFileChecksum, szMpqSubDir);
 +
      // Test sparse compression
      if(nError == ERROR_SUCCESS)
          nError = TestSparseCompression();
 @@ -4456,10 +4456,17 @@ int main(int argc, char * argv[])      // Open another protected map
      if(nError == ERROR_SUCCESS)
          nError = TestOpenArchive("MPQ_2016_v1_ProtectedMap_HashOffsIsZero.w3x");
 -*/
 +
      // Something like Somj 2.0
      if(nError == ERROR_SUCCESS)
          nError = TestOpenArchive("MPQ_2016_v1_ProtectedMap_Somj2.w3x");
 +
 +    // Protector from China (2016-05-27)
 +    if(nError == ERROR_SUCCESS)
 +        nError = TestOpenArchive("MPQ_2016_v1_WME4_4.w3x");
 +*/
 +    if(nError == ERROR_SUCCESS)
 +        nError = TestOpenArchive("MPQ_2016_v1_AnotherProtectedMap.w3x");
  /*
      // Open the multi-file archive with wrong prefix to see how StormLib deals with it
      if(nError == ERROR_SUCCESS)
  | 
