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(); }
internal override void ParseAttributeNonResidentBody(RawDisk disk) { base.ParseAttributeNonResidentBody(disk); // Read clusters from disk Data = new byte[NonResidentHeader.ContentSize]; using (RawDiskStream diskStream = disk.CreateDiskStream()) using (NtfsDiskStream attribStream = new NtfsDiskStream(diskStream, false, NonResidentHeader.Fragments, (uint)disk.ClusterSize, 0, Data.LongLength)) attribStream.Read(Data, 0, Data.Length); }
public static byte[] ReadFragments(INTFSInfo ntfsInfo, DataFragment[] fragments) { int totalLength = (int)(fragments.Sum(s => (decimal)s.Clusters) * ntfsInfo.BytesPrCluster); byte[] data = new byte[totalLength]; Stream diskStream = ntfsInfo.GetDiskStream(); using (NtfsDiskStream stream = new NtfsDiskStream(diskStream, ntfsInfo.OwnsDiskStream, fragments, ntfsInfo.BytesPrCluster, 0, totalLength)) { stream.Read(data, 0, data.Length); } // Return the data return(data); }
public static byte[] ReadFragments(RawDisk disk, DataFragment[] fragments) { int totalLength = 0; foreach (DataFragment fragment in fragments) { totalLength += (int)(fragment.Clusters * disk.ClusterSize); } byte[] data = new byte[totalLength]; using (Stream diskStream = disk.CreateDiskStream()) using (NtfsDiskStream stream = new NtfsDiskStream(diskStream, false, fragments, (uint)disk.ClusterSize, 0, totalLength)) { stream.Read(data, 0, data.Length); } // Return the data return(data); }
public static byte[] ReadFragments(Ntfs ntfsInfo, List <DataFragment> fragments) { long totalLength = 0; foreach (var frag in fragments) { totalLength += frag.Clusters * ntfsInfo.BytesPerCluster; } var data = new byte[totalLength]; Stream diskStream = ntfsInfo.DiskStream; using (NtfsDiskStream stream = new NtfsDiskStream(diskStream, false, fragments, ntfsInfo.BytesPerCluster, 0, totalLength)) { stream.Read(data, 0, data.Length); } // Return the data return(data); }
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 static void PerformCopy(NTFSWrapper wrapper, Options opts, uint mftId) { // Fetch record FileRecord record = wrapper.ReadMFTRecord(mftId); // Find attribute(s) List <Attribute> attribs = record.Attributes.Concat(record.ExternalAttributes).Where(s => s.Type == opts.SourceAttribute && s.AttributeName == opts.SourceName).ToList(); if (!attribs.Any()) { PrintError("Unable to find any attribute named \"" + opts.SourceName + "\" of type " + opts.SourceAttribute); AwesomeConsole.WriteLine(); return; } // Determine resident or non-resident data Stream fileStream = null; if (attribs.All(x => x.NonResidentFlag == ResidentFlag.NonResident)) { // Fetch fragments DataFragment[] fragments = attribs.SelectMany(s => s.NonResidentHeader.Fragments).OrderBy(s => s.StartingVCN).ToArray(); ushort compressionUnitSize = attribs[0].NonResidentHeader.CompressionUnitSize; ushort compressionClusterCount = (ushort)(compressionUnitSize == 0 ? 0 : Math.Pow(2, compressionUnitSize)); fileStream = new NtfsDiskStream(wrapper.GetDiskStream(), true, fragments, wrapper.BytesPrCluster, compressionClusterCount, (long)attribs.First().NonResidentHeader.ContentSize); } else { // Fetch data if (attribs.Count != 1) { PrintError("There were multiple attributes for this single file that matched, yet they were all Resident. This is an error."); AwesomeConsole.WriteLine(); return; } Attribute attrib = attribs.First(); if (attrib is AttributeGeneric) { AttributeGeneric generic = (AttributeGeneric)attrib; fileStream = new MemoryStream(generic.Data); } else if (attrib is AttributeData) { AttributeData data = (AttributeData)attrib; fileStream = new MemoryStream(data.DataBytes); } else { PrintError("Only certain resident attributes are supported, like $DATA"); AwesomeConsole.WriteLine(); return; } } // Perform copy using (AwesomeConsole.BeginSequentialWrite()) { AwesomeConsole.Write("Found data, copying "); AwesomeConsole.Write(fileStream.Length.ToString("N0"), ConsoleColor.Green); AwesomeConsole.Write(" bytes to "); AwesomeConsole.WriteLine(opts.Destination, ConsoleColor.Green); } using (FileStream fs = File.OpenWrite(opts.Destination)) { if (fs.CanSeek && fs.CanWrite) { // Pre-expand the destination, to help filesystems allocate files fs.SetLength(fileStream.Length); } byte[] buff = new byte[65535]; int lastProgressed = -1; for (long offset = 0; offset < fileStream.Length; offset += buff.Length) { int read = fileStream.Read(buff, 0, buff.Length); if (read == 0) { // Finished break; } fs.Write(buff, 0, read); int progressed = (int)((offset * 1f / fileStream.Length) * 20); if (read != buff.Length) { // Finished progressed = 20; } if (lastProgressed != progressed) { AwesomeConsole.Write("["); for (int i = 0; i < 20; i++) { if (i < progressed) { AwesomeConsole.Write("="); } else if (i == progressed) { AwesomeConsole.Write(">"); } else { AwesomeConsole.Write(" "); } } AwesomeConsole.Write("]"); Console.CursorLeft = 0; lastProgressed = progressed; } } AwesomeConsole.WriteLine(); AwesomeConsole.WriteLine("Done.", ConsoleColor.Green); } }