Win32 Windows Volume Program and Code Example 24

 

 

 

 

 

Another Day, Another MFT Program Example: List, Recover and Delete the Deleted Files from Master File Table

 

The following program example tries to extend the previous example by adding a 'feature' that can 'delete' a file in the Master File Table.

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

 

Another Day, Another MFT Program Example: List, Recover and Delete the Deleted Files from Master File Table - creating a new Win32 console application project

 

Add the source file and give a suitable name.

 

Another Day, Another MFT Program Example: List, Recover and Delete the Deleted Files from Master File Table - adding a new C++ source file to the existing project

 

Add the following source code.

 

#include <windows.h>

#include <stdio.h>

#include <assert.h>

#include "ntfs.h"

 

// Fixing the offset

#define FIXOFFSET(x, y) ((CHAR*)(x) + (y))

 

// Global variables. Not a good practice

ULONG     BytesPerFileRecord;

UINT     BytesPerCluster;

BOOT_BLOCK    BootBlk;

PFILE_RECORD_HEADER MFT;

HANDLE     hVolume;

FILE     *pFLog;

 

BOOL BitSet(PUCHAR Bitmap, ULONG Idx)

{

      return (Bitmap[Idx >> 3] & (1 << (Idx & 7))) != 0;

}

 

void FixupUpdateSequenceArray(PFILE_RECORD_HEADER FileRecord)

{

      PUSHORT UsAry = PUSHORT(FIXOFFSET(FileRecord, FileRecord->Ntfs.UsaOffset));

      PUSHORT Sector = PUSHORT(FileRecord);

     

      for (ULONG Idx = 1; Idx < FileRecord->Ntfs.UsaCount; Idx++)

      {

            // If( UsAry[0] != Sector[255] ) then this sector is corrupt or broken

            Sector[255] = UsAry[Idx];

            Sector += 256;

      }

}

 

void ZeroSequenceArray(PFILE_RECORD_HEADER FileRecord)

{

      PUSHORT UsAry = PUSHORT(FIXOFFSET(FileRecord, FileRecord->Ntfs.UsaOffset));

     

      for (ULONG Idx = 1; Idx < FileRecord->Ntfs.UsaCount; Idx++)

      {

            UsAry[Idx] = 0x3030;

      }

}

 

void ReadSector(ULONGLONG Sector, ULONG Cnt, PVOID Buffer)

{

      ULARGE_INTEGER Offset;

      OVERLAPPED Overlap = {0};

      ULONG ReadBytes, CntIdx = 0, NeedReadByte = Cnt * BootBlk.BytesPerSector;

     

      // Assign the physical position.

      Offset.QuadPart   = Sector * BootBlk.BytesPerSector;

      // Set position to Overlap.

      Overlap.Offset   = Offset.LowPart;

      Overlap.OffsetHigh = Offset.HighPart;

     

      ReadFile(hVolume, Buffer, NeedReadByte, &ReadBytes, &Overlap);

     

      if(ReadBytes != NeedReadByte)

      {

            while(CntIdx < Cnt)

            {

                  //Set position to Overlap.

                  Overlap.Offset   = Offset.LowPart;

                  Overlap.OffsetHigh = Offset.HighPart;

                 

                  ReadFile(hVolume, Buffer, BootBlk.BytesPerSector, &ReadBytes, &Overlap);

                 

                  if(ReadBytes != BootBlk.BytesPerSector)

                  {

                        wprintf(L"Read Sector failed: %d:%d:%d\n", Offset.LowPart, Cnt * BootBlk.BytesPerSector, ReadBytes);

                        return;

                  }

                 

                  Buffer = (UCHAR*)Buffer + BootBlk.BytesPerSector;

                  // Update the physical position.

                  Offset.QuadPart += BootBlk.BytesPerSector;

                  ++CntIdx;

            }

      }

      return;

}

 

void ReadLCN(ULONGLONG LCN, ULONG Cnt, PVOID Buffer)

{

      ReadSector(LCN * BootBlk.SectorsPerCluster, Cnt * BootBlk.SectorsPerCluster, Buffer);

}

 

void WriteSector(ULONGLONG Sector, ULONG Cnt, PVOID Buffer)

{

      ULARGE_INTEGER Offset;

      OVERLAPPED Overlap = {0};

      ULONG Written;

     

      // Assign the physical position.

      Offset.QuadPart   = Sector * BootBlk.BytesPerSector;

      // Set position to Overlap.

      Overlap.Offset   = Offset.LowPart;

      Overlap.OffsetHigh = Offset.HighPart;

      WriteFile(hVolume, Buffer, Cnt * BootBlk.BytesPerSector, &Written, &Overlap);

     

      if(Written != Cnt * BootBlk.BytesPerSector)

            wprintf(L"Wrote failed: %d:%d:%d\n", Overlap.Offset, Cnt * BootBlk.BytesPerSector, Written);

}

 

void WriteLCN(ULONGLONG LCN, ULONG Cnt, PVOID Buffer)

{

      WriteSector(LCN * BootBlk.SectorsPerCluster, Cnt * BootBlk.SectorsPerCluster, Buffer);

}

 

void ZeroLCN(ULONGLONG LCN, ULONG Cnt)

{

      ULONGLONG ZeroSectorNum=512;

      BYTE *p512Sector = new BYTE[(UINT)BootBlk.BytesPerSector * (UINT)ZeroSectorNum];

      ULONGLONG SectorNum = Cnt * (UINT)BootBlk.SectorsPerCluster;

      ULONGLONG SectorSrtIdx = LCN * BootBlk.SectorsPerCluster, Idx;

      ULONGLONG SectorEndIdx = SectorSrtIdx + SectorNum;

     

      wprintf(L"->Sector Start Index: %d, Zero Sector number is %d\n", (UINT)SectorSrtIdx, (UINT)SectorNum);

     

      memset(p512Sector, '0', (UINT)BootBlk.BytesPerSector * (UINT)ZeroSectorNum);

     

      if(p512Sector)

      {

            Idx = SectorSrtIdx;

           

            while((SectorNum > 0) && (ZeroSectorNum > 0))

            {

                  wprintf(L"\n%d--->", ZeroSectorNum);

                  for(; (Idx < SectorEndIdx) && (SectorNum >= ZeroSectorNum); Idx += ZeroSectorNum)

                  {

                        WriteSector(Idx, (UINT)ZeroSectorNum, p512Sector);

                        SectorNum -= ZeroSectorNum;

                        wprintf(L".");

                  }

                  ZeroSectorNum >>= 1;

            }

           

            if(SectorNum)

            {

                  // Evaluates an expression and, when the result is false,

                  // prints a diagnostic message and aborts the program.

                  assert(SectorNum == 1);

                  WriteSector(Idx, 1, p512Sector);

                  wprintf(L"\n%3d--->.", 1);

            }

           

            wprintf(L"\n");

            delete [] p512Sector;

      }

}

 

ULONG AttributeLength(PATTRIBUTE Attr)

{

      return Attr->Nonresident == FALSE

            ? PRESIDENT_ATTRIBUTE(Attr)->ValueLength: ULONG(PNONRESIDENT_ATTRIBUTE(Attr)->DataSize);

}

 

ULONG AttributeLengthAllocated(PATTRIBUTE Attr)

{

     

      return Attr->Nonresident == FALSE? PRESIDENT_ATTRIBUTE(Attr)->ValueLength:

            ULONG(PNONRESIDENT_ATTRIBUTE(Attr)->AllocatedSize);

}

 

ULONG RunLength(PUCHAR Run)

{

      return (*Run & 0xf) + ((*Run >> 4) & 0xf) + 1;

}

 

ULONGLONG RunCount(PUCHAR Run)

{

      // Get the end index.

      UCHAR Idx = *Run & 0xF;

      ULONGLONG Cnt = 0;

     

      for (; Idx > 0; Idx--)

            Cnt = (Cnt << 8) + Run[Idx];

      return Cnt;

}

 

LONGLONG RunLCN(PUCHAR Run)

{

      UCHAR VCNNumEndIdx = *Run & 0xf;

      UCHAR LCNIdxValNum = (*Run >> 4) & 0xf;

     

      LONGLONG LCN = LCNIdxValNum == 0 ? 0 : CHAR(Run[VCNNumEndIdx + LCNIdxValNum]);

     

      for (LONG Idx = VCNNumEndIdx + LCNIdxValNum - 1; Idx > VCNNumEndIdx; Idx--)

            LCN = (LCN << 8) + Run[Idx];

      return LCN;

}

 

BOOL FindRun(PNONRESIDENT_ATTRIBUTE Attr, ULONGLONG VCN, PULONGLONG LCN, PULONGLONG Cnt)

{

      INT Idx;

     

      if (VCN < Attr->LowVcn || VCN > Attr->HighVcn)

            return FALSE;

     

      *LCN = 0;

      ULONGLONG Base = Attr->LowVcn;

     

      PUCHAR Run = PUCHAR(FIXOFFSET(Attr, Attr->RunArrayOffset));

     

      for (Idx = 0; *Run != 0; Run += RunLength(Run), ++Idx)

      {

            *LCN += RunLCN(Run);

            *Cnt   = RunCount(Run);

           

            if (Base <= VCN && VCN < Base + *Cnt)

            {

                  *LCN = RunLCN(Run) == 0 ? 0 : *LCN + VCN - Base;

                  *Cnt    -= ULONG(VCN - Base);

                  return TRUE;

            }

            else

            {

                  Base += *Cnt;

            }

      }

      *Cnt = 0;

      return FALSE;

}

 

void ZeroExternalAttribute(PNONRESIDENT_ATTRIBUTE Attr, ULONGLONG VCN, ULONG Cnt)

{

      ULONGLONG LCN, RunClstrCnt;

      ULONG RdCnt, Left;

      ULONG ZOBytes = 0;

     

      for (Left = Cnt; Left > 0; Left -= RdCnt)

      {

            FindRun(Attr, VCN, &LCN, &RunClstrCnt);

            RdCnt = ULONG(min(RunClstrCnt, Left));

           

            if(RdCnt != 0)

            {

                  ZOBytes += RdCnt * BytesPerCluster;

                  ZeroLCN(LCN, RdCnt);

                  VCN   += RdCnt;

            }

            else

                  break;

      }

      wprintf(L"Zero data bytes number %d\n", ZOBytes);

}

 

void ReadExternalAttribute(PNONRESIDENT_ATTRIBUTE Attr, ULONGLONG VCN, ULONG Cnt, PVOID Buffer)

{

      ULONGLONG LCN, RunClstrCnt;

      ULONG RdCnt, Left;

      PUCHAR DataPtr = PUCHAR(Buffer);

     

      for (Left = Cnt; Left > 0; Left -= RdCnt)

      {

            FindRun(Attr, VCN, &LCN, &RunClstrCnt);

           

            RdCnt = ULONG(min(RunClstrCnt, Left));

            ULONG RdBytes = RdCnt * BytesPerCluster;

           

            if (LCN == 0)

            {

                  memset(DataPtr, 0, RdBytes);

            }

            else

            {

                  // LCN is physical index of cluster.

                  ReadLCN(LCN, RdCnt, DataPtr);

            }

           

            // Update virtual cluster index.

            VCN   += RdCnt;

            DataPtr += RdBytes;

      }

}

 

void ReadAttribute(PATTRIBUTE Attr, PVOID Buffer)

{

      if (Attr->Nonresident == FALSE)

      {

            PRESIDENT_ATTRIBUTE RAttr = PRESIDENT_ATTRIBUTE(Attr);

            memcpy(Buffer, FIXOFFSET(RAttr, RAttr->ValueOffset), RAttr->ValueLength);

      }

      else

      {

            PNONRESIDENT_ATTRIBUTE NAttr = PNONRESIDENT_ATTRIBUTE(Attr);

            ReadExternalAttribute(NAttr, 0, ULONG(NAttr->HighVcn) + 1, Buffer);

      }

}

 

PATTRIBUTE FindAttribute(PFILE_RECORD_HEADER FileRecord, ATTRIBUTE_TYPE Tp, PWSTR Name)

{

      for (PATTRIBUTE Attr = PATTRIBUTE(FIXOFFSET(FileRecord, FileRecord->AttributesOffset));

            Attr->AttributeType != -1;

            Attr = PATTRIBUTE(FIXOFFSET(Attr, Attr->Length)))

      {

            if (Attr->AttributeType == Tp)

            {

                  // This Attribute hasn't name, found return.

                  if (Name == 0 && Attr->NameLength == 0)

                  {

                        return Attr;

                  }

                 

                  if (Name != 0 && wcslen(Name) == Attr->NameLength

                        && _wcsicmp(Name, PWSTR(FIXOFFSET(Attr, Attr->NameOffset))) == 0)

                  {

                        return Attr;

                  }

            }

      }

      return NULL;

}

 

PATTRIBUTE FindAttributeFileName(PFILE_RECORD_HEADER FileRecord, PWSTR Name)

{

      PATTRIBUTE AttrCp = NULL;

      PFILENAME_ATTRIBUTE FileName;

     

      for (PATTRIBUTE Attr = PATTRIBUTE(FIXOFFSET(FileRecord, FileRecord->AttributesOffset));

            Attr->AttributeType != -1;

            Attr = PATTRIBUTE(FIXOFFSET(Attr, Attr->Length)))

      {

            if (Attr->AttributeType == AttributeFileName)

            {

                  // This Attribute has no name, found return.

                  if (Name == 0 && Attr->NameLength == 0)

                  {

                        AttrCp = Attr;

                        FileName = PFILENAME_ATTRIBUTE(FIXOFFSET(AttrCp,

                              PRESIDENT_ATTRIBUTE(AttrCp)->ValueOffset));

                       

                        if(FileName->NameType == 1)

                              return AttrCp;

                  }

                 

                  if (Name != 0 && wcslen(Name) == Attr->NameLength

                        && _wcsicmp(Name, PWSTR(FIXOFFSET(Attr, Attr->NameOffset))) == 0)

                  {

                        AttrCp = Attr;

                        FileName = PFILENAME_ATTRIBUTE(FIXOFFSET(AttrCp,

                              PRESIDENT_ATTRIBUTE(AttrCp)->ValueOffset));

                       

                        if(FileName->NameType == 1)

                              return AttrCp;

                  }

            }

      }

      return AttrCp;

}

 

void ReadVCN(PFILE_RECORD_HEADER FileRecord, ATTRIBUTE_TYPE Tp, ULONGLONG VCN, ULONG Cnt, PVOID Buffer)

{

      PNONRESIDENT_ATTRIBUTE Attr = PNONRESIDENT_ATTRIBUTE(FindAttribute(FileRecord, Tp, 0));

     

      if (Attr == 0 || (VCN < Attr->LowVcn || VCN > Attr->HighVcn))

      {

            PATTRIBUTE Attrlist = FindAttribute(FileRecord, AttributeAttributeList, 0);

            // Will cause a breakpoint exception to occur in the current process.

            DebugBreak();

      }

      ReadExternalAttribute(Attr, VCN, Cnt, Buffer);

}

 

ULONGLONG GetLCN(ULONG Idx)

{

      ULONGLONG VCN = ULONGLONG(Idx) * BytesPerFileRecord / BytesPerCluster;

      PNONRESIDENT_ATTRIBUTE Attr = PNONRESIDENT_ATTRIBUTE(FindAttribute(MFT, AttributeData, 0));

      ULONGLONG LCN, RunClstrCnt;

     

      if(FindRun(Attr, VCN, &LCN, &RunClstrCnt) == FALSE)

            return 0;

      return LCN;

}

 

void ReadFileRecord(ULONG Idx, PFILE_RECORD_HEADER FileRecord)

{

      ULONG ClstrNum = BootBlk.ClustersPerFileRecord;

     

      if (ClstrNum > 0x80)

            ClstrNum = 1;

      PUCHAR BufPtr = new UCHAR[BytesPerCluster * ClstrNum];

     

      ULONGLONG VCN = ULONGLONG(Idx) * BytesPerFileRecord / BytesPerCluster;

 

    ReadVCN(MFT, AttributeData, VCN, ClstrNum, BufPtr);

     

      LONG FRPerCluster = (BytesPerCluster / BytesPerFileRecord) - 1;

      ULONG FRIdx = FRPerCluster > 0 ? (Idx & FRPerCluster) : 0;

     

      memcpy(FileRecord, BufPtr + FRIdx * BytesPerFileRecord, BytesPerFileRecord);

      delete [] BufPtr;

}

 

void ListDeleted()

{

      ULONG Idx;

      PATTRIBUTE Attr = (PATTRIBUTE)FindAttribute(MFT, AttributeBitmap, 0);

      PUCHAR Bitmap   = new UCHAR[AttributeLengthAllocated(Attr)];

     

      ReadAttribute(Attr, Bitmap);

      ULONG Num = AttributeLength(FindAttribute(MFT, AttributeData, 0)) / BytesPerFileRecord;

 

      fwprintf(pFLog, L"\nMFT Data number %u\n\n", Num);

 

      PFILE_RECORD_HEADER FileRecord = PFILE_RECORD_HEADER(new UCHAR[BytesPerFileRecord]);

     

      for (Idx = 0; Idx < Num; Idx++)

      {

            if (BitSet(Bitmap, Idx))

                  continue;

 

            ReadFileRecord(Idx, FileRecord);

            FixupUpdateSequenceArray(FileRecord);

 

            if (FileRecord->Ntfs.Type == 'ELIF' && (FileRecord->Flags & 1) == 0)

            {

                  Attr = (PATTRIBUTE)FindAttributeFileName(FileRecord, 0);

                  if (Attr == 0)

                        continue;

 

                  PFILENAME_ATTRIBUTE Name = PFILENAME_ATTRIBUTE(FIXOFFSET(Attr, PRESIDENT_ATTRIBUTE(Attr)->ValueOffset));

                  fwprintf(pFLog, L"%10u, %3d, %ws\n", Idx, INT(Name->NameLength), Name->Name);

                  // To see the index, file name length and the file name displayed on the standard output,

                  // uncomment the following line

                  // wprintf(L"%10u %u, %ws\n", Idx, INT(Name->NameLength), Name->Name);

            }

      }

      delete [] Bitmap;

      delete [] (UCHAR*)FileRecord;

}

 

void LoadMFT()

{

      BytesPerCluster = BootBlk.SectorsPerCluster * BootBlk.BytesPerSector;

      BytesPerFileRecord = BootBlk.ClustersPerFileRecord < 0x80

            ? BootBlk.ClustersPerFileRecord * BytesPerCluster : (1 << (0x100 - BootBlk.ClustersPerFileRecord));

 

      wprintf(L"Cluster Per File Record: %u\n", BootBlk.ClustersPerFileRecord);

      wprintf(L"Bytes Per File Record: %u\n", BytesPerFileRecord);

 

      MFT = PFILE_RECORD_HEADER(new UCHAR[BytesPerFileRecord]);

      ReadSector(BootBlk.MftStartLcn * BootBlk.SectorsPerCluster,BytesPerFileRecord / BootBlk.BytesPerSector, MFT);

      FixupUpdateSequenceArray(MFT);

}

 

VOID UnloadMFT()

{

      // Clean up

      wprintf(L"Unloading MFT...\n");

      delete [] (UCHAR*)MFT;

}

 

void RemoveFile(ULONG Idx)

{

      PFILE_RECORD_HEADER FileRecord = PFILE_RECORD_HEADER(new UCHAR[BytesPerFileRecord]);

      UCHAR *ClustersBuf;

      ULONG BufferSize, DataSize, AllocatedSize, Position, LCN, ClstrNum;

     

      ReadFileRecord(Idx, FileRecord);

      FixupUpdateSequenceArray(FileRecord);

     

      if (FileRecord->Ntfs.Type != 'ELIF')

      {

            wprintf(L"RemoveFile() - FileRecord->Ntfs.Type != \'ELIF\'...\n");

            delete [] (UCHAR*)FileRecord;

            return;

      }

 

      PATTRIBUTE Attr = FindAttribute(FileRecord, AttributeData, 0);

 

      if (Attr == 0)

      {

            wprintf(L"RemoveFile() - Attr == 0...\n");

            delete [] (UCHAR*)FileRecord;

            return;

      }

 

      DataSize   = AttributeLength(Attr);

      AllocatedSize = AttributeLengthAllocated(Attr);

      BufferSize   = AllocatedSize > DataSize ? AllocatedSize : DataSize;

     

      PUCHAR Buffer   = new UCHAR[BufferSize + 1];

 

      ClstrNum   = BootBlk.ClustersPerFileRecord;

     

      if (ClstrNum > 0x80)

            ClstrNum = 1;

 

      ClustersBuf     = new UCHAR[BytesPerCluster * ClstrNum];

     

      if (Attr->Nonresident == FALSE)

      {

            wprintf(L"This file data is resident!\n");

            PRESIDENT_ATTRIBUTE RAttr = PRESIDENT_ATTRIBUTE(Attr);

            LONG FRPerCluster = (BytesPerCluster / BytesPerFileRecord) - 1;

            ULONG FRIdx = FRPerCluster > 0 ? (Idx & FRPerCluster) : 0;

 

            Position = (ULONG)(FIXOFFSET(RAttr, RAttr->ValueOffset)) - (ULONG)FileRecord;

            Position = FRIdx * BytesPerFileRecord + Position;

 

            if(LCN = (ULONG)GetLCN(Idx), LCN)

            {

                  // Read file record

                  ReadLCN(LCN, ClstrNum, ClustersBuf);

                  FixupUpdateSequenceArray((FILE_RECORD_HEADER*)&ClustersBuf[FRIdx * BytesPerFileRecord]);

                  ZeroSequenceArray((FILE_RECORD_HEADER*)&ClustersBuf[FRIdx * BytesPerFileRecord]);

                  memset(&ClustersBuf[Position], '0', DataSize);

                  WriteLCN(LCN, ClstrNum, ClustersBuf);

            }

      }

      else

      {

            wprintf(L"This file data is nonresident!\n");

            PNONRESIDENT_ATTRIBUTE NAttr = PNONRESIDENT_ATTRIBUTE(Attr);

            ZeroExternalAttribute(NAttr, 0, ULONG(NAttr->HighVcn) + 1);

      }

      wprintf(L" Removed file should be succeeded!\n");

      wprintf(L" The file\'s content should be empty!!!\n");

}

 

void RecoverFile(ULONG Idx, LPCWSTR NewFileName)

{

      PFILE_RECORD_HEADER FileRecord = PFILE_RECORD_HEADER(new UCHAR[BytesPerFileRecord]);

      ULONG Written, BufferSize, DataSize, AllocatedSize;

      ReadFileRecord(Idx, FileRecord);

      FixupUpdateSequenceArray(FileRecord);

     

      if (FileRecord->Ntfs.Type != 'ELIF')

      {

            delete [] (UCHAR*)FileRecord;

            wprintf(L"Failed. FileRecord->Ntfs.Type != 'ELIF'\n");

            return;

      }

     

      PATTRIBUTE Attr = FindAttribute(FileRecord, AttributeData, 0);

     

      if (Attr == 0)

      {

            delete [] (UCHAR*)FileRecord;

            wprintf(L"Failed, Attr == 0!\n");

            return;

      }

 

      DataSize   = AttributeLength(Attr);

      AllocatedSize = AttributeLengthAllocated(Attr);

      BufferSize   = AllocatedSize > DataSize ? AllocatedSize : DataSize;

      // Align

      BufferSize    = BufferSize / BootBlk.BytesPerSector * BootBlk.BytesPerSector + BootBlk.BytesPerSector;

     

      PUCHAR Buffer = new UCHAR[BufferSize];

     

      wprintf(L"RecoverFile() - Reading the deleted file data...\n");

      ReadAttribute(Attr, Buffer);

     

      HANDLE hFile = CreateFile(NewFileName, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);

 

     

      if(hFile == INVALID_HANDLE_VALUE)

      {

            wprintf(L"RecoverFile() - CreateFile() failed, error %u\n", GetLastError());

            exit(1);

      }

     

      if(WriteFile(hFile, Buffer, DataSize, &Written, 0) == 0)

      {

            wprintf(L"RecoverFile() - WriteFile() failed, error %u\n", GetLastError());

            exit(1);

      }

     

      // Another check

      // Written = the number of byte to be written

      if(Written != DataSize)

            wprintf(L"Writing the file data failed!, error %u\n", GetLastError());

 

      CloseHandle(hFile);

      delete [] Buffer;

      delete [] (UCHAR*)FileRecord;

}

 

int wmain(int argc, WCHAR *argv[])

{

      // Default partition

      WCHAR Drive[] = L"\\\\?\\C:";

      ULONG Read, Idx;

      LPCWSTR OriFileName = L"";

      errno_t ernoFLog1;

      WCHAR *cOption = L"A";

     

      // Give some info to clueless user

      wprintf(L"Usages:\n");

      wprintf(L"(Default primary partition is C:\\\n");

      wprintf(L"1. %s - Attempting to list the deleted files...\n", argv[0]);

      wprintf(L"     (The deleted files stored in C:\\DeletedFile.txt)\n");

      wprintf(L"2. Finding the deleted file\n");

      wprintf(L"     %s <file_index> <original_file_name>\n", argv[0]);

      wprintf(L"     (The index and file name can be found in C:\\DeletedFile.txt)\n");

      wprintf(L"     e.g. %s  123546 tergedik.txt\n", argv[0]);

      wprintf(L"3. Removing the deleted file\n");

      wprintf(L"     %s <file_index_to_be_removed>\n", argv[0]);

      wprintf(L"     e.g. %s 123546\n", argv[0]);

      wprintf(L"===Press any key to continue!===\n");

     

      // Let them read for a while

      getwchar();

 

      ernoFLog1 = _wfopen_s(&pFLog, L"C:\\DeletedFile.txt", L"w");

     

      if(ernoFLog1 != 0)

      {

            wprintf(L"_wfopen_s() failed, error %u\n", _get_errno(&ernoFLog1));

            exit(1);

      }

 

      hVolume = CreateFile(

            Drive,

            GENERIC_READ | GENERIC_WRITE , FILE_SHARE_READ | FILE_SHARE_WRITE,

            0,

            OPEN_EXISTING,

            0,

            0);

 

      if( hVolume == INVALID_HANDLE_VALUE)

      {

            wprintf(L"CreateFile() failed, error %u\n", GetLastError());

            exit(1);

      }

     

      if(ReadFile(hVolume, &BootBlk, sizeof(BOOT_BLOCK), &Read, 0) == 0)

      {

            wprintf(L"ReadFile() failed, error %u\n", GetLastError());

            exit(1);

      }

 

      wprintf(L"Read volume should succeeded...\n");

     

      LoadMFT();

     

      wprintf(L"Load MFT succeed:\n");

      wprintf(L" Bytes Per Sector:Sectors Per Cluster:Clusters Per FileRecord-->");

      wprintf(L" %u:%u:%u.\n", BootBlk.BytesPerSector, BootBlk.SectorsPerCluster, BootBlk.ClustersPerFileRecord);

     

      wprintf(L"Attempt to list the deleted files.........\n");

      wprintf(L"   Find them in C:\\DeletedFile.txt lol!\n");

      ListDeleted();

     

      // Attempt to find the deleted file from MFT

      if(argc == 3)

      {

            // Use the index and the original file name for recovery.

            // The recovered file stored under the project's debug folder.

            // The index and original file name can be found in C:\DeletedFile.txt

            Idx = _wtoi(argv[1]);

            OriFileName = argv[2];

            wprintf(L"Recovered file should be in the projects\'s Debug folder!\n");

            RecoverFile(Idx, OriFileName);

      }

 

      // Attempt to delete the 'file' from MFT

      if(argc == 2)

      {

            // Use the index to remove the file

            Idx = _wtoi(argv[1]);

            RemoveFile(Idx);

      }

     

      // Free up all the resources.

      // Look likes some of the malloc() are not freed lol! Who cares?

      // You can do it...

      UnloadMFT();

      CloseHandle(hVolume);

      fclose(pFLog);

}

 

 

 

  < Windows Volume 23 | Win32 Programming Index | Windows Volume Index | Windows Volume 25 >