如何编码实现NTFS格式下删除文件的恢复(续一)

上节地址:http://blog.csdn.net/A00553344/archive/2009/12/18/5031993.aspx

7.    主文件列表(MFT)记录详解

了解了NTFS的基本结构后,现在来详细分析MFT表内的记录,它是NTFS格式存储的关键内容。

 

常驻属性和“非常驻属性

 

    前面我们知道,磁盘上的每一个文件(目录)对应MFT表内的一条记录,记录的大小是1KB,记录的内容是文件的所有属性,包括文件本身的数据也当成属性来存储。那么问题来了,对于很多文件来说,本身的数据就大于1KB,那么记录是怎么存储的呢?NTFS系统是这么规定的,当文件属性太大的时候(比如文件的数据属性)NTFS系统会将该属性值存放到卷中某个位置,而MFT记录的内容只会记录该属性索引到外部的地址,以及索引区的大小。这种属性被称为文件的“非常驻属性”。与之相反,能够保存在FMT内的的属性叫做“常驻属性”。

 

下表是MFT记录的属性列表,每一个MFT记录只包含其中的一部分属性,不会包含所有的属性。

属性号

属性名

属性描述

0x10

$STANDRD_INFORMATION(标准属性)

包括基本文件属性,如只读、存档;时间标记,如文件的创建时间和最近一次修改的时间;有多少目录指向本文件

0x20

$ATTRIBUTE_LIST(属性列表)

当一个文件需要使用多个MFT文件记录时,用来表示该文件的属性列表

0x30

$FILE_NAME(文件名属性)

这是以Unicode字符表示的,由于MS-DOS不能正确识别Win32子系统创建的文件名,当Win32子系统创建一个文件名时,MTFS会自动生成一个备用的MS-DOS文件名,所以一个文件可以有多种文件名属性。  

0x40

$VOLUME_VERSION(卷版本)

卷版本号

0x50

$SECURITY_DEscriptOR(安全描述符)

这是为了向后兼容而被保留的,主要用于保护文件以防止未授权访问。

0x60

$VOLUME_NAME(卷名)

卷名称或卷标识

0x70

$VOLUME_INFORMATION(卷信息)

卷信息

0x80

$DATA(数据属性)

这是文件的内容

0x90

$INDEX_ROOT(索引根属性)

索引根

0xA0

$INDEX_ALLOCATION(索引分配属性)

索引分配

0xB0

$BITMAP(位图属性)

位图

0xC0

$SYMBOLIC_LINK(符号链接)

符号链接

0xD0

$EA_INFORMATION(EA信息)

扩充属性信息:主要为与OS/2兼容

0xE0

$EA

扩充属性:主要为与OS/2兼容

0x100

$OBJECT_ID

对象ID:一个具有64个字节的标识符,其中最低的16个字节对卷来说是唯一的

 

读到这里,我们来实际编码读点数据来加深印象。

 

第一步:读入引导扇区

 

定义一个引导区的结构

Type

PBOOT_SEQUENCE = TBOOT_SEQUENCE^; 

TBOOT_SEQUENCE = packed record        // 引导扇区数据结构

    _jmpcode : array[1..3] of Byte;

   cOEMID: array[1..8] of Char;

      wBytesPerSector: Word;

      bSectorsPerCluster: Byte;

    wSectorsReservedAtBegin: Word;

      Mbz1: Byte;

      Mbz2: Word;

      Reserved1: Word;

      bMediaDescriptor: Byte;

      Mbz3: Word;

      wSectorsPerTrack: Word;

      wSides: Word;

      dwSpecialHiddenSectors: DWord;

      Reserved2: DWord;

      Reserved3: DWord;

      TotalSectors: Int64;

      MftStartLcn: Int64;

      Mft2StartLcn: Int64;

      ClustersPerFileRecord: DWord;

      ClustersPerIndexBlock: DWord;

      VolumeSerialNumber: Int64;

      _loadercode: array[1..430] of Byte;

      wSignature: Word;

end;

 

procedure SaveDebugInfo(var buffer; bufSize: Cardinal; filename: string);

var

  debugF : TFileStream;

begin

  debugF := TFileStream.Create(filename,fmCreate);

  try

    debugF.Write(buffer,bufSize);

  finally

    debugF.Free;

  end;

 

end;

procedure Button1Click(Sender: Tobject);

var

  hDevice       : THANDLE;

  PbootSequence : PBOOT_SEQUENCE;

  dwRead        : Cardinal;

begin

  hDevice := CreateFile( PChar('//./E'),

                         GENERIC_READ,

                         FILE_SHARE_READ or FILE_SHARE_WRITE,

                         nil,

                         OPEN_EXISTING,

                         FILE_ATTRIBUTE_NORMAL,

                         0);

  if (hDevice = INVALID_HANDLE_VALUE) then

  begin

    Showmessage('无法读写磁盘!');

    CloseHandle(hDevice);

   exit;

  end;

  New(PBootSequence);

  ZeroMemory(PBootSequence, SizeOf(TBOOT_SEQUENCE));

  SetFilePointer(hDevice, 0, nil, FILE_BEGIN);

  ReadFile(hDevice,PBootSequence^, 512,dwread,nil);

SaveDebugInfo(PBootSequence^,sizeof(TBOOT_SEQUENCE),'boot_sector.bin');

Dispose(PBootSequence);

Closehandle(hDevice);

End;

读入的引导区为下图:

 

每扇区字节数(红色):0x0200

每簇扇区数(蓝色): 0x08

$MFT的逻辑簇号(黄色)0x0000000000000004

MFT记录簇数(绿色): 0x000000F6

 

 

 

第二步 读入MFT

我们知道MFT的第一条记录是本身。现在已经知道了

1.      每扇区字节数(红色):0x0200

2.      每簇扇区数(蓝色): 0x08

3.       $MFT的逻辑簇号(黄色) 0x0000000000000004

4.       MFT记录簇数(绿色): 0x000000F6

可以计算出$MFT的位置和MFT中每条记录的大小(通常是1KB):

$MFT位置(偏移量) := $MFT的逻辑簇号 *每簇扇区数 *每扇区字节数

MFT记录簇数不能直接拿来计算每条记录的大小,要看它是否小于0x80,计算公式如下:

  if (MFT记录簇数 < $80) then

      MFT记录字节数 := MFT记录簇数*每簇字节数;

  else

      MFT记录字节数 := 1 shl ($100 -MFT记录簇数)

我们现在获得$MFT的偏移动位置及$MFT中每条记录的大小,这样我们就可以读出$MFT中的第一条记录,即对应$MFT文件自身的那条记录。

代码:

  SetLength(存放数据的缓冲区, MFT记录字节数);

  SetFilePointer(hDevice, Int64Rec($MFT位置).Lo,

                 @Int64Rec($MFT位置).Hi, FILE_BEGIN);

  Readfile(hDevice, PChar(存放数据的缓冲区)^, MFT记录字节数, dwread, nil);

SaveDebugInfo(存放数据的缓冲区, MFT记录字节数,'MFT.bin');

读到的对应$FMT文件的记录为:

  • 红色部分: 记录属性头,所有的MFT记录都有这一部分.
  • 绿色部分: $STANDRD_INFORMATION(标准属性包括基本文件属性,如只读、存档;时间标记,如文件的创建时间和最近一次修改的时间;有多少目录指向本文件  
  • 蓝色部分: $FILE_NAME(文件名属性这是以Unicode字符表示的,由于MS-DOS不能正确识别Win32子系统创建的文件名,当Win32子系统创建一个文件名时,MTFS会自动生成一个备用的MS-DOS文件名,所以一个文件可以有多种文件名属性。
  • 灰色部分$DATA(数据属性这是文件的内容 
  • 紫色部分$BITMAP(位图属性位图  
  • 最后的FF FF FF FF 00 00 00 00 为一条MFT记录的结束标志.

 

 

 

  • 0
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值