NTFS數據恢復源碼分析

unit uScanThread;

interface

uses
 Classes,Windows,SysUtils,uNTFS;

type
  TScanThread = class(TThread)
  private
    { Private declarations }
    FcurDrive : string;
    diskInfo  : TDISK_INFORMATION;
    FLocation : string;
    FFileName : string;
    FFileExt  : string;
    FFileSize : string;
    FCreateTime : string;
    FLastTime : string;
    procedure UpdateListView;
  protected
    procedure Execute; override;
  public
    constructor Create(suspended: boolean; curDrive: string);
  end;

implementation

uses uMain;

 

 

function Int64TimeToDateTime(aFileTime: Int64): TDateTime;
var
  UTCTime, LocalTime: TSystemTime;
begin
  FileTimeToSystemTime( TFileTime(aFileTime), UTCTime);
  SystemTimeToTzSpecificLocalTime(nil, UTCTime, LocalTime);
  result := SystemTimeToDateTime(LocalTime);
end;

constructor TScanThread.Create(suspended: Boolean; curDrive: string);
begin
  inherited Create(suspended);
  FCurDrive := curDrive;
end;

procedure TScanThread.UpdateListView;
begin
  with MainForm.ListView1.Items.Add do
  begin
    caption := '0x'+ FLocation;
    subitems.Add(FFileName); 文件名
    subitems.Add(FFileExt);文件類型
    subitems.Add(FFileSize);文件大小
    subitems.Add(FCreateTime);文件創建時間
    subItems.Add(FLastTime);文件最後修改時間
  end;
  MainForm.DeleteFileCount.Caption := '刪除的文件數:'+inttostr(MainForm.ListView1.Items.Count);
end;

 

 

procedure TScanThread.Execute;
var
  hDevice, hDest : THandle;
  BootData: array[1..512] of Char;
  MFTData: TDynamicCharArray;
  MFTAttributeData: TDynamicCharArray;
  StandardInformationAttributeData: TDynamicCharArray;
  FileNameAttributeData: TDynamicCharArray;
  DataAttributeHeader: TDynamicCharArray;
  dwread: LongWord;
  dwwritten: LongWord;
  pBootSequence: ^TBOOT_SEQUENCE;
  pFileRecord: ^TFILE_RECORD;
  pMFTNonResidentAttribute : ^TNONRESIDENT_ATTRIBUTE;
  pStandardInformationAttribute : ^TSTANDARD_INFORMATION;
  pFileNameAttribute : ^TFILENAME_ATTRIBUTE;
  pDataAttributeHeader: ^TRECORD_ATTRIBUTE;
  CurrentRecordCounter: integer;
  CurrentRecordLocator: Int64;
  FileName: WideString;
  FileCreationTime, FileChangeTime: TDateTime;
  FileParentDirectoryRecordNumber: Int64;
  FileSize: Int64;
  FileSizeArray : TDynamicCharArray;
  i: integer;

begin

  isSearching := true;
  hDevice := CreateFile( PChar('\\.\'+FcurDrive),      //打開驅動器句柄
                         GENERIC_READ,
                         FILE_SHARE_READ or FILE_SHARE_WRITE,
                         nil,
                         OPEN_EXISTING,
                         FILE_ATTRIBUTE_NORMAL,
                         0);
  if (hDevice = INVALID_HANDLE_VALUE) then  //無效驅動器,停止搜索
  begin
    CloseHandle(hDevice);
    isSearching := false;
    exit;
  end;
  New(PBootSequence);
  ZeroMemory(PBootSequence, SizeOf(TBOOT_SEQUENCE));
  SetFilePointer(hDevice, 0, nil, FILE_BEGIN);
  ReadFile(hDevice,PBootSequence^, 512,dwread,nil);
  MainForm.DriveName.Caption := '名稱: '+ GetVolumeLabel(FcurDrive[1]);
  MainForm.DriveSerial.Caption := '序號: ' + IntToHex(PBootSequence.VolumeSerialNumber,8);
  with PBootSequence^ do
  begin
    if  (cOEMID[1]+cOEMID[2]+cOEMID[3]+cOEMID[4] <> 'NTFS') then   //標識不是NTFS停止搜索
    begin
      Dispose(PBootSequence);
      Closehandle(hDevice);
      isSearching := false;
      exit;
    end
  end;
                                      讀入$MFT

$MFT位置(偏移量) := $MFT的邏輯簇號 *每簇扇區數 *每扇區字節數

diskInfo.BytesPerSector := PBootSequence^.wBytesPerSector;每扇區字節數
  diskInfo.SectorsPerCluster := PBootSequence^.bSectorsPerCluster;  每簇扇區數
  diskInfo.BytesPerCluster := diskInfo.BytesPerSector *
                              diskInfo.SectorsPerCluster;每簇的字節數
  MainForm.DriveSize.Caption := '大小 : '+IntToStr(PBootSequence.TotalSectors *
                                          diskInfo.BytesPerSector)+' 字節';

//磁盤多少字節
  if (PBootSequence^.ClustersPerFileRecord < $80) then
      diskInfo.BytesPerFileRecord := PBootSequence^.ClustersPerFileRecord *
                           diskInfo.BytesPerCluster
   (每MFT記錄字節數 := 每MFT記錄簇數*每簇字節數 )    
  else
      diskInfo.BytesPerFileRecord := 1 shl ($100 - PBootSequence^.ClustersPerFileRecord);

定位mft:
  MFT_Location := PBootSequence^.MftStartLcn * PBootSequence^.wBytesPerSector
   每扇區多少字節                             * PBootSequence^.bSectorsPerCluster;
每簇多少扇區
  MainForm.DriveMFTLocation.Caption := 'MFT位置 : 0x'+IntToHex(MFT_Location,2);
  MainForm.DiskInfo.BytesPerFileRecord := diskInfo.BytesPerFileRecord;每個文件記錄的字節數一般爲512*2
  MainForm.DiskInfo.BytesPerCluster    := diskInfo.BytesPerCluster;每簇的字節數
  MainForm.DiskInfo.BytesPerSector     := diskInfo.BytesPerSector;
  MainForm.DiskInfo.SectorsPerCluster  := diskInfo.SectorsPerCluster; 每簇扇區數


  SetLength(MFTData,diskInfo.BytesPerFileRecord);   //每MFT記錄字節數
  SetFilePointer(hDevice, Int64Rec(MFT_Location).Lo,//(MFT_Location($MFT位置)
                 @Int64Rec(MFT_Location).Hi, FILE_BEGIN);
  Readfile(hDevice, PChar(MFTData)^, diskInfo.BytesPerFileRecord, dwread, nil);
                           (MFTData:存放數據 緩衝區)
  //**** 獲取主記錄 ************************************************************
  if not FixupUpdateSequence(MFTData,diskInfo) then
  begin
    Closehandle(hDevice);
    Dispose(PBootSequence);
    IsSearching := false;
    exit;
  end;

  MFTAttributeData := FindAttributeByType(MFTData,AttributeData);
  New(pMFTNonResidentAttribute);
  ZeroMemory(pMFTNonResidentAttribute, SizeOf(TNONRESIDENT_ATTRIBUTE));
  CopyMemory(pMFTNonResidentAttribute, MFTAttributeData, SizeOf(TNONRESIDENT_ATTRIBUTE));
  if (pMFTNonResidentAttribute^.Attribute.Flags = $8000)
     or (pMFTNonResidentAttribute^.Attribute.Flags = $4000)
     or (pMFTNonResidentAttribute^.Attribute.Flags = $0001) then
  begin
    Dispose(pMFTNonResidentAttribute);
    Closehandle(hDevice);
    Dispose(PBootSequence);
    IsSearching := false;
    exit;
  end;

  MFT_Size := pMFTNonResidentAttribute^.HighVCN - pMFTNonResidentAttribute^.LowVCN;

  Dispose(pMFTNonResidentAttribute);

  MFT_END := MFT_LOCATION + MFT_SIZE;
  MFT_RECORD_COUNT := (MFT_SIZE * diskInfo.BytesPerCluster) div diskInfo.BytesPerFileRecord;
  MainForm.DriveMFTSize.Caption := 'MFT大小 : '+IntToStr(MFT_SIZE * diskInfo.BytesPerCluster)+' 字節';
  MainForm.DriveMFTRecordsCount.Caption := '文件數 : '+IntToStr(MFT_RECORD_COUNT);


  MainForm.listview1.Items.Clear;
  MainForm.PB.Max := MFT_RECORD_COUNT - 16;
  MainForm.PB.Min := 0;
  MainForm.PB.Position := 0;
  MainForm.btnScan.Caption := '停止掃描';    // 按鈕btnScan
  MainForm.btnRecover.Enabled := false;按鈕爲灰色
  for CurrentRecordCounter := 16 to MFT_RECORD_COUNT-1 do
  begin
    if StopScan then
    begin
      break;
    end;
    MainForm.PB.Position := MainForm.PB.Position + 1;
    CurrentRecordLocator := MFT_LOCATION + CurrentRecordCounter * diskInfo.BytesPerFileRecord;
    SetLength(MFTData, diskInfo.BytesPerFileRecord);
    SetFilePointer(hDevice, Int64Rec(CurrentRecordLocator).Lo,
                   @Int64Rec(CurrentRecordLocator).Hi, FILE_BEGIN);
    Readfile(hDevice, PChar(MFTData)^, diskInfo.BytesPerFileRecord, dwread, nil);
    if not FixupUpdateSequence(MFTData,diskInfo) then    // FixupUpdateSequence(更新序列號偏移)
    begin
      continue;
    end;
    New(pFileRecord);
    ZeroMemory(pFileRecord, SizeOf(TFILE_RECORD));
    CopyMemory(pFileRecord, MFTData, SizeOf(TFILE_RECORD));

    if pFileRecord^.Flags=$0 then
    begin
      StandardInformationAttributeData := FindAttributeByType(MFTData, AttributeStandardInformation);
      if StandardInformationAttributeData<>nil then
      begin
        New(pStandardInformationAttribute);
        ZeroMemory(pStandardInformationAttribute, SizeOf(TSTANDARD_INFORMATION));
        CopyMemory(pStandardInformationAttribute, StandardInformationAttributeData,
                   SizeOf(TSTANDARD_INFORMATION));

        FileCreationTime := Int64TimeToDateTime(pStandardInformationAttribute^.CreationTime);
        FileChangeTime := Int64TimeToDateTime(pStandardInformationAttribute^.ChangeTime);
        Dispose(pStandardInformationAttribute);
      end
      else
      begin
        continue;
      end;

      FileNameAttributeData := FindAttributeByType(MFTData, AttributeFileName, true);
      if FileNameAttributeData<>nil then
      begin
        New(pFileNameAttribute);
        ZeroMemory(pFileNameAttribute, SizeOf(TFILENAME_ATTRIBUTE));
        CopyMemory(pFileNameAttribute, FileNameAttributeData, SizeOf(TFILENAME_ATTRIBUTE));
   文件名  FileName:= WideString(Copy(FileNameAttributeData, $5A,pFileNameAttribute^.NameLength*2));
 Dispose(pFileNameAttribute);
      end
      else
      begin
        continue;
      end;

      DataAttributeHeader := FindAttributeByType(MFTData, AttributeData);
      if DataAttributeHeader<>nil then
      begin
        New(pDataAttributeHeader);
        ZeroMemory(pDataAttributeHeader, SizeOf(TRECORD_ATTRIBUTE));
        CopyMemory(pDataAttributeHeader, DataAttributeHeader, SizeOf(TRECORD_ATTRIBUTE));
        FileSizeArray := Copy(DataAttributeHeader, $10+(pDataAttributeHeader^.NonResident)*$20,

                                 (pDataAttributeHeader^.NonResident+$1)*$4 );

//如果屬性頭 ATTRIBUTE.Nonresident標記爲1表示非常駐,這裏是獲得屬性長度//


        FileSize := 0;
        for i:=Length(FileSizeArray)-1 downto 0 do
          FileSize := (FileSize shl 8)+Ord(FileSizeArray[i]);   //將ASCLL碼值轉換爲字符 示例: ord('a')表示a在ASSCLL碼中的序號,爲97
        Dispose(pDataAttributeHeader);
      end
      else
      begin
        continue;
      end;
      FLocation := IntToHex(CurrentRecordLocator,2);
      FFileName := FileName;
      FFileExt  := ExtractFileExt(FileName);
      FFileSize := IntToStr(FileSize);
      FCreateTime := FormatDateTime('c',FileCreationTime);
      FLastTime := FormatDateTime('c',FileChangeTime);
      Synchronize(UpdateListView);
    end;
    Dispose(pFileRecord);
  end;
  Dispose(PBootSequence);
  Closehandle(hDevice);
  isSearching := false;
  MainForm.btnScan.Caption := '掃描磁盤';  按鈕屬性
  MainForm.btnRecover.Enabled := true;
end;

end.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章