예제 #1
0
        public bool TestAesKey(byte[] bytes, byte[] key)
        {
            BinaryReader IndexReader = new BinaryReader(new MemoryStream(AESDecryptor.DecryptAES(bytes, key)));
            int          stringLen   = IndexReader.ReadInt32();

            if (stringLen > 128 || stringLen < -128)
            {
                return(false);
            }
            if (stringLen == 0)
            {
                return(IndexReader.ReadUInt16() == 0);
            }
            if (stringLen < 0)
            {
                int nullTerminatedPos = 4 - (stringLen - 1) * 2;
                IndexReader.BaseStream.Seek(nullTerminatedPos, SeekOrigin.Begin);
                return(IndexReader.ReadInt16() == 0);
            }
            else
            {
                int nullTerminatedPos = 4 + stringLen - 1;
                IndexReader.BaseStream.Seek(nullTerminatedPos, SeekOrigin.Begin);
                return(IndexReader.ReadSByte() == 0);
            }
        }
예제 #2
0
 public ArraySegment <byte> GetData(Stream stream, byte[] key, string[] compressionMethods)
 {
     lock (stream)
     {
         if (CompressionMethodIndex == 0U)
         {
             stream.Position = Offset + StructSize;
             if (Encrypted)
             {
                 var data = new byte[(Size & 15) == 0 ? Size : (Size / 16 + 1) * 16];
                 stream.Read(data, 0, data.Length);
                 return(new ArraySegment <byte>(AESDecryptor.DecryptAES(data, key), 0, (int)UncompressedSize));
             }
             else
             {
                 var data = new byte[UncompressedSize];
                 stream.Read(data, 0, data.Length);
                 return(new ArraySegment <byte>(data));
             }
         }
         else
         {
             var data = new byte[UncompressedSize];
             Decompress(stream, key, compressionMethods, data);
             return(new ArraySegment <byte>(data));
         }
     }
     throw new NotImplementedException("Decompression not yet implemented");
 }
예제 #3
0
 bool DecryptAndValidateIndex(ref byte[] IndexData, byte[] aesKey, FSHAHash ExpectedHash, out FSHAHash OutHash)
 {
     if (Info.bEncryptedIndex)
     {
         IndexData = AESDecryptor.DecryptAES(IndexData, aesKey);
     }
     OutHash = ExpectedHash; // too lazy to actually check against the hash
     // https://github.com/EpicGames/UnrealEngine/blob/79a64829237ae339118bb50b61d84e4599c14e8a/Engine/Source/Runtime/PakFile/Private/IPlatformFilePak.cpp#L5371
     return(true);
 }
예제 #4
0
        private void Decompress(Stream stream, byte[] key, string[] compressionMethods, byte[] outData)
        {
            if (compressionMethods == null || compressionMethods.Length == 0)
            {
                throw new ArgumentOutOfRangeException(nameof(compressionMethods), "CompressionMethods are null or empty");
            }

            string compressionMethod = compressionMethods[CompressionMethodIndex - 1]; // -1 because we dont have 'NAME_None' in the array
            int    bytesRead         = 0;

            for (int i = 0; i < CompressionBlocks.Length; i++)
            {
                stream.Position = Offset + CompressionBlocks[i].CompressedStart;
                int uncompressedSize = (int)Math.Min(CompressionBlockSize, outData.Length - bytesRead);

                byte[] blockBbuffer;
                if (Encrypted)
                {
                    blockBbuffer = new byte[BinaryHelper.Align(CompressionBlocks[i].Size, AESDecryptor.BLOCK_SIZE)];
                    stream.Read(blockBbuffer, 0, blockBbuffer.Length);
                    blockBbuffer = AESDecryptor.DecryptAES(blockBbuffer, key);
                }
                else
                {
                    blockBbuffer = new byte[CompressionBlocks[i].Size];
                    stream.Read(blockBbuffer, 0, blockBbuffer.Length);
                }

                using var blockMs = new MemoryStream(blockBbuffer, false);
                using Stream compressionStream = compressionMethod switch
                      {
                          "Zlib" => new ZlibStream(blockMs, CompressionMode.Decompress),
                          "Gzip" => new GZipStream(blockMs, CompressionMode.Decompress),
                          "Oodle" => new OodleStream(blockBbuffer, uncompressedSize),
                          _ => throw new NotImplementedException($"Decompression not yet implemented ({compressionMethod})")
                      };

                bytesRead += compressionStream.Read(outData, bytesRead, uncompressedSize);
            }
        }
예제 #5
0
        void ReadIndexInternal(byte[] key, PakFilter filter, out Exception exc)
        {
            if (Initialized)
            {
                exc = new InvalidOperationException("Index is already initialized");
                return;
            }

            if (Info.bEncryptedIndex && key == null)
            {
                exc = new ArgumentException("Index is encrypted but no key was provided", nameof(key));
                return;
            }

            Stream.Position = Info.IndexOffset;

            BinaryReader IndexReader;

            if (Info.bEncryptedIndex)
            {
                IndexReader = new BinaryReader(new MemoryStream(AESDecryptor.DecryptAES(Reader.ReadBytes((int)Info.IndexSize), key)));
                int stringLen = IndexReader.ReadInt32();
                if (stringLen > 512 || stringLen < -512)
                {
                    exc = new ArgumentException("The provided key is invalid", nameof(key));
                    return;
                }
                if (stringLen < 0)
                {
                    IndexReader.BaseStream.Position += (stringLen - 1) * 2;
                    if (IndexReader.ReadUInt16() != 0)
                    {
                        exc = new ArgumentException("The provided key is invalid", nameof(key));
                        return;
                    }
                }
                else
                {
                    IndexReader.BaseStream.Position += stringLen - 1;
                    if (IndexReader.ReadByte() != 0)
                    {
                        exc = new ArgumentException("The provided key is invalid", nameof(key));
                        return;
                    }
                }
                IndexReader.BaseStream.Position = 0;
            }
            else
            {
                IndexReader = Reader;
            }

            Dictionary <string, FPakEntry> tempFiles;

            if (Info.Version >= EPakVersion.PATH_HASH_INDEX)
            {
                ReadIndexUpdated(IndexReader, key, out tempFiles, filter);
            }
            else
            {
                // https://github.com/EpicGames/UnrealEngine/blob/bf95c2cbc703123e08ab54e3ceccdd47e48d224a/Engine/Source/Runtime/PakFile/Private/IPlatformFilePak.cpp#L4509
                MountPoint = IndexReader.ReadFString();
                if (MountPoint.StartsWith("../../.."))
                {
                    MountPoint = MountPoint.Substring(8);
                }
                else
                {
                    // Weird mount point location...
                    MountPoint = "/";
                }
                if (!CaseSensitive)
                {
                    MountPoint = MountPoint.ToLowerInvariant();
                }

                var NumEntries = IndexReader.ReadInt32();
                tempFiles = new Dictionary <string, FPakEntry>(NumEntries);
                for (int i = 0; i < NumEntries; i++)
                {
                    var entry = new FPakEntry(IndexReader, Info.Version, CaseSensitive, FileName);
                    // if there is no filter OR the filter passes
                    if (filter == null || filter.CheckFilter(MountPoint + entry.Name, CaseSensitive))
                    {
                        // Filename is without the MountPoint concatenated to save memory
                        tempFiles[entry.Name] = entry;
                    }
                }
            }

            Paks.Merge(tempFiles, out var files, MountPoint);
            Entries = files;

            DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[PakFileReader]", "[ReadIndexInternal]", $"{FileName} contains {Entries.Count} files, mount point: \"{this.MountPoint}\", version: {(int)this.Info.Version}");

            if (Info.bEncryptedIndex)
            {
                // underlying stream is a MemoryStream of the decrypted index, might improve performance with a crypto stream of some sort
                IndexReader.Dispose();
            }

            Reader.Dispose();
            Initialized = true;
            exc         = null;
        }
예제 #6
0
        void ReadIndexInternal(byte[] key, PakFilter filter, out Exception exc)
        {
            if (Initialized)
            {
                exc = new InvalidOperationException("Index is already initialized");
                return;
            }

            if (Info.bEncryptedIndex && key == null)
            {
                exc = new ArgumentException("Index is encrypted but no key was provided", nameof(key));
                return;
            }

            Stream.Position = Info.IndexOffset;

            BinaryReader IndexReader;

            if (Info.bEncryptedIndex)
            {
                IndexReader = new BinaryReader(new MemoryStream(AESDecryptor.DecryptAES(Reader.ReadBytes((int)Info.IndexSize), key)));
                int stringLen = IndexReader.ReadInt32();
                if (stringLen > 512 || stringLen < -512)
                {
                    exc = new ArgumentException("The provided key is invalid", nameof(key));
                    return;
                }
                if (stringLen < 0)
                {
                    IndexReader.BaseStream.Position += (stringLen - 1) * 2;
                    if (IndexReader.ReadUInt16() != 0)
                    {
                        exc = new ArgumentException("The provided key is invalid", nameof(key));
                        return;
                    }
                }
                else
                {
                    IndexReader.BaseStream.Position += stringLen - 1;
                    if (IndexReader.ReadByte() != 0)
                    {
                        exc = new ArgumentException("The provided key is invalid", nameof(key));
                        return;
                    }
                }
                IndexReader.BaseStream.Position = 0;
            }
            else
            {
                IndexReader = Reader;
            }

            Dictionary <string, FPakEntry> tempFiles;

            if (Info.Version >= EPakVersion.PATH_HASH_INDEX)
            {
                ReadIndexUpdated(IndexReader, key, out tempFiles, filter);
            }
            else
            {
                // https://github.com/EpicGames/UnrealEngine/blob/bf95c2cbc703123e08ab54e3ceccdd47e48d224a/Engine/Source/Runtime/PakFile/Private/IPlatformFilePak.cpp#L4509
                MountPoint = IndexReader.ReadFString() ?? "";
                if (MountPoint.StartsWith("../../.."))
                {
                    MountPoint = MountPoint[8..];