Quantcast
Channel: Reading MFT
Viewing all articles
Browse latest Browse all 444

Reading MFT

$
0
0
I do this all of the time....
Here is the PInvoke code I wrote:  And below that some sample code I wrote that enumerates the MFT.  That should give you enough to start...

 

using System;  
using System.Collections.Generic;  
using System.Text;  
using System.Runtime.InteropServices;  
 
namespace EnumerateVolume  
{  
    class PInvokeWin32  
    {  
        #region DllImports and Constants  
 
        public const UInt32 GENERIC_READ = 0x80000000;  
        public const UInt32 GENERIC_WRITE = 0x40000000;  
        public const UInt32 FILE_SHARE_READ = 0x00000001;  
        public const UInt32 FILE_SHARE_WRITE = 0x00000002;  
        public const UInt32 FILE_ATTRIBUTE_DIRECTORY = 0x00000010;  
        public const UInt32 OPEN_EXISTING = 3;  
        public const UInt32 FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;  
        public const Int32 INVALID_HANDLE_VALUE = -1;  
        public const UInt32 FSCTL_QUERY_USN_JOURNAL = 0x000900f4;  
        public const UInt32 FSCTL_ENUM_USN_DATA = 0x000900b3;  
        public const UInt32 FSCTL_CREATE_USN_JOURNAL = 0x000900e7;  
 
        [DllImport("kernel32.dll", SetLastError = true)]  
        public static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess,  
                                                  uint dwShareMode, IntPtr lpSecurityAttributes,  
                                                  uint dwCreationDisposition, uint dwFlagsAndAttributes,  
                                                  IntPtr hTemplateFile);  
 
        [DllImport("kernel32.dll", SetLastError = true)]  
        [return: MarshalAs(UnmanagedType.Bool)]  
        public static extern bool GetFileInformationByHandle(IntPtr hFile,  
                                                                     out BY_HANDLE_FILE_INFORMATION lpFileInformation);  
 
        [DllImport("kernel32.dll", SetLastError = true)]  
        [return: MarshalAs(UnmanagedType.Bool)]  
        public static extern bool CloseHandle(IntPtr hObject);  
 
        [DllImport("kernel32.dll", ExactSpelling = trueSetLastError = trueCharSetCharSet = CharSet.Auto)]  
        [return: MarshalAs(UnmanagedType.Bool)]  
        public static extern bool DeviceIoControl(IntPtr hDevice,  
                                                      UInt32 dwIoControlCode,  
                                                      IntPtr lpInBuffer, Int32 nInBufferSize,  
                                                      out USN_JOURNAL_DATA lpOutBuffer, Int32 nOutBufferSize,  
                                                      out uint lpBytesReturned, IntPtr lpOverlapped);  
 
        [DllImport("kernel32.dll", ExactSpelling = trueSetLastError = trueCharSetCharSet = CharSet.Auto)]  
        [return: MarshalAs(UnmanagedType.Bool)]  
        public static extern bool DeviceIoControl(IntPtr hDevice,  
                                                      UInt32 dwIoControlCode,  
                                                      IntPtr lpInBuffer, Int32 nInBufferSize,  
                                                      IntPtr lpOutBuffer, Int32 nOutBufferSize,  
                                                      out uint lpBytesReturned, IntPtr lpOverlapped);  
 
        [DllImport("kernel32.dll")]  
        public static extern void ZeroMemory(IntPtr ptr, Int32 size);  
 
        [StructLayout(LayoutKind.Sequential, Pack = 1)]  
        public struct BY_HANDLE_FILE_INFORMATION  
        {  
            public uint FileAttributes;  
            public FILETIME CreationTime;  
            public FILETIME LastAccessTime;  
            public FILETIME LastWriteTime;  
            public uint VolumeSerialNumber;  
            public uint FileSizeHigh;  
            public uint FileSizeLow;  
            public uint NumberOfLinks;  
            public uint FileIndexHigh;  
            public uint FileIndexLow;  
        }  
 
        [StructLayout(LayoutKind.Sequential, Pack = 1)]  
        public struct FILETIME  
        {  
            public uint DateTimeLow;  
            public uint DateTimeHigh;  
        }  
 
 
        [StructLayout(LayoutKind.Sequential, Pack = 1)]  
        public struct USN_JOURNAL_DATA  
        {  
            public UInt64 UsnJournalID;  
            public Int64 FirstUsn;  
            public Int64 NextUsn;  
            public Int64 LowestValidUsn;  
            public Int64 MaxUsn;  
            public UInt64 MaximumSize;  
            public UInt64 AllocationDelta;  
        }  
 
        [StructLayout(LayoutKind.Sequential, Pack = 1)]  
        public struct MFT_ENUM_DATA  
        {  
            public UInt64 StartFileReferenceNumber;  
            public Int64 LowUsn;  
            public Int64 HighUsn;  
        }  
 
        [StructLayout(LayoutKind.Sequential, Pack = 1)]  
        public struct CREATE_USN_JOURNAL_DATA  
        {  
            public UInt64 MaximumSize;  
            public UInt64 AllocationDelta;  
        }  
 
        public class USN_RECORD  
        {  
            public UInt32 RecordLength;  
            public UInt64 FileReferenceNumber;  
            public UInt64 ParentFileReferenceNumber;  
            public UInt32 FileAttributes;  
            public Int32 FileNameLength;  
            public Int32 FileNameOffset;  
            public string FileName = string.Empty;  
 
            private const int FR_OFFSET = 8;  
            private const int PFR_OFFSET = 16;  
            private const int FA_OFFSET = 52;  
            private const int FNL_OFFSET = 56;  
            private const int FN_OFFSET = 58;  
 
            public USN_RECORD(IntPtr p)  
            {  
                this.RecordLength = (UInt32)Marshal.ReadInt32(p);  
                this.FileReferenceNumber = (UInt64)Marshal.ReadInt64(p, FR_OFFSET);  
                this.ParentFileReferenceNumber = (UInt64)Marshal.ReadInt64(p, PFR_OFFSET);  
                this.FileAttributes = (UInt32)Marshal.ReadInt32(p, FA_OFFSET);  
                this.FileNameLength = Marshal.ReadInt16(p, FNL_OFFSET);  
                this.FileNameOffset = Marshal.ReadInt16(p, FN_OFFSET);  
                FileName = Marshal.PtrToStringUni(new IntPtr(p.ToInt32() + this.FileNameOffset), this.FileNameLength / sizeof(char));  
            }  
        }  
 
        #endregion  
    }  
}  
 
        public void EnumerateVolume(  
            out Dictionary<UInt64, FileNameAndFrn> files, string[] fileExtensions)  
        {  
            files = new Dictionary<ulong, FileNameAndFrn>();  
            IntPtr medBuffer = IntPtr.Zero;  
            try  
            {  
                GetRootFrnEntry();  
                GetRootHandle();  
 
                CreateChangeJournal();  
 
                SetupMFT_Enum_DataBuffer(ref medBuffer);  
                EnumerateFiles(medBuffer, ref files, fileExtensions);  
            }  
            catch (Exception e)  
            {  
                Log.Info(e.Message, e);  
                Exception innerException = e.InnerException;  
                while (innerException != null)  
                {  
                    Log.Info(innerException.Message, innerException);  
                    innerException = innerException.InnerException;  
                }  
                throw new ApplicationException("Error in EnumerateVolume()", e);  
            }  
            finally  
            {  
                if (_changeJournalRootHandle.ToInt32() != PInvokeWin32.INVALID_HANDLE_VALUE)  
                {  
                    PInvokeWin32.CloseHandle(_changeJournalRootHandle);  
                }  
                if (medBuffer != IntPtr.Zero)  
                {  
                    Marshal.FreeHGlobal(medBuffer);  
                }  
            }  
        }  
 
        private void GetRootFrnEntry()  
        {  
            string driveRoot = string.Concat("\\\\.\\", _drive);  
            driveRoot = string.Concat(driveRoot, Path.DirectorySeparatorChar);  
            IntPtr hRoot = PInvokeWin32.CreateFile(driveRoot,   
                0,  
                PInvokeWin32.FILE_SHARE_READ | PInvokeWin32.FILE_SHARE_WRITE,   
                IntPtr.Zero,  
                PInvokeWin32.OPEN_EXISTING,  
                PInvokeWin32.FILE_FLAG_BACKUP_SEMANTICS,   
                IntPtr.Zero);  
 
            if (hRoot.ToInt32() != PInvokeWin32.INVALID_HANDLE_VALUE)  
            {  
                PInvokeWin32.BY_HANDLE_FILE_INFORMATION fi = new PInvokeWin32.BY_HANDLE_FILE_INFORMATION();  
                bool bRtn = PInvokeWin32.GetFileInformationByHandle(hRoot, out fi);  
                if (bRtn)  
                {  
                    UInt64 fileIndexHigh = (UInt64)fi.FileIndexHigh;  
                    UInt64 indexRoot = (fileIndexHigh <32) | fi.FileIndexLow;  
 
                    FileNameAndFrn f = new FileNameAndFrn(driveRoot, 0);  
                    _directories.Add(indexRoot, f);  
                }  
                else  
                {  
                    throw new IOException("GetFileInformationbyHandle() returned invalid handle",  
                        new Win32Exception(Marshal.GetLastWin32Error()));  
                }  
                PInvokeWin32.CloseHandle(hRoot);  
            }  
            else  
            {  
                throw new IOException("Unable to get root frn entry", new Win32Exception(Marshal.GetLastWin32Error()));  
            }  
        }  
 
        private void GetRootHandle()  
        {  
            string vol = string.Concat("\\\\.\\", _drive);  
            _changeJournalRootHandle = PInvokeWin32.CreateFile(vol,  
                 PInvokeWin32.GENERIC_READ | PInvokeWin32.GENERIC_WRITE,  
                 PInvokeWin32.FILE_SHARE_READ | PInvokeWin32.FILE_SHARE_WRITE,  
                 IntPtr.Zero,  
                 PInvokeWin32.OPEN_EXISTING,  
                 0,  
                 IntPtr.Zero);  
            if (_changeJournalRootHandle.ToInt32() == PInvokeWin32.INVALID_HANDLE_VALUE)  
            {  
                throw new IOException("CreateFile() returned invalid handle",  
                    new Win32Exception(Marshal.GetLastWin32Error()));  
            }  
        }  
 
        unsafe private void EnumerateFiles(IntPtr medBuffer, ref Dictionary<ulong, FileNameAndFrn> files, string[] fileExtensions)  
        {  
            IntPtr pData = Marshal.AllocHGlobal(sizeof(UInt64) + 0x10000);  
            PInvokeWin32.ZeroMemory(pData, sizeof(UInt64) + 0x10000);  
            uint outBytesReturned = 0;  
 
            while (false != PInvokeWin32.DeviceIoControl(_changeJournalRootHandle, PInvokeWin32.FSCTL_ENUM_USN_DATA, medBuffer,  
                                    sizeof(PInvokeWin32.MFT_ENUM_DATA), pData, sizeof(UInt64) + 0x10000, out outBytesReturned,  
                                    IntPtr.Zero))  
            {  
                IntPtr pUsnRecord = new IntPtr(pData.ToInt32() + sizeof(Int64));  
                while (outBytesReturned > 60)  
                {  
                    PInvokeWin32.USN_RECORD usn = new PInvokeWin32.USN_RECORD(pUsnRecord);  
                    if (0 != (usn.FileAttributes & PInvokeWin32.FILE_ATTRIBUTE_DIRECTORY))  
                    {  
                        //  
                        // handle directories  
                        //  
                        if (!_directories.ContainsKey(usn.FileReferenceNumber))  
                        {  
                            _directories.Add(usn.FileReferenceNumber,  
                                new FileNameAndFrn(usn.FileName, usn.ParentFileReferenceNumber));  
                        }  
                        else  
                        {   // this is debug code and should be removed when we are certain that  
                            // duplicate frn's don't exist on a given drive.  To date, this exception has  
                            // never been thrown.  Removing this code improves performance....  
                            throw new Exception(string.Format("Duplicate FRN: {0} for {1}",   
                                usn.FileReferenceNumber, usn.FileName));  
                        }  
                    }  
                    else  
                    {  
                        //   
                        // handle files  
                        //  
                        bool add = true;  
                        if (fileExtensions != null && fileExtensions.Length != 0)  
                        {  
                            add = false;  
                            string s = Path.GetExtension(usn.FileName);  
                            foreach (string extension in fileExtensions)  
                            {  
                                if (0 == string.Compare(s, extension, true))  
                                {  
                                    add = true;  
                                    break;  
                                }  
                            }  
                        }  
                        if (add)  
                        {  
                            if (!files.ContainsKey(usn.FileReferenceNumber))  
                            {  
                                files.Add(usn.FileReferenceNumber,  
                                    new FileNameAndFrn(usn.FileName, usn.ParentFileReferenceNumber));  
                            }  
                            else  
                            {  
                                FileNameAndFrn frn = files[usn.FileReferenceNumber];  
                                if (0 != string.Compare(usn.FileName, frn.Name, true))  
                                {  
                                    Log.InfoFormat(  
                                        "Attempt to add duplicate file reference number: {0} for file {1}, file from index {2}",  
                                        usn.FileReferenceNumber, usn.FileName, frn.Name);  
                                    throw new Exception(string.Format("Duplicate FRN: {0} for {1}",  
                                        usn.FileReferenceNumber, usn.FileName));  
                                }  
                            }  
                        }  
                    }  
                    pUsnRecord = new IntPtr(pUsnRecord.ToInt32() + usn.RecordLength);  
                    outBytesReturned -usn.RecordLength;  
                }  
                Marshal.WriteInt64(medBuffer, Marshal.ReadInt64(pData, 0));  
            }  
            Marshal.FreeHGlobal(pData);  
        }  
 

 

Viewing all articles
Browse latest Browse all 444

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>