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   = "";
        }
Exemple #2
0
            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;
                    }
                }
            }
Exemple #3
0
        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);
        }
Exemple #4
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);
     }
 }
Exemple #5
0
        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);
            }
        }
Exemple #6
0
        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);
        }
Exemple #8
0
 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;
     }
 }
Exemple #9
0
        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();
        }
Exemple #10
0
        /// <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);
        }
Exemple #11
0
 public void Read <T>(long pos, out T value) where T : struct
 {
     reader.Read(pos + offset, out value);
 }
Exemple #12
0
        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);
        }