internal static NtfsFileEntry CreateEntry(NTFSWrapper ntfsWrapper, uint fileId, AttributeFileName fileName = null) { if (fileName == null) { // Dig up a preferred name FileRecord tmpRecord = ntfsWrapper.ReadMFTRecord(fileId); fileName = NtfsUtils.GetPreferredDisplayName(tmpRecord); } NtfsFileEntry entry = ntfsWrapper.FileCache.Get(fileId, fileName.FileName.GetHashCode()); if (entry != null) { Debug.WriteLine("Got from cache: " + fileId + ":" + fileName.Id); return(entry); } // Create it FileRecord record = ntfsWrapper.ReadMFTRecord(fileId); if (record.Flags.HasFlag(FileEntryFlags.Directory)) { entry = new NtfsDirectory(ntfsWrapper, record, fileName); } else { entry = new NtfsFile(ntfsWrapper, record, fileName); } ntfsWrapper.FileCache.Set(fileId, fileName.Id, entry); return(entry); }
private static void PrintPaths(RawDisk disk, Options options) { uint mftId = uint.MaxValue; if (options.PathType == PathType.MftId) { AwesomeConsole.WriteLine("Specified an Mft Id - skipping forward-only search", ConsoleColor.DarkGreen); mftId = options.MftId; } else if (options.PathType == PathType.File || options.PathType == PathType.Directory) { AwesomeConsole.WriteLine("Conducting forward-only path search", ConsoleColor.Green); string[] pathParts = options.PathArgument.Split(new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries); string[] pathParents = pathParts.Skip(1).Take(pathParts.Length - 2).ToArray(); NTFSWrapper ntfs = new NTFSWrapper(new NTFSDiskProvider(disk), 4); NtfsDirectory dir = ntfs.GetRootDirectory(); PrintName(dir.Name); AwesomeConsole.Write(" "); PrintReference(dir.MFTRecord.FileReference); AwesomeConsole.WriteLine(); string pathSoFar = options.Drive + ":\\"; for (int i = 0; i < pathParents.Length; i++) { AwesomeConsole.Write(pathSoFar, ConsoleColor.DarkYellow); if (dir == null) { PrintName(pathParents[i]); AwesomeConsole.Write(" "); PrintError("(Unable to find parent)"); AwesomeConsole.WriteLine(); } else { dir = dir.ListDirectories(false).FirstOrDefault(s => s.Name.Equals(pathParents[i], StringComparison.InvariantCultureIgnoreCase)); if (dir == null) { PrintName(pathParents[i]); AwesomeConsole.Write(" "); PrintError("(Unable to find this)"); AwesomeConsole.WriteLine(); } else { PrintName(dir.Name); AwesomeConsole.Write(" "); PrintReference(dir.MFTRecord.FileReference); AwesomeConsole.WriteLine(); } } pathSoFar = Path.Combine(pathSoFar, pathParents[i] + "\\"); } AwesomeConsole.Write(pathSoFar, ConsoleColor.DarkYellow); if (dir == null) { PrintName(pathParts.Last()); AwesomeConsole.Write(" "); PrintError("(Unable to find parent)"); AwesomeConsole.WriteLine(); } else { IEnumerable <NtfsFileEntry> childs = options.PathType == PathType.File ? (IEnumerable <NtfsFileEntry>)dir.ListFiles(false) : dir.ListDirectories(false); NtfsFileEntry child = childs.FirstOrDefault(s => s.Name.Equals(pathParts.Last(), StringComparison.InvariantCultureIgnoreCase)); if (child == null) { PrintName(pathParts.Last()); AwesomeConsole.Write(" "); PrintError("(Unable to find this)"); AwesomeConsole.WriteLine(); } else { PrintName(child.Name); AwesomeConsole.Write(" "); PrintReference(child.MFTRecord.FileReference); AwesomeConsole.WriteLine(); mftId = child.MFTRecord.MFTNumber; AwesomeConsole.WriteLine("Search completed, found MftId: " + mftId); } } } AwesomeConsole.WriteLine(); { NTFSWrapper wrapper = new NTFSWrapper(new NTFSDiskProvider(disk), 4); if (wrapper.FileRecordCount < mftId) { PrintError("Unable to locate the specified file, aborting."); AwesomeConsole.WriteLine(); return; } AwesomeConsole.WriteLine("Conducting backwards-only path search", ConsoleColor.Green); Dictionary <uint, List <string> > paths = new Dictionary <uint, List <string> >(); List <string> finalPaths = new List <string>(); FileRecord baseRecord = wrapper.ReadMFTRecord(mftId); foreach (AttributeFileName fileName in baseRecord.Attributes.OfType <AttributeFileName>().Concat(baseRecord.ExternalAttributes.OfType <AttributeFileName>())) { uint parentId = fileName.ParentDirectory.FileId; if (paths.ContainsKey(parentId)) { paths[parentId].Add(fileName.FileName); } else { paths[parentId] = new List <string> { fileName.FileName } }; } do { Dictionary <uint, List <string> > newPaths = new Dictionary <uint, List <string> >(); foreach (KeyValuePair <uint, List <string> > keyValuePair in paths) { if (keyValuePair.Key == (uint)SpecialMFTFiles.RootDir) { finalPaths.AddRange(keyValuePair.Value.Select(s => Path.Combine(options.Drive + ":\\", s))); } else { FileRecord record = wrapper.ReadMFTRecord(keyValuePair.Key); foreach (AttributeFileName fileName in record.Attributes.OfType <AttributeFileName>().Concat(record.ExternalAttributes.OfType <AttributeFileName>())) { uint parentId = fileName.ParentDirectory.FileId; if (newPaths.ContainsKey(parentId)) { newPaths[parentId].AddRange(keyValuePair.Value.Select(s => Path.Combine(fileName.FileName, s))); } else { newPaths[parentId] = new List <string>(keyValuePair.Value.Select(s => Path.Combine(fileName.FileName, s))); } } } } paths = newPaths; } while (paths.Any()); AwesomeConsole.WriteLine("Got " + finalPaths.Count + " paths"); foreach (string finalPath in finalPaths) { PrintName(finalPath); AwesomeConsole.WriteLine(); } } }
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); } }
static void Main(string[] args) { const char driveLetter = 'E'; RawDisk disk = new RawDisk(driveLetter); using (Stream stream = disk.CreateDiskStream()) using (Stream streama = disk.CreateDiskStream()) { NTFSParser parser = new NTFSParser(stream); NTFSParser parsera = new NTFSParser(streama); int longest = 0; foreach (FileRecord record in parser.GetRecords(true)) { int count = record.Attributes.Count; if (count > longest) { longest = count; Console.WriteLine(record.FileReference + " - " + count); } } } NTFSDiskProvider provider = new NTFSDiskProvider(disk); NTFSWrapper ntfsWrapper = new NTFSWrapper(provider, 524288); ntfsWrapper.InitializeCommon(); Console.WriteLine("Read NTFS. Version: " + ntfsWrapper.NTFSVersion); // Filerecord bitmap ntfsWrapper.ParseNonResidentAttribute(ntfsWrapper.FileMFT.Attributes.OfType <AttributeBitmap>().Single()); BitArray bitmapData = ntfsWrapper.FileMFT.Attributes.OfType <AttributeBitmap>().Single().Bitfield; HashSet <AttributeType> types = new HashSet <AttributeType>(); // Read fragmented file for (uint i = 0; i < ntfsWrapper.FileRecordCount; i++) { if (!ntfsWrapper.InRawDiskCache(i)) { ntfsWrapper.PrepRawDiskCache(i); } if (!bitmapData[(int)i]) { continue; } FileRecord record = ntfsWrapper.ReadMFTRecord(i); if (record.Flags.HasFlag(FileEntryFlags.FileInUse)) { ntfsWrapper.ParseNonResidentAttributes(record); } Console.Write("Read {0:N0} of {1:N0} - ({2:N0} bytes {3:N0} allocated)", i, ntfsWrapper.FileRecordCount, record.SizeOfFileRecord, record.SizeOfFileRecordAllocated); if (record.Flags.HasFlag(FileEntryFlags.FileInUse)) { Console.ForegroundColor = ConsoleColor.Magenta; Console.Write(" (InUse)"); Console.ForegroundColor = ConsoleColor.Gray; } else { Console.ForegroundColor = ConsoleColor.DarkMagenta; Console.Write(" (Not InUse)"); Console.ForegroundColor = ConsoleColor.Gray; } if (bitmapData[(int)i]) { Console.ForegroundColor = ConsoleColor.Magenta; Console.Write(" (Bitmap:InUse)"); Console.ForegroundColor = ConsoleColor.Gray; } else { Console.ForegroundColor = ConsoleColor.DarkMagenta; Console.Write(" (Bitmap:Not InUse)"); Console.ForegroundColor = ConsoleColor.Gray; } if (record.Flags.HasFlag(FileEntryFlags.Directory)) { Console.ForegroundColor = ConsoleColor.Yellow; Console.Write(" (dir)"); Console.ForegroundColor = ConsoleColor.Gray; } if (record.BaseFile.FileId != 0) { Console.ForegroundColor = ConsoleColor.Yellow; Console.Write(" (base: {0})", record.BaseFile); Console.ForegroundColor = ConsoleColor.Gray; } if (Enum.IsDefined(typeof(SpecialMFTFiles), record.FileReference.FileId)) { Console.ForegroundColor = ConsoleColor.Green; Console.Write(" ({0})", (SpecialMFTFiles)record.FileReference.FileId); Console.ForegroundColor = ConsoleColor.Gray; } Console.WriteLine(); foreach (Attribute attribute in record.Attributes.Concat(record.ExternalAttributes).OrderBy(s => s.Id)) { bool wasNew = types.Add(attribute.Type); if (wasNew) { File.AppendAllLines("out.txt", new[] { record.FileReference + ": " + attribute.Type }); Debugger.Break(); } string name = string.IsNullOrWhiteSpace(attribute.AttributeName) ? string.Empty : " '" + attribute.AttributeName + "'"; Console.Write(" " + attribute.Id + " (" + attribute.Type); if (name != string.Empty) { Console.ForegroundColor = ConsoleColor.Green; Console.Write(name); Console.ForegroundColor = ConsoleColor.Gray; } Console.Write(")"); AttributeFileName attributeFileName = attribute as AttributeFileName; if (attributeFileName != null) { Console.ForegroundColor = ConsoleColor.Red; Console.Write(" '{0}'", attributeFileName.FileName); Console.ForegroundColor = ConsoleColor.Gray; } AttributeData attributeData = attribute as AttributeData; if (attributeData != null) { Console.ForegroundColor = ConsoleColor.Red; Console.Write(" {0}", attributeData.NonResidentFlag); Console.ForegroundColor = ConsoleColor.Green; Console.Write(" ({0:N0} bytes)", attributeData.NonResidentFlag == ResidentFlag.NonResident ? attributeData.NonResidentHeader.ContentSize : (ulong)attributeData.DataBytes.Length); if (attributeData.NonResidentFlag == ResidentFlag.Resident) { Console.ForegroundColor = ConsoleColor.Red; Console.Write(" ('{0}')", Encoding.ASCII.GetString(attributeData.DataBytes, 0, Math.Min(attributeData.DataBytes.Length, 30))); } else { Console.ForegroundColor = ConsoleColor.Cyan; Console.WriteLine(); foreach (DataFragment fragment in attributeData.DataFragments) { Console.Write(" LCN: {0:N0} ({1:N0} clusters) ", fragment.LCN, fragment.Clusters); if (fragment.IsCompressed) { Console.ForegroundColor = ConsoleColor.Blue; Console.Write(" (Compressed)"); Console.ForegroundColor = ConsoleColor.Cyan; } if (fragment.IsSparseFragment) { Console.ForegroundColor = ConsoleColor.Blue; Console.Write(" (Sparse)"); Console.ForegroundColor = ConsoleColor.Cyan; } Console.WriteLine(); } } Console.ForegroundColor = ConsoleColor.Gray; } Console.WriteLine(); } Console.WriteLine(); } Console.WriteLine("Done."); Console.ReadLine(); }