Exemplo n.º 1
0
        private TellTaleFileStructureInfo PrepareFileInfo(BinReader reader)
        {
            var result = new TellTaleFileStructureInfo();

            result.FileVersion = 10;

            // For neatness, we reset to start of file, but skipping the format FourCC.
            reader.Position = 4;

            result.BlockSizeUncompressed = reader.ReadU32LE();
            uint blockCount = reader.ReadU32LE();

            ulong blockOffset = reader.ReadU64LE(); // first block offset

            result.VirtualBlocksOffset = blockOffset;

            for (int i = 0; i < blockCount; i++)
            {
                ulong nextBlockOffset = reader.ReadU64LE();
                result.BlockOffsets.Add(blockOffset);
                result.BlockSizesCompressed.Add((uint)(nextBlockOffset - blockOffset));
                blockOffset = nextBlockOffset;
            }

            return(result);
        }
Exemplo n.º 2
0
        protected override Stream CreateStream(string path)
        {
            var fileStream = File.OpenRead(path);

            using (BinReader reader = new BinReader(fileStream))
            {
                TellTaleFileStructureInfo fileInfo = PrepareFileInfo(reader);
                if (fileInfo == null)
                {
                    return(null);
                }
                byte[] key = FindKey(reader, fileInfo, TellTaleKeyManager.Instance.KeysTTArch);
                // TODO: Make sure key was found
                return(new TellTaleBlowfishZlibStream(fileStream, fileInfo, key, fileInfo.FileVersion >= 7));
            }
        }
Exemplo n.º 3
0
        private byte[] FindKey(BinReader reader, TellTaleFileStructureInfo fileInfo, IEnumerable <TellTaleKeyInfo> keys)
        {
            const int decompressSize = 4;
            const int readSize       = 4096;

            byte[] readBytes    = new byte[readSize];
            byte[] testBytes    = new byte[readSize];
            byte[] deflateBytes = new byte[decompressSize];
            reader.Position = fileInfo.VirtualBlocksOffset;
            reader.Read(readBytes, 0, readSize);

            using (MemoryStream stream = new MemoryStream(testBytes))
            {
                foreach (var info in keys)
                {
                    var testBlowfish = new Blowfish(info.Key, true);
                    testBlowfish.Decipher(readBytes, testBytes, readSize);

                    stream.Position = 0;
                    using (DeflateStream deflateStream = new DeflateStream(stream, CompressionMode.Decompress, true))
                    {
                        try
                        {
                            int bytesRead = 0;
                            // FIXME: Sometimes DeflateStream.Read reads 0 bytes...
                            while (bytesRead == 0)
                            {
                                bytesRead = deflateStream.Read(deflateBytes, 0, decompressSize);
                            }
                        }
                        catch (InvalidDataException)
                        {
                            // Since a wrong key may cause invalid zlib input,
                            // we catch the exception for that, and continue to the next key
                            continue;
                        }
                    }
                    if (deflateBytes[0] == '3' && deflateBytes[1] == 'A' && deflateBytes[2] == 'T' &&
                        deflateBytes[3] == 'T')
                    {
                        return(info.Key);
                    }
                }
            }
            return(null);
        }
Exemplo n.º 4
0
        private byte[] FindKey(BinReader reader, TellTaleFileStructureInfo fileInfo, IEnumerable <TellTaleKeyInfo> keys)
        {
            // ttarch1 doesn't have a nice magic FourCC to check for.
            // Instead, we have two possibilities:
            // - if the info block is encrypted, we can check if it follows known info block "rules":
            //   - its folder count is a small number (usually 1 or 2)
            //   - its folder name lengths aren't insane
            //   - its folder names decode to typical ASCII characters
            //   - etc.
            // - if it's not, we can instead check if the first block starts with something we can recognize

            if (fileInfo.IsInfoEncrypted)
            {
                return(DetermineKeyByInfoTable(reader, fileInfo, keys));
            }
            else
            {
                return(DetermineKeyByFirstBlock(reader, fileInfo, keys));
            }
        }
Exemplo n.º 5
0
        private static byte[] DetermineKeyByInfoTable(BinReader reader, TellTaleFileStructureInfo fileInfo, IEnumerable <TellTaleKeyInfo> keys)
        {
            byte[] encryptedTable = fileInfo.ReadInfoBlock(reader, null);
            byte[] decryptedTable = new byte[encryptedTable.Length];

            foreach (var info in keys)
            {
                var blowfish = new Blowfish(info.Key, fileInfo.FileVersion >= 7);
                blowfish.Decipher(encryptedTable, decryptedTable, (uint)(encryptedTable.Length / 8) * 8);

                // Now we do our assertions which should be true if the key was right:
                using (MemoryStream infoStream = new MemoryStream(decryptedTable))
                {
                    using (var infoReader = new BinReader(infoStream))
                    {
                        uint folderCount = infoReader.ReadU32LE();
                        // The maximum number of folders is somewhat arbitrary.
                        // In games tested, I haven't seen folder counts this high.
                        if (folderCount > 128)
                        {
                            Trace.TraceInformation("Key check - folder count: {0}", folderCount);
                            continue;
                        }

                        // We just check the first folder:
                        uint nameSize = infoReader.ReadU32LE();
                        if (nameSize > 300)
                        {
                            Trace.TraceInformation("Key check - folder name size: {0}", nameSize);
                            continue;
                        }

                        return(info.Key);
                    }
                }
            }

            return(null);
        }
Exemplo n.º 6
0
        protected override Stream CreateStream(string path)
        {
            var fileStream = File.OpenRead(path);

            using (BinReader reader = new BinReader(fileStream))
            {
                FourCC fourCC = reader.ReadFourCC();
                switch (fourCC.Name)
                {
                case "ECTT":
                    // Compressed and encrypted
                    TellTaleFileStructureInfo fileInfo = PrepareFileInfo(reader);
                    byte[] key = FindKey(reader, fileInfo, TellTaleKeyManager.Instance.KeysTTArch2);
                    if (key == null)
                    {
                        throw new ScummRevisitedException("Couldn't determine blowfish key");
                    }
                    // ttarch2 always uses modified blowfish algorithm
                    return(new TellTaleBlowfishZlibStream(fileStream, fileInfo, key, true));

                case "ZCTT":
                    // Compressed and unencrypted
                    fileInfo = PrepareFileInfo(reader);
                    return(new TellTaleBlowfishZlibStream(fileStream, fileInfo));

                case "3ATT":
                case "NCTT":
                    // Uncompressed and unencrypted
                    return(fileStream);

                default:
                    // not TTARCH2
                    fileStream.Dispose();
                    return(null);
                }
            }
        }
Exemplo n.º 7
0
 private static byte[] DetermineKeyByFirstBlock(BinReader reader, TellTaleFileStructureInfo fileInfo, IEnumerable <TellTaleKeyInfo> keys)
 {
     // TODO: Implement key finding
     return(HexUtils.StringToByteArray(KEY));
 }
Exemplo n.º 8
0
        public static TellTaleFileStructureInfo PrepareFileInfo(BinReader reader)
        {
            var result = new TellTaleFileStructureInfo();

            // For neatness, we reset to start of file, but skipping the format FourCC.
            reader.Position = 0;

            result.FileVersion = reader.ReadU32LE();
            uint infoEncrypted = reader.ReadU32LE();

            if (result.FileVersion > 9 || infoEncrypted > 1)
            {
                // Not a ttarch file, or unsupported
                return(null);
            }

            uint type3 = reader.ReadU32LE();

            uint filesFormat = 0;
            uint blockCount  = 0;
            uint dataSize    = 0;
            uint unknown1    = 0;
            uint unknown2    = 0;
            uint unknown3    = 0;
            uint unknown4    = 0;
            byte unknown5    = 0;
            uint unknown6    = 0;

            ulong[] blockOffsets = null;

            if (result.FileVersion >= 3)
            {
                filesFormat = reader.ReadU32LE();
                blockCount  = reader.ReadU32LE();

                blockOffsets = new ulong[blockCount];
                if (blockCount > 0)
                {
                    ulong blockOffset = 0;
                    for (int i = 0; i < blockCount; i++)
                    {
                        uint size = reader.ReadU32LE();
                        result.BlockSizesCompressed.Add(size);
                        blockOffsets[i] = blockOffset;
                        blockOffset    += size;
                    }
                }

                dataSize = reader.ReadU32LE();
            }

            if (result.FileVersion >= 4)
            {
                unknown1 = reader.ReadU32LE();
                unknown2 = reader.ReadU32LE();
            }
            if (result.FileVersion >= 7)
            {
                unknown3 = reader.ReadU32LE();
                unknown4 = reader.ReadU32LE();
                result.BlockSizeUncompressed = reader.ReadU32LE() * 1024;
            }
            if (result.FileVersion >= 8)
            {
                unknown5 = reader.ReadU8();
            }
            if (result.FileVersion >= 9)
            {
                unknown6 = reader.ReadU32LE();
            }

            result.HasInfo         = true;
            result.IsInfoEncrypted = infoEncrypted == 1;

            result.InfoSizeUncompressed = reader.ReadU32LE();

            if (result.FileVersion >= 7 && filesFormat == 2)
            {
                result.IsInfoCompressed   = true;
                result.InfoSizeCompressed = reader.ReadU32LE();
            }
            else
            {
                result.InfoSizeCompressed = result.InfoSizeUncompressed;
            }

            result.InfoOffset          = reader.Position;
            result.VirtualBlocksOffset = reader.Position + result.InfoSizeUncompressed;
            ulong blocksOffset = reader.Position + result.InfoSizeCompressed;

            for (var i = 0; i < blockCount; i++)
            {
                result.BlockOffsets.Add(blockOffsets[i] + blocksOffset);
            }

            return(result);
        }