Win32 Windows Volume Program and Code Example 21

 

 

 

Master File Table Program Example 2: Reading and Dumping the Deleted Files

 

The following program example tries to read the file record header from Master File Table.

Create a new Win32 console application project and give a suitable project name.

 

Master File Table Program Example 2: Reading and Dumping the Deleted Files - creating a new Win32 console mode application

 

Add the source file and give a suitable name.

 

Master File Table Program Example 2: Reading and Dumping the Deleted Files - adding a new C++ source file

 

 

 

Add the following source code.

 

#include <windows.h>

#include <stdio.h>

#include <winioctl.h>

 

typedef struct {

      ULONG Type;

      USHORT UsaOffset;

      USHORT UsaCount;

      USN Usn;

} NTFS_RECORD_HEADER, *PNTFS_RECORD_HEADER;

 

// Type needed for interpreting the MFT-records

typedef struct {

    NTFS_RECORD_HEADER RecHdr;    // An NTFS_RECORD_HEADER structure with a Type of 'FILE'.

    USHORT SequenceNumber;        // Sequence number - The number of times

                                                  // that the MFT entry has been reused.

    USHORT LinkCount;             // Hard link count - The number of directory links to the MFT entry

    USHORT AttributeOffset;       // Offset to the first Attribute - The offset, in bytes,

                                                  // from the start of the structure to the first attribute of the MFT

    USHORT Flags;                 // Flags - A bit array of flags specifying properties of the MFT entry

                                                  // InUse 0x0001 - The MFT entry is in use

                                                  // Directory 0x0002 - The MFT entry represents a directory

    ULONG BytesInUse;             // Real size of the FILE record - The number of bytes used by the MFT entry.

    ULONG BytesAllocated;         // Allocated size of the FILE record - The number of bytes

                                                  // allocated for the MFT entry

    ULONGLONG BaseFileRecord;     // reference to the base FILE record - If the MFT entry contains

                                                  // attributes that overflowed a base MFT entry, this member

                                                  // contains the file reference number of the base entry;

                                                  // otherwise, it contains zero

    USHORT NextAttributeNumber;   // Next Attribute Id - The number that will be assigned to

                                                  // the next attribute added to the MFT entry.

    USHORT Pading;                // Align to 4 byte boundary (XP)

    ULONG MFTRecordNumber;        // Number of this MFT Record (XP)

    USHORT UpdateSeqNum;          //

} FILE_RECORD_HEADER, *PFILE_RECORD_HEADER;

 

 

// Convert the Win32 system error code to string

void ErrorMessage(DWORD dwCode);

 

int wmain(int argc, WCHAR **argv)

{

      HANDLE hVolume;

      LPWSTR lpDrive = L\\\\.\\c:;

      NTFS_VOLUME_DATA_BUFFER ntfsVolData = {0};

      BOOL bDioControl = FALSE;

      DWORD dwWritten = 0;

      DWORD lpBytesReturned = 0;

      FILE_RECORD_HEADER  FileRecHdr = {0};

      // Variables for MFT-reading

      NTFS_FILE_RECORD_INPUT_BUFFER   ntfsFileRecordInput;

      PNTFS_FILE_RECORD_OUTPUT_BUFFER ntfsFileRecordOutput;

     

      hVolume = CreateFile(lpDrive,

            GENERIC_READ | GENERIC_WRITE,

            FILE_SHARE_READ | FILE_SHARE_WRITE,

            NULL,

            OPEN_EXISTING,

            0,

            NULL);

 

      if(hVolume == INVALID_HANDLE_VALUE)

      {

            wprintf(LCreateFile() failed!\n);

            ErrorMessage(GetLastError());

            if(CloseHandle(hVolume) != 0)

                  wprintf(LhVolume handle was closed successfully!\n);

            else

            {

                  wprintf(LFailed to close hVolume handle!\n);

                  ErrorMessage(GetLastError());

            }

            exit(1);

      }

      else

            wprintf(LCreateFile() is pretty fine!\n);

     

     

      // get ntfsVolData by calling DeviceIoControl()

      // with CtlCode FSCTL_GET_NTFS_VOLUME_DATA

      // setup output buffer - FSCTL_GET_NTFS_FILE_RECORD depends on this

     

      // a call to FSCTL_GET_NTFS_VOLUME_DATA returns the structure NTFS_VOLUME_DATA_BUFFER

      bDioControl = DeviceIoControl(hVolume, FSCTL_GET_NTFS_VOLUME_DATA, NULL, 0, &ntfsVolData, sizeof(ntfsVolData), &dwWritten, NULL);

 

      // Failed or pending

      if(bDioControl == 0)

      {

            wprintf(LDeviceIoControl() failed!\n);

            ErrorMessage(GetLastError());

            if(CloseHandle(hVolume) != 0)

                  wprintf(LhVolume handle was closed successfully!\n);

            else

            {

                  wprintf(LFailed to close hVolume handle!\n);

                  ErrorMessage(GetLastError());

            }

            exit(1);

      }

      else

            wprintf(L1st DeviceIoControl(...,FSCTL_GET_NTFS_VOLUME_DATA,...) call is working...\n);

 

      //a call to FSCTL_GET_NTFS_VOLUME_DATA returns the structure NTFS_VOLUME_DATA_BUFFER

      ntfsFileRecordOutput = (PNTFS_FILE_RECORD_OUTPUT_BUFFER)

            malloc(sizeof(NTFS_FILE_RECORD_OUTPUT_BUFFER)+ntfsVolData.BytesPerFileRecordSegment-1);

 

      if(ntfsFileRecordOutput == NULL)

            wprintf(LInsufficient memory lol!\n);

      else

            wprintf(LMemory allocated successfully!\n);

     

      // The MFT-record #5 is the root-dir???

      ntfsFileRecordInput.FileReferenceNumber.QuadPart = 5;

     

      bDioControl = DeviceIoControl(

            hVolume,

            FSCTL_GET_NTFS_FILE_RECORD,

        &ntfsFileRecordInput,

        sizeof(NTFS_FILE_RECORD_INPUT_BUFFER),

        ntfsFileRecordOutput,

        sizeof(NTFS_FILE_RECORD_OUTPUT_BUFFER)+ntfsVolData.BytesPerFileRecordSegment-1,

        &lpBytesReturned, NULL);

     

      // Failed or pending

      if(bDioControl == 0)

      {

            wprintf(LDeviceIoControl() failed!\n);

            ErrorMessage(GetLastError());

            if(CloseHandle(hVolume) != 0)

            {

                  wprintf(LhVolume handle was closed successfully!\n);

            }

            else

            {

                  wprintf(LFailed to close hVolume handle!\n);

                  ErrorMessage(GetLastError());

            }

            exit(1);

      }

      else

            wprintf(L2nd DeviceIoControl(...,FSCTL_GET_NTFS_FILE_RECORD,...) call is working...\n);

     

            // read the record header from start of MFT-record

            if(!(memcpy(&FileRecHdr, &ntfsFileRecordOutput->FileRecordBuffer[0], sizeof(FILE_RECORD_HEADER))))

                  wprintf(Lmemcpy() failed!\n);

            else

                  wprintf(Lmemcpy() is OK!\n\n);

 

            wprintf(LAttributeOffset: %u\n,FileRecHdr.AttributeOffset);

            wprintf(LBaseFileRecord: %u\n,FileRecHdr.BaseFileRecord);

            wprintf(LBytesAllocated: %u\n,FileRecHdr.BytesAllocated);

            wprintf(LBytesInUse: %u\n,FileRecHdr.BytesInUse);

            wprintf(LFlags: %u\n,FileRecHdr.Flags);

            wprintf(LLinkCount: %u\n,FileRecHdr.LinkCount);

            wprintf(LMFTRecordNumber: %u\n,FileRecHdr.MFTRecordNumber);

            wprintf(LNextAttributeNumber: %u\n,FileRecHdr.NextAttributeNumber);

            wprintf(LPading: %u\n,FileRecHdr.Pading);

            wprintf(LRecHdr: %u\n,FileRecHdr.RecHdr);

            wprintf(LSequenceNumber: %u\n,FileRecHdr.SequenceNumber);

            wprintf(LUpdateSeqNum: %u\n,FileRecHdr.UpdateSeqNum);

 

      if(CloseHandle(hVolume) != 0)

            wprintf(LhVolume handle was closed successfully!\n);

      else

      {

            wprintf(LFailed to close hVolume handle!\n);

            ErrorMessage(GetLastError());

      }

 

      // Free up the allocated memory by malloc()

      free(ntfsFileRecordOutput);

 

      return 0;

}

 

void ErrorMessage(DWORD dwCode)

{

    // get the error code...

    DWORD dwErrCode = dwCode;

    DWORD dwNumChar;

 

    LPWSTR szErrString = NULL;  // will be allocated and filled by FormatMessage

 

    dwNumChar = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER |

                 FORMAT_MESSAGE_FROM_SYSTEM, // use windows internal message table

                 0,       // 0 since source is internal message table

                 dwErrCode, // this is the error code number

                 0,       // auto-determine language to use

                 (LPWSTR)&szErrString, // the messsage

                 0,                 // min size for buffer

                 0 );               // since getting message from system tables

      if(dwNumChar == 0)

            wprintf(LFormatMessage() failed, error %u\n, GetLastError());

      //else

      //    wprintf(LFormatMessage() should be fine!\n);

 

     wprintf(LError code %u:\n  %s\n, dwErrCode, szErrString) ;

 

      // This buffer used by FormatMessage()

    if(LocalFree(szErrString) != NULL)

            wprintf(LFailed to free up the buffer, error %u\n, GetLastError());

      //else

      //    wprintf(LBuffer has been freed\n);

  }

 

 

Build and run the project. The following screenshot is an output sample.

 

Master File Table Program Example 2: Reading and Dumping the Deleted Files - a sample console output

 

 

  < Windows Volume 20 | Win32 Programming Index | Windows Volume Index | Windows Volume 22 >