public PfsReader(IMemoryReader r, byte[] ekpfs = null) { reader = r; var buf = new byte[0x400]; reader.Read(0, buf, 0, 0x400); using (var ms = new MemoryStream(buf)) { hdr = PfsHeader.ReadFromStream(ms); } int dinodeSize; Func <Stream, inode> dinodeReader; if (hdr.Mode.HasFlag(PfsMode.Signed)) { dinodes = new DinodeS32[hdr.DinodeCount]; dinodeReader = DinodeS32.ReadFromStream; dinodeSize = 0x2C8; } else { dinodes = new DinodeD32[hdr.DinodeCount]; dinodeReader = DinodeD32.ReadFromStream; dinodeSize = 0xA8; } if (hdr.Mode.HasFlag(PfsMode.Encrypted)) { if (ekpfs == null) { throw new ArgumentException("PFS image is encrypted but no EKPFS was provided"); } var(tweakKey, dataKey) = Crypto.PfsGenEncKey(ekpfs, hdr.Seed); reader = new XtsDecryptReader(reader, dataKey, tweakKey, 16, 0x1000); } var total = 0; var maxPerSector = hdr.BlockSize / dinodeSize; sectorBuf = new byte[hdr.BlockSize]; sectorStream = new MemoryStream(sectorBuf); for (var i = 0; i < hdr.DinodeBlockCount; i++) { var position = hdr.BlockSize + hdr.BlockSize * i; reader.Read(position, sectorBuf, 0, sectorBuf.Length); sectorStream.Position = 0; for (var j = 0; j < maxPerSector && total < hdr.DinodeCount; j++) { dinodes[total++] = dinodeReader(sectorStream); } } root = LoadDir(0, null, ""); uroot = root.Get("uroot") as Dir; if (uroot == null) { throw new Exception("Invalid PFS image (no uroot)"); } uroot.parent = null; uroot.name = ""; }
public void Save(string path, bool decompress = false) { var buf = new byte[0x10000]; using (var file = System.IO.File.OpenWrite(path)) { var sz = size; file.SetLength(sz); long pos = 0; var reader = GetView(); if (decompress && size != compressed_size) { sz = compressed_size; reader = new PFSCReader(reader); } while (sz > 0) { var toRead = (int)Math.Min(sz, buf.Length); reader.Read(pos, buf, 0, toRead); file.Write(buf, 0, toRead); pos += toRead; sz -= toRead; } } }
public static void Read <T>(IMemoryReader reader, long pos, out T value) where T : struct { int sizeOfT = Marshal.SizeOf(typeof(T)); var buf = new byte[sizeOfT]; reader.Read(pos, buf, 0, sizeOfT); value = ByteArrayToStructure <T>(buf, 0); }
/// <summary> /// Precondition: activeSector is set /// Postconditions: /// - sectorOffset is reset to 0 /// - sectorBuf[] is filled with decrypted sector /// - position is updated /// </summary> private void ReadSectorBuffer(Ctx ctx, int currentSector, byte[] sectorBuf) { reader.Read(currentSector * sectorSize, sectorBuf, 0, (int)sectorSize); if (currentSector >= cryptStartSector) { DecryptSector(ctx, sectorBuf, (ulong)currentSector); } }
public static void ReadArray <T>(this IMemoryReader reader, long pos, T[] value, int offset, int count) where T : struct { // Fast path for bytes if (value is byte[] b) { reader.Read(pos, b, offset, count); return; } // Slow path int sizeOfT = Marshal.SizeOf(typeof(T)); var buf = new byte[sizeOfT * count]; reader.Read(pos, buf, 0, sizeOfT * count); for (var i = 0; i < count; i++) { value[i] = ByteArrayToStructure <T>(buf, i * sizeOfT); } }
public void Read(long pos, byte[] buf, int offset, int count) { var chunkIdx = pos / chunkSize; while (count > 0) { int offsetIntoChunk = (int)(pos % chunkSize); int toReadFromChunk = Math.Min(chunkSize - offsetIntoChunk, count); reader.Read((long)chunks[chunkIdx++] * chunkSize + offsetIntoChunk, buf, offset, count); pos += toReadFromChunk; offset += toReadFromChunk; count -= toReadFromChunk; } }
static public Boolean ToInt32(IMemoryReader tMemory, UInt32 tAddress, ref Int32 tData) { Boolean tResult = false; if (null == tMemory) { return(false); } Byte[] tBuffer = new Byte[4]; tResult = tMemory.Read(tAddress, ref tBuffer, 4); tData = BitConverter.ToInt32(tBuffer, 0); return(tResult); }
public void Read(long pos, byte[] buf, int offset, int count) { while (count > 0 && pos > 0) { if (bufferStart > pos || pos >= bufferStart + buffer.Length) { bufferStart = pos; reader.Read(pos, buffer, 0, buffer.Length); } int offsetIntoBuffer = (int)(pos - bufferStart); int toReadFromChunk = Math.Min(buffer.Length - offsetIntoBuffer, count); Buffer.BlockCopy(buffer, offsetIntoBuffer, buf, offset, toReadFromChunk); pos += toReadFromChunk; offset += toReadFromChunk; count -= toReadFromChunk; } }
void UpdateHexView() { if (xtsReader == null) { return; } var buf = new byte[header.BlockSize]; xtsReader.Read(header.BlockSize, buf, 0, buf.Length); var sb = new StringBuilder(); for (int i = 0; i < header.BlockSize; i++) { if (i != 0 && i % 16 == 0) { sb.AppendLine(); } sb.AppendFormat("{0:X2} ", buf[i]); } sectorPreview.Text = sb.ToString(); }
/// <summary> /// Searches memory from startAddress to endAddress, looking for the memory specified by `searchFor`. Note /// that this is NOT meant to be used to search the entire address space. This method will attempt to read /// all memory from startAddress to endAddress, so providing very large ranges of memory will make this take /// a long time. /// </summary> /// <param name="reader">The memory reader to search through.</param> /// <param name="startAddress">The address to start searching memory.</param> /// <param name="length">The length of memory to search.</param> /// <param name="searchFor">The memory to search for.</param> /// <returns>The address of the value if found, 0 if not found.</returns> public static ulong SearchMemory(this IMemoryReader reader, ulong startAddress, int length, ReadOnlySpan <byte> searchFor) { if (reader is null) { throw new ArgumentNullException(nameof(reader)); } // While not strictly disallowed, providing a sanity check to make sure the user isn't // searching from 0 to ulong.MaxValue is a good idea. if (startAddress == 0) { throw new ArgumentException($"{nameof(startAddress)} must be within allocated memory."); } if (length <= searchFor.Length) { return(0); } ulong endAddress = startAddress + (uint)length; // Reading memory is slow, we want to read in reasonably large chunks. byte[] array = ArrayPool <byte> .Shared.Rent(768 + searchFor.Length); try { while (startAddress < endAddress) { int bytesRemaining = (int)(endAddress - startAddress); if (bytesRemaining < searchFor.Length) { break; } Span <byte> buffer = array.AsSpan(0, Math.Min(bytesRemaining, array.Length)); if (!reader.Read(startAddress, buffer, out int read) || read < searchFor.Length) { startAddress += (uint)searchFor.Length; continue; } buffer = buffer.Slice(0, read); int index = buffer.IndexOf(searchFor); if (index >= 0) { return(startAddress + (uint)index); } // To keep the code simple, we'll re-read the last bit of the buffer each time instead of // block copying the leftover bits at the end and having to keep track of the buffer offset // along the way. int increment = buffer.Length - searchFor.Length; if (increment <= 0) { increment = searchFor.Length; } startAddress += (uint)increment; } } finally { ArrayPool <byte> .Shared.Return(array); } return(0); }
public void Read <T>(long pos, out T value) where T : struct { reader.Read(pos + offset, out value); }
public override ulong GetNextObjectAddress(ulong addr) { if (addr == 0) { return(0); } if (!ObjectRange.Contains(addr)) { throw new InvalidOperationException($"Segment [{FirstObjectAddress:x},{CommittedMemory:x}] does not contain object {addr:x}"); } bool large = IsLargeObjectSegment; uint minObjSize = (uint)IntPtr.Size * 3; IMemoryReader memoryReader = _helpers.DataReader; ulong mt = memoryReader.ReadPointer(addr); ClrType?type = _helpers.Factory.GetOrCreateType(Heap, mt, addr); if (type is null) { return(0); } ulong size; if (type.ComponentSize == 0) { size = (uint)type.StaticSize; } else { uint count = memoryReader.Read <uint>(addr + (uint)IntPtr.Size); // Strings in v4+ contain a trailing null terminator not accounted for. if (Heap.StringType == type) { count++; } size = count * (ulong)type.ComponentSize + (ulong)type.StaticSize; } size = ClrmdHeap.Align(size, large); if (size < minObjSize) { size = minObjSize; } ulong obj = addr + size; if (!large) { obj = _clrmdHeap.SkipAllocationContext(this, obj); // ignore mt here because it won't be used } if (obj >= End) { return(0); } int marker = GetMarkerIndex(obj); if (marker != -1 && _markers[marker] == 0) { _markers[marker] = obj; } return(obj); }