internal unsafe void EnumerateIndexEntries(NtfsIndexEntryHandlerDelegate callback, bool traceNodes) { fixed(NtfsRootIndexAttribute *pAttribute = &this) { NtfsNodeHeader *pNodeHeader = (NtfsNodeHeader *)((byte *)pAttribute + sizeof(NtfsRootIndexAttribute)); if (traceNodes) { pNodeHeader->Dump(); } NtfsIndexEntryHeader *pIndexEntry = (NtfsIndexEntryHeader *)((byte *)pNodeHeader + pNodeHeader->OffsetToFirstIndexEntry); while (true) { ulong scannedEntryOffset = (ulong)((byte *)pIndexEntry - (byte *)pNodeHeader); if (pNodeHeader->IndexLength <= scannedEntryOffset) { throw new ApplicationException(); } if (!callback(pIndexEntry)) { return; } // TODO : Clarify exit condition. Does the last record holds any valuable data ? if (pIndexEntry->LastIndexEntry) { return; } pIndexEntry = (NtfsIndexEntryHeader *)((byte *)pIndexEntry + pIndexEntry->EntryLength); } throw new ApplicationException("Last index entry missing."); } }
public static unsafe int Main(string[] args) { InstallExceptionHandlers(); using (PartitionDataDisposableBatch mainBatch = PartitionDataDisposableBatch.CreateNew()) { DisplayVersion(); IntPtr handle = IntPtr.Zero; int nativeError; DiskGeometry geometry = new DiskGeometry(); try { handle = Natives.CreateFile2(@"\\.\PhysicalDrive0", 0x80000000 /* GENERIC_READ */, 0x02 /* FILE_SHARE_WRITE */, 3 /* OPEN_EXISTING */, IntPtr.Zero); nativeError = Marshal.GetLastWin32Error(); if ((IntPtr.Zero == handle) || (0 != nativeError)) { Console.WriteLine("Physical drive opening failed. Error 0x{0:X8}", nativeError); return(1); } geometry.Acquire(handle); _partitionManager = new PartitionManager(handle, geometry); _partitionManager.Discover(); InterpretActivePartitions(); if (FeaturesContext.InvariantChecksEnabled) { NtfsMFTFileRecord.AssertMFTRecordCachingInvariance(_partitionManager); } // TODO : Configure TrackedPartitionIndex from command line arguments. foreach (GenericPartition partition in _partitionManager.EnumeratePartitions()) { if (!partition.ShouldCapture) { continue; } NtfsPartition ntfsPartition = partition as NtfsPartition; NtfsPartition.Current = ntfsPartition; // Basic functionnality tests. Don't remove. //ntfsPartition.CountFiles(); //ntfsPartition.MonitorBadClusters(); //ntfsPartition.ReadBitmap(); // Dump bad clusters. ntfsPartition.DumpBadClusters(); // Dump UsnJournal PrototypeUsnJournal(); new NtfsUsnJournalReader(ntfsPartition).Run(); // Dump LogFile // new NtfsLogFileReader(ntfsPartition).Run(); // Locate file. // string fileName = @"TEMP\AsciiTes.txt"; string fileName = @"$Extend\$UsnJrnl"; NtfsIndexEntryHeader *fileDescriptor = ntfsPartition.FindFile(fileName); if (null == fileDescriptor) { throw new System.IO.FileNotFoundException(fileName); } IPartitionClusterData fileData = null; NtfsFileRecord * usnJournalFileRecord = ntfsPartition.GetFileRecord(fileDescriptor->FileReference, ref fileData); if ((null == usnJournalFileRecord) || (null == fileData)) { throw new ApplicationException(); } try { usnJournalFileRecord->EnumerateRecordAttributes( delegate(NtfsAttribute * attribute, Stream dataStream) { attribute->Dump(); return(true); }); // For debugging purpose. // fileRecord->BinaryDumpContent(); // TODO : Do something with the file. } finally { if (null != fileData) { fileData.Dispose(); } } } return(0); } finally { if (IntPtr.Zero == handle) { Natives.CloseHandle(handle); handle = IntPtr.Zero; } } } }
private unsafe void _Run() { NtfsPartition partition = Partition; IPartitionClusterData clusterData = null; try { // Note : We could also use the NtfsWellKnownMetadataFiles.Extend entry to // locate the directory, then find the $UsnJrnl entry directly from there. string fileName = @"$UsnJrnl"; NtfsIndexEntryHeader *fileDescriptor = partition.FindFile(fileName, NtfsWellKnownMetadataFiles.Extend); if (null == fileDescriptor) { throw new System.IO.FileNotFoundException(fileName); } IPartitionClusterData fileData = null; try { NtfsFileRecord *fileRecord = partition.GetFileRecord(fileDescriptor->FileReference, ref fileData); fileRecord->AssertRecordType(); // We retrieve the first attribute here. Stream dataStream; NtfsAttribute *jAttribute = fileRecord->GetAttribute(NtfsAttributeType.AttributeData, out dataStream, 1, _isDollarJAttributeNameFilter); if (null == jAttribute) { throw new ApplicationException(); } if (jAttribute->IsResident) { // Seems this is never the case. throw new NotSupportedException("CODE REVIEW REQUIRED"); } NtfsNonResidentAttribute *jNrAttribute = (NtfsNonResidentAttribute *)jAttribute; jNrAttribute->Dump(); byte[] buffer = new byte[NtfsPartition.Current.ClusterSize]; DateTime sparseReadStartTime = DateTime.UtcNow; TimeSpan sparseReadDuration; if (null == dataStream) { dataStream = jNrAttribute->OpenDataStream(); throw new ApplicationException("CODE REVIEW REQUIRED"); } int totalReads = 0; bool nonNullByteFound = false; while (true) { int readCount = dataStream.Read(buffer, 0, buffer.Length); if (-1 == readCount) { sparseReadDuration = DateTime.UtcNow - sparseReadStartTime; break; } if (nonNullByteFound) { for (int index = 0; index < readCount; index++) { if (0 == buffer[index]) { continue; } sparseReadDuration = DateTime.UtcNow - sparseReadStartTime; Console.WriteLine("{0} null leading bytes found after {1} secs.", totalReads + index, (int)sparseReadDuration.TotalSeconds); nonNullByteFound = true; break; } } totalReads += readCount; if (nonNullByteFound) { Helpers.BinaryDump(buffer, (uint)readCount); } } if (!nonNullByteFound) { sparseReadDuration = DateTime.UtcNow - sparseReadStartTime; Console.WriteLine("{0} null leading bytes found after {1} secs.", totalReads, (int)sparseReadDuration.TotalSeconds); } throw new NotImplementedException(); NtfsAttribute *rawAttribute = fileRecord->GetAttribute(NtfsAttributeType.AttributeData, out dataStream, 1); if (null == rawAttribute) { throw new ApplicationException(); } if ("$Max" != rawAttribute->Name) { throw new ApplicationException(); } if (rawAttribute->IsResident) { NtfsResidentAttribute *reMaxAttribute = (NtfsResidentAttribute *)rawAttribute; if (FeaturesContext.InvariantChecksEnabled) { if (0x20 != reMaxAttribute->ValueLength) { throw new ApplicationException(); } } MaxAttribute *maxAttribute = (MaxAttribute *)((byte *)reMaxAttribute + reMaxAttribute->ValueOffset); } else { throw new NotSupportedException(); } rawAttribute = fileRecord->GetAttribute(NtfsAttributeType.AttributeData, out dataStream, 2); if (null == rawAttribute) { throw new ApplicationException(); } if ("$J" != rawAttribute->Name) { throw new ApplicationException(); } throw new NotImplementedException(); } finally { if (null != fileData) { fileData.Dispose(); } } } finally { if (null != clusterData) { clusterData.Dispose(); } } }