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); } }
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"); }
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); }
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); } }
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; }
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..];