public static UsnJrnl[] GetInstances(string volume) { // Check for valid Volume name NativeMethods.getVolumeName(ref volume); // Set up FileStream to read volume IntPtr hVolume = NativeMethods.getHandle(volume); FileStream streamToRead = NativeMethods.getFileStream(hVolume); // Get VolumeBootRecord object for logical addressing VolumeBootRecord VBR = VolumeBootRecord.Get(streamToRead); // Get the $J Data attribute (contains UsnJrnl details NonResident J = UsnJrnl.GetJStream(UsnJrnl.GetFileRecord(volume)); List <UsnJrnl> usnList = new List <UsnJrnl>(); for (int i = 0; i < J.DataRun.Length; i++) { if (!(J.DataRun[i].Sparse)) { long clusterCount = J.DataRun[i].ClusterLength; byte[] fragmentBytes = NativeMethods.readDrive(streamToRead, ((ulong)J.DataRun[i].StartCluster * VBR.BytesPerCluster), ((ulong)clusterCount * VBR.BytesPerCluster)); byte[] clusterBytes = new byte[VBR.BytesPerCluster]; for (long j = 0; j < clusterCount; j++) { Array.Copy(fragmentBytes, ((long)j * VBR.BytesPerCluster), clusterBytes, 0, clusterBytes.Length); int offset = 0; do { if (clusterBytes[offset] == 0) { break; } try { UsnJrnl usn = new UsnJrnl(clusterBytes, volume, ref offset); if (usn.Version > USN40Version) { break; } usnList.Add(usn); } catch { break; } } while (offset >= 0 && offset < clusterBytes.Length); } } } return(usnList.ToArray()); }
internal IndexAllocation(NonResident header, string volume) { // Headers Name = (ATTR_TYPE)header.commonHeader.ATTRType; NameString = header.NameString; NonResident = header.commonHeader.NonResident; AttributeId = header.commonHeader.Id; // Get IndexAllocation Bytes byte[] bytes = header.GetBytes(volume); // Instantiate empty IndexEntry List List<IndexEntry> indexEntryList = new List<IndexEntry>(); // Iterate through IndexBlocks (4096 bytes in size) for (int offset = 0; offset < bytes.Length; offset += 4096) { // Detemine size of Update Sequence ushort usOffset = BitConverter.ToUInt16(bytes, offset + 0x04); ushort usSize = BitConverter.ToUInt16(bytes, offset + 0x06); int indexBlockSize = usOffset + (usSize * 2); if (indexBlockSize == 0) { break; } IndexBlock.ApplyFixup(ref bytes, offset); // Instantiate IndexBlock Object (Header) IndexBlock indexBlock = new IndexBlock(NativeMethods.GetSubArray(bytes, (uint)offset, (uint)indexBlockSize)); // Create byte array for IndexEntry object // 0x18 represents the offset of the EntryOffset value, so it must be added on byte[] indexEntryBytes = NativeMethods.GetSubArray(bytes, (uint)offset + indexBlock.EntryOffset + 0x18, indexBlock.TotalEntrySize); int entryOffset = 0; do { // Instantiate an IndexEntry Object IndexEntry indexEntry = new IndexEntry(NativeMethods.GetSubArray(indexEntryBytes, (uint)entryOffset, BitConverter.ToUInt16(indexEntryBytes, entryOffset + 0x08))); entryOffset += indexEntry.Size; // Check if entry is the last in the Entry array if (indexEntry.Flags == 0x02 || indexEntry.Flags == 0x03) { break; } // Add IndexEntry Object to list indexEntryList.Add(indexEntry); }while(entryOffset < indexEntryBytes.Length); } Entries = indexEntryList.ToArray(); }
internal IndexAllocation(NonResident header, string volume) { // Headers Name = (ATTR_TYPE)header.commonHeader.ATTRType; NameString = header.NameString; NonResident = header.commonHeader.NonResident; AttributeId = header.commonHeader.Id; // Get IndexAllocation Bytes byte[] bytes = header.GetBytes(volume); // Instantiate empty IndexEntry List List <IndexEntry> indexEntryList = new List <IndexEntry>(); // Iterate through IndexBlocks (4096 bytes in size) for (int offset = 0; offset < bytes.Length; offset += 4096) { // Detemine size of Update Sequence ushort usOffset = BitConverter.ToUInt16(bytes, offset + 0x04); ushort usSize = BitConverter.ToUInt16(bytes, offset + 0x06); int indexBlockSize = usOffset + (usSize * 2); if (indexBlockSize == 0) { break; } IndexBlock.ApplyFixup(ref bytes, offset); // Instantiate IndexBlock Object (Header) IndexBlock indexBlock = new IndexBlock(NativeMethods.GetSubArray(bytes, (uint)offset, (uint)indexBlockSize)); // Create byte array for IndexEntry object // 0x18 represents the offset of the EntryOffset value, so it must be added on byte[] indexEntryBytes = NativeMethods.GetSubArray(bytes, (uint)offset + indexBlock.EntryOffset + 0x18, indexBlock.TotalEntrySize); int entryOffset = 0; do { // Instantiate an IndexEntry Object IndexEntry indexEntry = new IndexEntry(NativeMethods.GetSubArray(indexEntryBytes, (uint)entryOffset, BitConverter.ToUInt16(indexEntryBytes, entryOffset + 0x08))); entryOffset += indexEntry.Size; // Check if entry is the last in the Entry array if (indexEntry.Flags == 0x02 || indexEntry.Flags == 0x03) { break; } // Add IndexEntry Object to list indexEntryList.Add(indexEntry); }while(entryOffset < indexEntryBytes.Length); } Entries = indexEntryList.ToArray(); }
public static byte[] GetRecordBytes(string volume, int index) { // Get handle for volume IntPtr hVolume = NativeMethods.getHandle(volume); // Get filestream based on hVolume using (FileStream streamToRead = NativeMethods.getFileStream(hVolume)) { // Get Volume Boot Record Ntfs.VolumeBootRecord VBR = VolumeBootRecord.Get(streamToRead); // Determine start of MFT ulong mftStartOffset = VBR.MFTStartIndex * VBR.BytesPerCluster; // Get FileRecord for $MFT FileRecord mftRecord = MasterFileTable.GetRecord(streamToRead, volume); // Get $MFT Data Attribute NonResident data = null; foreach (Attr attr in mftRecord.Attribute) { if (attr.Name == Attr.ATTR_TYPE.DATA) { data = attr as NonResident; } } // Iterate through fragments of the MFT foreach (DataRun dr in data.DataRun) { ulong DataRunRecords = ((ulong)dr.ClusterLength * (ulong)VBR.BytesPerCluster) / (ulong)VBR.BytesPerFileRecord; // Check if index can be found in current DataRun if (index < (int)DataRunRecords) { ulong recordOffset = ((ulong)dr.StartCluster * (ulong)VBR.BytesPerCluster) + ((ulong)index * (ulong)VBR.BytesPerFileRecord); byte[] recordBytesRaw = NativeMethods.readDrive(streamToRead, recordOffset, (ulong)VBR.BytesPerFileRecord); ApplyFixup(ref recordBytesRaw); return(recordBytesRaw); } // Decrement index for the number of FileRecords in the current DataRun else { index -= ((int)dr.ClusterLength * (int)VBR.BytesPerCluster) / (int)VBR.BytesPerFileRecord; } } throw new Exception("Could not find the FileRecord requested..."); } }
public static byte[] getBytes(string volume) { // Get handle for volume IntPtr hVolume = NativeMethods.getHandle(volume); // Get filestream based on hVolume using (FileStream streamToRead = NativeMethods.getFileStream(hVolume)) { VolumeBootRecord VBR = VolumeBootRecord.Get(streamToRead); FileRecord logFileRecord = GetFileRecord(volume); NonResident data = GetDataAttr(logFileRecord); return(data.GetBytes(volume)); } }
public static UsnJrnl Get(string volume, ulong usn) { // Check for valid Volume name NativeMethods.getVolumeName(ref volume); // Set up FileStream to read volume IntPtr hVolume = NativeMethods.getHandle(volume); FileStream streamToRead = NativeMethods.getFileStream(hVolume); // Get VolumeBootRecord object for logical addressing VolumeBootRecord VBR = VolumeBootRecord.Get(streamToRead); // Get the $J Data attribute (contains UsnJrnl details NonResident J = UsnJrnl.GetJStream(UsnJrnl.GetFileRecord(volume)); // Determine the length of the initial sparse pages ulong SparseLength = (ulong)J.DataRun[0].ClusterLength * VBR.BytesPerCluster; // Subtract length of sparse data from desired usn offset ulong usnOffset = usn - SparseLength; // Iterate through each data run for (int i = 1; i < J.DataRun.Length; i++) { // Determine length of current DataRun ulong dataRunLength = (ulong)J.DataRun[i].ClusterLength * VBR.BytesPerCluster; // Check if usnOffset resides in current DataRun if (dataRunLength <= usnOffset) { // If not, subtract length of DataRun from usnOffset usnOffset -= dataRunLength; } // If usnOffset resides within DataRun, parse associated UsnJrnl Entry else { // Read DataRun from disk byte[] fragmentBytes = NativeMethods.readDrive(streamToRead, ((ulong)J.DataRun[i].StartCluster * VBR.BytesPerCluster), ((ulong)J.DataRun[i].ClusterLength * VBR.BytesPerCluster)); // Instatiate a byte array that is the size of a single cluster byte[] clusterBytes = new byte[VBR.BytesPerCluster]; // Iterate through the clusters in the DataRun for (long j = 0; j < J.DataRun[i].ClusterLength; j++) { // If usnOffset is not in current cluster, then subtract cluster size from offset and iterate if (VBR.BytesPerCluster <= usnOffset) { usnOffset -= VBR.BytesPerCluster; } // Else if usnOffset is in current cluster else { // Copy current cluster bytes to clusterBytes variable Array.Copy(fragmentBytes, ((long)j * VBR.BytesPerCluster), clusterBytes, 0, clusterBytes.Length); // Parse desired UsnJrnl entry from cluster int offset = (int)usnOffset; return(new UsnJrnl(clusterBytes, volume, ref offset)); } } } } return(null); }
internal static Bitmap Get(string volume, ulong cluster) { ulong sectorOffset = cluster / 4096; ulong byteOffset = (cluster % 4096) / 8; // Check for valid Volume name NativeMethods.getVolumeName(ref volume); IntPtr hVolume = NativeMethods.getHandle(volume); // Set up FileStream to read volume FileStream streamToRead = NativeMethods.getFileStream(hVolume); // Get VolumeBootRecord object for logical addressing VolumeBootRecord VBR = VolumeBootRecord.Get(streamToRead); // Get the Data attribute NonResident dataStream = Bitmap.GetDataStream(Bitmap.GetFileRecord(volume)); // Calulate the offset of the Bitmap file's data ulong dataRunOffset = (ulong)dataStream.DataRun[0].StartCluster * VBR.BytesPerCluster; // Calculate the offset of the sector that contains the entry for the specific cluster ulong offset = dataRunOffset + (VBR.BytesPerSector * sectorOffset); // Read appropriate sector byte[] bytes = NativeMethods.readDrive(streamToRead, offset, VBR.BytesPerSector); byte b = bytes[byteOffset]; bool inUse = false; switch (cluster % 8) { case 0: if ((b & 0x01) > 0) { inUse = true; } break; case 1: if ((b & 0x02) > 0) { inUse = true; } break; case 2: if ((b & 0x04) > 0) { inUse = true; } break; case 3: if ((b & 0x08) > 0) { inUse = true; } break; case 4: if ((b & 0x10) > 0) { inUse = true; } break; case 5: if ((b & 0x20) > 0) { inUse = true; } break; case 6: if ((b & 0x40) > 0) { inUse = true; } break; case 7: if ((b & 0x80) > 0) { inUse = true; } break; } return(new Bitmap(cluster, inUse)); }
internal static Bitmap[] GetInstances(string volume) { // Check for valid Volume name NativeMethods.getVolumeName(ref volume); // Set up FileStream to read volume IntPtr hVolume = NativeMethods.getHandle(volume); FileStream streamToRead = NativeMethods.getFileStream(hVolume); // Get VolumeBootRecord object for logical addressing VolumeBootRecord VBR = VolumeBootRecord.Get(streamToRead); // Get the Data attribute NonResident dataStream = Bitmap.GetDataStream(Bitmap.GetFileRecord(volume)); byte[] bytes = NativeMethods.readDrive(streamToRead, ((ulong)dataStream.DataRun[0].StartCluster * VBR.BytesPerCluster), ((ulong)dataStream.DataRun[0].ClusterLength * VBR.BytesPerCluster)); Bitmap[] bitmapArray = new Bitmap[bytes.Length * 8]; for (int j = 0; j < bytes.Length; j++) { for (int k = 0; k < 8; k++) { bool inUse = false; int index = ((j * 8) + k); switch (k) { case 0: if ((bytes[j] & 0x01) > 0) { inUse = true; } break; case 1: if ((bytes[j] & 0x02) > 0) { inUse = true; } break; case 2: if ((bytes[j] & 0x04) > 0) { inUse = true; } break; case 3: if ((bytes[j] & 0x08) > 0) { inUse = true; } break; case 4: if ((bytes[j] & 0x10) > 0) { inUse = true; } break; case 5: if ((bytes[j] & 0x20) > 0) { inUse = true; } break; case 6: if ((bytes[j] & 0x40) > 0) { inUse = true; } break; case 7: if ((bytes[j] & 0x80) > 0) { inUse = true; } break; } bitmapArray[index] = new Bitmap((ulong)index, inUse); } } return(bitmapArray); }