private void InitiateMFT() { // Read first FileRecord _buffer = new byte[BytesPrFileRecord]; _diskStream.Seek((long)(_boot.MFTCluster * BytesPrCluster), SeekOrigin.Begin); _diskStream.Read(_buffer, 0, _buffer.Length); // Parse FileRecord record = FileRecord.Parse(_buffer, 0, _boot.BytesPrSector, _sectorsPrRecord); // TODO: Parse nonresident $DATA's _mftRecord = record; // Prep an NTFSDiskStream List <AttributeData> dataAttribs = _mftRecord.Attributes.OfType <AttributeData>().Where(s => s.AttributeName == string.Empty && s.NonResidentFlag == ResidentFlag.NonResident).ToList(); DataFragment[] fragments = dataAttribs.SelectMany(s => s.DataFragments).OrderBy(s => s.StartingVCN).ToArray(); ushort compressionUnitSize = dataAttribs[0].NonResidentHeader.CompressionUnitSize; ushort compressionClusterCount = (ushort)(compressionUnitSize == 0 ? 0 : Math.Pow(2, compressionUnitSize)); _mftStream = new NtfsDiskStream(_diskStream, false, fragments, BytesPrCluster, compressionClusterCount, (long)dataAttribs[0].NonResidentHeader.ContentSize); CurrentMftRecordNumber = 0; FileRecordCount = (uint)(_mftStream.Length / BytesPrFileRecord); }
public FileRecord ParseNextRecord() { Debug.Assert(_buffer.Length == BytesPrFileRecord); Debug.Assert(0 != BytesPrFileRecord); uint newPosition = CurrentMftRecordNumber * BytesPrFileRecord; if (_mftStream.Position != newPosition) { _mftStream.Seek(newPosition, SeekOrigin.Begin); } int read = _mftStream.Read(_buffer, 0, _buffer.Length); if (read == 0) { return(null); } // Parse FileRecord record = FileRecord.Parse(_buffer, 0, _boot.BytesPrSector, _sectorsPrRecord); // Increment number CurrentMftRecordNumber = record.MFTNumber + 1; return(record); }
static void Main(string[] args) { char driveLetter = 'C'; if (args.Length == 1) { driveLetter = args[0][0]; } using (RawDisk disk = new RawDisk(driveLetter)) { MftDiskExtents res = new MftDiskExtents(); byte[] ntfsBoot = disk.ReadSectors(0, 1); BootSector boot = BootSector.ParseData(ntfsBoot, ntfsBoot.Length, 0); Console.WriteLine("MFT is at LCN " + boot.MFTCluster); MftDetails mft = GetMftDetails(disk, boot); Console.WriteLine("MFT is in " + mft.MftExtents.Length + " extents"); res.Extents.AddRange(mft.MftExtents); using (RawDiskStream diskStream = disk.CreateDiskStream()) using (NtfsDiskStream mftStream = new NtfsDiskStream(diskStream, false, mft.MftExtents, (uint)disk.ClusterSize, 0, (long)mft.MftSize)) { uint sectorsPrRecord = (uint)(boot.MFTRecordSizeBytes / disk.SectorSize); ushort bytesPrSector = (ushort)disk.SectorSize; int records = (int)(mftStream.Length / boot.MFTRecordSizeBytes); byte[] tmp = new byte[boot.MFTRecordSizeBytes]; while (true) { int read = mftStream.Read(tmp, 0, tmp.Length); if (read < boot.MFTRecordSizeBytes) { Console.WriteLine("Stopped reading as we got " + read + " bytes instead of " + tmp.Length + " bytes"); break; } FileRecord rec = FileRecord.Parse(tmp, 0, bytesPrSector, sectorsPrRecord); // Keep track of all external extents to the MFT RecordExternalDiskExtents(rec, res); //// Special case for LIST attributes, since they can further reference more extents outside the MFT //ProcessNonResidentListAttributes(disk, rec); } } long clustersTotal = res.Extents.Sum(x => x.Clusters); Console.WriteLine("To copy: {0:N0} extents", res.Extents.Count); Console.WriteLine("{0:N0} clusters, {1:N0} bytes", clustersTotal, clustersTotal * disk.ClusterSize); } Console.ReadLine(); }
private static MftDetails GetMftDetails(RawDisk disk, BootSector boot) { byte[] mftFirst = disk.ReadClusters((long)boot.MFTCluster, 1); FileRecord rec = FileRecord.Parse(mftFirst, 0, (ushort)disk.SectorSize, (uint)(boot.MFTRecordSizeBytes / disk.SectorSize)); // Get DATA attrib // TODO: Handle multiple DATA attributes AttributeGeneric dataAttrib = null; foreach (Attribute attribute in rec.Attributes) { if (attribute.Type == AttributeType.DATA && attribute.AttributeName.Length == 0) { // Got it! dataAttrib = attribute as AttributeGeneric; break; } } Debug.Assert(dataAttrib != null); MftDetails res = new MftDetails(); // Get attribute data // Parse out extents if (dataAttrib.NonResidentFlag == ResidentFlag.Resident) { byte[] dataAttribData = dataAttrib.Data; res.MftSize = dataAttrib.ResidentHeader.ContentLength; res.MftExtents = DataFragment.ParseFragments(dataAttribData, dataAttribData.Length, 0, 0, 0); } else { res.MftSize = dataAttrib.NonResidentHeader.ContentSize; res.MftExtents = dataAttrib.NonResidentHeader.Fragments; } Debug.Assert(res.MftExtents != null); return(res); }
public FileRecord NextMFTRecord() { var newPosition = CurrentMftRecordNumber * BytesPerFileRecord; if (mftStream.Position != newPosition) { mftStream.Seek(newPosition, SeekOrigin.Begin); } var read = mftStream.Read(buffer, 0, buffer.Length); if (read == 0) { return(null); } var record = FileRecord.Parse(buffer, 0, BootSector.BytesPerSector, SectorsPerRecord); CurrentMftRecordNumber = record.MFTNumber + 1; return(record); }
private void ParseMft() { buffer = new byte[BytesPerFileRecord]; DiskStream.Seek((long)(BootSector.MftCluster * BytesPerCluster), SeekOrigin.Begin); DiskStream.Read(buffer, 0, buffer.Length); mftRecord = FileRecord.Parse(buffer, 0, BootSector.BytesPerSector, SectorsPerRecord); var fragmentList = new List <DataFragment>(); AttributeData firstAttributeData = null; foreach (var attribute in mftRecord.Attributes) { if (attribute is AttributeData data && data.AttributeName == string.Empty && data.NonResidentFlag == ResidentFlag.NonResident) { if (firstAttributeData == null) { firstAttributeData = data; } foreach (var frag in data.DataFragments) { fragmentList.Add(frag); } } } fragmentList = Utility.Util.Sort(fragmentList, new DataFragmentComparer()); ushort compressionUnitSize = firstAttributeData.NonResidentHeader.CompressionUnitSize; ushort compressionClusterCount = (ushort)(compressionUnitSize == 0 ? 0 : Math.Pow(2, compressionUnitSize)); mftStream = new NtfsDiskStream(DiskStream, false, fragmentList, BytesPerCluster, compressionClusterCount, (long)firstAttributeData.NonResidentHeader.ContentSize); CurrentMftRecordNumber = 0; FileRecordCount = (uint)(mftStream.Length / BytesPerFileRecord); Console.WriteLine("[NTFS DRIVER] " + FileRecordCount + " file records found"); }
private FileRecord ParseMFTRecord(byte[] data) { return(FileRecord.Parse(data, 0, Boot.BytesPrSector, _sectorsPrRecord)); }
public FileRecord ParseMftRecordData(byte[] data) { return(FileRecord.Parse(data, 0, BytesPerSector, SectorsPerRecord)); }