public void SimpleFile() { byte[] randomData = new byte[65 * 4096]; _random.NextBytes(randomData); using (TempFile tmpFile = new TempFile()) { // Create a file File.WriteAllBytes(tmpFile.File.FullName, randomData); // Discover it via the NTFS lib char driveLetter = tmpFile.File.FullName[0]; RawDisk disk = new RawDisk(driveLetter); NTFSDiskProvider provider = new NTFSDiskProvider(disk); NTFSWrapper ntfsWrapper = new NTFSWrapper(provider, 0); NtfsDirectory ntfsDir = NTFSHelpers.OpenDir(ntfsWrapper, tmpFile.File.DirectoryName); NtfsFile ntfsFile = NTFSHelpers.OpenFile(ntfsDir, tmpFile.File.Name); Assert.IsNotNull(ntfsFile); // Read it using (Stream actualStream = File.OpenRead(tmpFile.File.FullName)) using (Stream ntfsStream = ntfsFile.OpenRead()) { bool equal = StreamUtils.CompareStreams(actualStream, ntfsStream); Assert.IsTrue(equal); } } }
private static NtfsDirectory FindDir(NTFSWrapper wrapper, Options opts) { string[] pathParts = opts.PathArgument.Split(new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries).Skip(1).ToArray(); if (pathParts.Length == 0) { // Chosen path is root return(wrapper.GetRootDirectory()); } // Navigate to directory NtfsDirectory dir = wrapper.GetRootDirectory(); for (int i = 0; i < pathParts.Length; i++) { dir = dir.ListDirectories(false).FirstOrDefault(s => s.Name.Equals(pathParts[i], StringComparison.InvariantCultureIgnoreCase)); if (dir == null) { return(null); } } // Return the last directory return(dir); }
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); }
internal NtfsDirectory(NTFSWrapper ntfsWrapper, FileRecord record, AttributeFileName fileName) : base(ntfsWrapper, record, fileName) { Debug.Assert(record.Flags.HasFlag(FileEntryFlags.Directory)); PrepRecord(); }
protected NtfsFileEntry(NTFSWrapper ntfsWrapper, FileRecord record, AttributeFileName fileName) { NTFSWrapper = ntfsWrapper; MFTRecord = record; FileName = fileName; Init(); }
/* TODO: * List streams ($DATA, $BITMAP ..) * List alternate namings (Win32, DOS, POSIX) * Toggle FileID's * List matching attributes * Recursive * Deleted records */ static void Main(string[] args) { Options opts = new Options(); bool success = opts.Parse(args); if (!success) { AwesomeConsole.WriteLine("Unable to parse the commandline:"); PrintError(opts.ErrorDetails); AwesomeConsole.WriteLine(); AwesomeConsole.WriteLine("Try --help for more informations"); return; } if (opts.ActionType == ActionType.ShowHelp) { opts.DisplayHelp(); return; } using (RawDisk disk = new RawDisk(opts.Drive)) { NTFSWrapper wrapper = new NTFSWrapper(new NTFSDiskProvider(disk), 1); NtfsDirectory dir = null; if (opts.PathType == PathType.Directory) { dir = FindDir(wrapper, opts); } if (dir == null) { PrintError("The given path didn't exist"); AwesomeConsole.WriteLine(); switch (opts.PathType) { case PathType.Directory: PrintError("Specified " + opts.PathType + ": " + opts.PathArgument); break; } AwesomeConsole.WriteLine(); return; } // Display DisplayDetails(wrapper, opts, dir); } if (Debugger.IsAttached) { Console.ReadLine(); } }
public void AlternateDatastreamDirectory() { Random rand = new Random(); byte[][] data = new byte[10][]; for (int i = 0; i < 10; i++) { data[i] = new byte[1024 * 1024]; rand.NextBytes(data[i]); } using (TempDir tmpDir = new TempDir()) { // Make file for (int i = 0; i < 10; i++) { using (SafeFileHandle fileHandle = Win32.CreateFile(tmpDir.Directory.FullName + ":alternate" + i + ":$DATA")) using (FileStream fs = new FileStream(fileHandle, FileAccess.ReadWrite)) { fs.Write(data[i], 0, data[i].Length); } } // Discover dir in NTFSLib char driveLetter = tmpDir.Directory.FullName[0]; RawDisk disk = new RawDisk(driveLetter); NTFSDiskProvider provider = new NTFSDiskProvider(disk); NTFSWrapper ntfsWrapper = new NTFSWrapper(provider, 0); NtfsDirectory ntfsDir = NTFSHelpers.OpenDir(ntfsWrapper, tmpDir.Directory.FullName); // Check streams string[] streams = ntfsWrapper.ListDatastreams(ntfsDir.MFTRecord); Assert.AreEqual(10, streams.Length); for (int i = 0; i < 10; i++) { Assert.AreEqual(1, streams.Count(s => s == "alternate" + i)); } // Check data for (int i = 0; i < 10; i++) { using (Stream memStream = new MemoryStream(data[i])) using (Stream fileStream = ntfsWrapper.OpenFileRecord(ntfsDir.MFTRecord, "alternate" + i)) { StreamUtils.CompareStreams(memStream, fileStream); } } } }
public void EnumerateChilds() { Random rand = new Random(); using (TempDir tmpDir = new TempDir()) { // Make files byte[] data = new byte[1024 * 1024]; for (int i = 0; i < 10; i++) { rand.NextBytes(data); File.WriteAllBytes(Path.Combine(tmpDir.Directory.FullName, i + ".bin"), data); } // Make dirs for (int i = 0; i < 10; i++) { rand.NextBytes(data); tmpDir.Directory.CreateSubdirectory("dir" + i); } // Discover dir in NTFSLib char driveLetter = tmpDir.Directory.FullName[0]; RawDisk disk = new RawDisk(driveLetter); NTFSDiskProvider provider = new NTFSDiskProvider(disk); NTFSWrapper ntfsWrapper = new NTFSWrapper(provider, 0); NtfsDirectory ntfsDir = NTFSHelpers.OpenDir(ntfsWrapper, tmpDir.Directory.FullName); // Enumerate files List <NtfsFile> ntfsFiles = ntfsDir.ListFiles().ToList(); Assert.AreEqual(10, ntfsFiles.Count); for (int i = 0; i < 10; i++) { Assert.AreEqual(1, ntfsFiles.Count(s => s.Name == i + ".bin")); } // Enumerate dirs List <NtfsDirectory> ntfsDirs = ntfsDir.ListDirectories().ToList(); Assert.AreEqual(10, ntfsDirs.Count); for (int i = 0; i < 10; i++) { Assert.AreEqual(1, ntfsDirs.Count(s => s.Name == "dir" + i)); } } }
public void SparseFile() { byte[] randomData = new byte[35 * 4096]; _random.NextBytes(randomData); // Clear the 16 * 4096 -> 32 * 4096 range Array.Clear(randomData, 16 * 4096, 16 * 4096); using (TempFile tmpFile = new TempFile()) { // Create a file File.WriteAllBytes(tmpFile.File.FullName, randomData); using (FilesystemDeviceWrapper wrapper = Win32.GetFileWrapper(tmpFile.File.FullName)) { wrapper.FileSystemSetSparseFile(true); wrapper.FileSystemSetZeroData(16 * 4096, 16 * 4096); FILE_ALLOCATED_RANGE_BUFFER[] rangesData = wrapper.FileSystemQueryAllocatedRanges(0, randomData.Length); // We should have 2 ranges on non-zero data Assert.AreEqual(2, rangesData.Length); } // Discover it via the NTFS lib char driveLetter = tmpFile.File.FullName[0]; RawDisk disk = new RawDisk(driveLetter); NTFSDiskProvider provider = new NTFSDiskProvider(disk); NTFSWrapper ntfsWrapper = new NTFSWrapper(provider, 0); NtfsDirectory ntfsDir = NTFSHelpers.OpenDir(ntfsWrapper, tmpFile.File.DirectoryName); NtfsFile ntfsFile = NTFSHelpers.OpenFile(ntfsDir, tmpFile.File.Name); Assert.IsNotNull(ntfsFile); Assert.IsTrue(tmpFile.File.Attributes.HasFlag(FileAttributes.SparseFile)); AttributeData attributeData = ntfsFile.MFTRecord.Attributes.OfType <AttributeData>().Single(); Assert.IsTrue(attributeData.DataFragments.Length > 1); Assert.IsTrue(attributeData.DataFragments.Any(s => s.IsSparseFragment)); // Read it using (Stream actualStream = File.OpenRead(tmpFile.File.FullName)) using (Stream ntfsStream = ntfsFile.OpenRead()) { bool equal = StreamUtils.CompareStreams(actualStream, ntfsStream); Assert.IsTrue(equal); } } }
public static IEnumerable <NtfsDirectory> GetDirectories(char driveLetter, string directory) { if (string.IsNullOrWhiteSpace(directory)) { throw new ArgumentException("String cannot be null, empty or whitespace.", nameof(directory)); } using (RawDisk disk = new RawDisk(driveLetter, FileAccess.Read)) { NTFSDiskProvider provider = new NTFSDiskProvider(disk); NTFSWrapper ntfsWrapper = new NTFSWrapper(provider, rawDiskCacheRecordSize); NtfsDirectory ntfsDir = NTFSHelpers.OpenDir(ntfsWrapper, directory); return(ntfsDir.ListDirectories()); } }
public void CompressedFile() { using (TempFile tmpFile = new TempFile()) { // Create a file // Write file data using (FileStream fs = File.OpenWrite(tmpFile.File.FullName)) { byte[] data = Encoding.ASCII.GetBytes("The white bunny jumps over the brown dog in a carparking lot"); for (int i = 0; i < 20000; i++) { fs.Write(data, 0, data.Length); } } using (FilesystemDeviceWrapper wrapper = Win32.GetFileWrapper(tmpFile.File.FullName)) { wrapper.FileSystemSetCompression(COMPRESSION_FORMAT.LZNT1); } // Discover it via the NTFS lib char driveLetter = tmpFile.File.FullName[0]; RawDisk disk = new RawDisk(driveLetter); NTFSDiskProvider provider = new NTFSDiskProvider(disk); NTFSWrapper ntfsWrapper = new NTFSWrapper(provider, 0); NtfsDirectory ntfsDir = NTFSHelpers.OpenDir(ntfsWrapper, tmpFile.File.DirectoryName); NtfsFile ntfsFile = NTFSHelpers.OpenFile(ntfsDir, tmpFile.File.Name); Assert.IsNotNull(ntfsFile); Assert.IsTrue(tmpFile.File.Attributes.HasFlag(FileAttributes.Compressed)); AttributeData attributeData = ntfsFile.MFTRecord.Attributes.OfType <AttributeData>().Single(); Assert.IsTrue(attributeData.DataFragments.Any(s => s.IsCompressed)); // Read it using (Stream actualStream = File.OpenRead(tmpFile.File.FullName)) using (Stream ntfsStream = ntfsFile.OpenRead()) { bool equal = StreamUtils.CompareStreams(actualStream, ntfsStream); Assert.IsTrue(equal); } } }
public static NtfsDirectory OpenDir(NTFSWrapper ntfsWrapper, string path) { Assert.IsTrue(Path.IsPathRooted(path)); string[] dirs = path.Split(new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries); NtfsDirectory currDir = ntfsWrapper.GetRootDirectory(); foreach (string dir in dirs.Skip(1)) // Skip root (C:\) { IEnumerable<NtfsDirectory> subDirs = currDir.ListDirectories(false); NtfsDirectory subDir = subDirs.FirstOrDefault(s => s.Name.Equals(dir, StringComparison.InvariantCultureIgnoreCase)); Assert.IsNotNull(subDir); currDir = subDir; } return currDir; }
private static uint FindPathMftId(Options opts) { string[] pathParts = opts.PathArgument.Split(new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries); string[] pathParents = pathParts.Skip(1).Take(pathParts.Length - 2).ToArray(); if (pathParts.Length == 1) { // Chosen path is root return((uint)SpecialMFTFiles.RootDir); } using (RawDisk disk = new RawDisk(opts.Drive)) { NTFSWrapper ntfs = new NTFSWrapper(new NTFSDiskProvider(disk), 4); // Navigate to parent directory NtfsDirectory parentDir = ntfs.GetRootDirectory(); for (int i = 0; i < pathParents.Length; i++) { parentDir = parentDir.ListDirectories(false).FirstOrDefault(s => s.Name.Equals(pathParents[i], StringComparison.InvariantCultureIgnoreCase)); if (parentDir == null) { return(uint.MaxValue); } } // Select the correct child IEnumerable <NtfsFileEntry> childs = opts.PathType == PathType.File ? (IEnumerable <NtfsFileEntry>)parentDir.ListFiles(false) : parentDir.ListDirectories(false); NtfsFileEntry child = childs.FirstOrDefault(s => s.Name.Equals(pathParts.Last(), StringComparison.InvariantCultureIgnoreCase)); if (child == null) { return(uint.MaxValue); } // Return the childs id return(child.MFTRecord.MFTNumber); } }
private void PrepRecord() { // Ensure we have all INDEX attributes at hand bool parseLists = false; foreach (AttributeList list in MFTRecord.Attributes.OfType <AttributeList>()) { foreach (AttributeListItem item in list.Items) { if (item.BaseFile != MFTRecord.FileReference && (item.Type == AttributeType.INDEX_ROOT || item.Type == AttributeType.INDEX_ALLOCATION)) { // We need to parse lists parseLists = true; } } } if (parseLists) { NTFSWrapper.ParseAttributeLists(MFTRecord); } // Get root _indexRoot = MFTRecord.Attributes.OfType <AttributeIndexRoot>().Single(s => s.AttributeName == DirlistAttribName); // Get allocations _indexes = MFTRecord.Attributes.OfType <AttributeIndexAllocation>().Where(s => s.AttributeName == DirlistAttribName).ToArray(); foreach (AttributeIndexAllocation index in _indexes) { NTFSWrapper.ParseNonResidentAttribute(index); } // Get bitmap of allocations // var bitmap = MFTRecord.Attributes.OfType<AttributeBitmap>().Single(s => s.AttributeName == DirlistAttribName); }
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(); }
private static void DisplayDetails(NTFSWrapper wrapper, Options opts, NtfsDirectory dir) { Console.WriteLine("Listing details for " + dir.Name); IEnumerable <NtfsFileEntry> subDirs = dir.ListDirectories(!opts.ShowAllNames); IEnumerable <NtfsFileEntry> subFiles = dir.ListFiles(!opts.ShowAllNames); foreach (NtfsFileEntry entry in subDirs.Concat(subFiles)) { if (opts.ShowAllStreams) { // Stream display var streams = entry.MFTRecord.Attributes.Concat(entry.MFTRecord.ExternalAttributes).GroupBy(s => new { s.AttributeName, s.Type }); foreach (var stream in streams) { AwesomeConsole.WriteLine(); } } else { // Simple file display AwesomeConsole.Write(entry.TimeModified.ToString("yyyy-MM-dd HH:mm")); AwesomeConsole.Write(" "); if (opts.ShowFileIds) { AwesomeConsole.Write(entry.MFTRecord.FileReference); AwesomeConsole.Write(" "); } if (entry is NtfsDirectory) { AwesomeConsole.Write("<DIR>"); } else { AttributeData dataAttrib = entry.MFTRecord.Attributes.OfType <AttributeData>().FirstOrDefault(s => s.NameLength == 0); long fileSize = -1; if (dataAttrib != null && dataAttrib.NonResidentFlag == ResidentFlag.Resident) { fileSize = dataAttrib.ResidentHeader.ContentLength; } else if (dataAttrib != null && dataAttrib.NonResidentFlag == ResidentFlag.NonResident) { fileSize = (long)dataAttrib.NonResidentHeader.ContentSize; } AwesomeConsole.Write(fileSize.ToString("N0")); } AwesomeConsole.Write(" "); AwesomeConsole.Write(entry.Name); AwesomeConsole.WriteLine(); } } // Volume in drive C has no label. // Volume Serial Number is 50C3-B38B // Directory of C:\ //23-08-2012 12:51 1.024 .rnd //12-05-2013 13:04 <DIR> AMD //03-03-2013 09:51 <SYMLINKD> Cygwin [C:\Program Files (x86)\Cygwin] //14-11-2012 23:24 <DIR> Intel //14-07-2009 05:20 <DIR> PerfLogs //20-05-2013 18:14 <DIR> Program Files //20-05-2013 18:20 <DIR> Program Files (x86) //12-05-2013 13:08 <DIR> ProgramData //11-05-2013 14:49 <DIR> Python27 //18-01-2013 02:13 <DIR> Temp //19-05-2013 18:21 378.273.792 test.bin //24-02-2013 02:32 <DIR> Users //21-05-2013 13:37 <DIR> Windows // 2 File(s) 378.274.816 bytes // 11 Dir(s) 21.434.728.448 bytes free }
private void PrepRecord() { // Ensure we have all INDEX attributes at hand bool parseLists = false; foreach (AttributeList list in MFTRecord.Attributes.OfType <AttributeList>()) { foreach (AttributeListItem item in list.Items) { if (item.BaseFile != MFTRecord.FileReference && (item.Type == AttributeType.INDEX_ROOT || item.Type == AttributeType.INDEX_ALLOCATION)) { // We need to parse lists parseLists = true; } } } if (parseLists) { NTFSWrapper.ParseAttributeLists(MFTRecord); } bool containsItem = MFTRecord.Attributes.Any(s => s.AttributeName == DirlistAttribName); if (containsItem) { IEnumerable <AttributeIndexRoot> matches = MFTRecord.Attributes.OfType <AttributeIndexRoot>().Where(s => s.AttributeName == DirlistAttribName); if (!matches.Any()) // Does list contain any items? { return; // Bail if no IndexRoot Attributes where AttributeName == DirlistAttribName } // IEnumerable.Single(predicate) returns the single item that matches the predicate, // and throws if the number of matches are not exactly one. That is, if it matches zero items or many items. // In our case, the exception message was "Sequence contains no matching element", so it was empty. //_indexRoot = MFTRecord.Attributes.OfType<AttributeIndexRoot>().Single(s => s.AttributeName == DirlistAttribName); // First will return the first item in the list, ignoring the rest. // It will throw if there is no items in the list, but wont if there are many. _indexRoot = matches.First(); } else { // No point in continuing in this case, as it will just waste time parsing IndexAllocations below, // but never iterate them because _indexRoot == null return; //using (System.IO.StreamWriter w = System.IO.File.AppendText("D:\\Log\\faillog.txt")) //{ // w.WriteLine("failed to get indexroot for mft number " + MFTRecord.MFTNumber.ToString()); //} } // Get allocations _indexes = MFTRecord.Attributes.OfType <AttributeIndexAllocation>().Where(s => s.AttributeName == DirlistAttribName).ToArray(); foreach (AttributeIndexAllocation index in _indexes) { NTFSWrapper.ParseNonResidentAttribute(index); } // Get bitmap of allocations // var bitmap = MFTRecord.Attributes.OfType<AttributeBitmap>().Single(s => s.AttributeName == DirlistAttribName); }
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) { Options opts = new Options(); bool success = opts.Parse(args); if (!success) { AwesomeConsole.WriteLine("Unable to parse the commandline:"); PrintError(opts.ErrorDetails); AwesomeConsole.WriteLine(); AwesomeConsole.WriteLine("Try --help for more informations"); return; } if (opts.ActionType == ActionType.ShowHelp) { opts.DisplayHelp(); return; } uint mftId = 0; if (opts.SourceType == PathType.File) { mftId = FindPathMftId(opts); } else if (opts.SourceType == PathType.MftId) { mftId = opts.MftId; } using (RawDisk disk = new RawDisk(opts.Drive)) { NTFSWrapper wrapper = new NTFSWrapper(new NTFSDiskProvider(disk), 1); if (wrapper.FileRecordCount < mftId) { PrintError("The given path or MftID didn't exist"); AwesomeConsole.WriteLine(); switch (opts.SourceType) { case PathType.File: PrintError("Specified " + opts.SourceType + ": " + opts.Source); break; case PathType.MftId: PrintError("Specified type: MftId, id: " + opts.MftId); break; } AwesomeConsole.WriteLine(); return; } PerformCopy(wrapper, opts, mftId); } if (Debugger.IsAttached) { Console.ReadLine(); } }