如何编码实现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记录的结束标志.

 

 

 

展开阅读全文

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

12-19

上贴地址:[url=http://hi.csdn.net/link.php?url=http://topic.csdn.net%2Fu%2F20091218%2F15%2F43f7e6e0-244f-4d45-9564-0e32cd1974d2.html]http://hi.csdn.net/link.php?url=http://topic.csdn.net%2Fu%2F20091218%2F15%2F43f7e6e0-244f-4d45-9564-0e32cd1974d2.html[/url]rnrn7. 主文件列表(MFT)记录详解rnrnrn了解了NTFS的基本结构后,现在来详细分析MFT表内的记录,它是NTFS格式存储的关键内容。rnrn rnrn“常驻属性”和“非常驻属性”rnrnrn 前面我们知道,磁盘上的每一个文件(目录)对应MFT表内的一条记录,记录的大小是1KB,记录的内容是文件的所有属性,包括文件本身的数据也当成属性来存储。那么问题来了,对于很多文件来说,本身的数据就大于1KB,那么记录是怎么存储的呢?NTFS系统是这么规定的,当文件属性太大的时候(比如文件的数据属性),NTFS系统会将该属性值存放到卷中某个位置,而MFT记录的内容只会记录该属性索引到外部的地址,以及索引区的大小。这种属性被称为文件的“非常驻属性”。与之相反,能够保存在FMT内的的属性叫做“常驻属性”。rnrnrn下表是MFT记录的属性列表,每一个MFT记录只包含其中的一部分属性,不会包含所有的属性。rnrn属性号rn 属性名rn 属性描述rn rn0x10rn $STANDRD_INFORMATION(标准属性)rn 包括基本文件属性,如只读、存档;时间标记,如文件的创建时间和最近一次修改的时间;有多少目录指向本文件rn rn0x20rn $ATTRIBUTE_LIST(属性列表)rn 当一个文件需要使用多个MFT文件记录时,用来表示该文件的属性列表rn rn0x30rn $FILE_NAME(文件名属性)rn 这是以Unicode字符表示的,由于MS-DOS不能正确识别Win32子系统创建的文件名,当Win32子系统创建一个文件名时,MTFS会自动生成一个备用的MS-DOS文件名,所以一个文件可以有多种文件名属性。 rn rn0x40rn $VOLUME_VERSION(卷版本)rn 卷版本号rn rn0x50rn $SECURITY_DEscriptOR(安全描述符)rn 这是为了向后兼容而被保留的,主要用于保护文件以防止未授权访问。rn rn0x60rn $VOLUME_NAME(卷名)rn 卷名称或卷标识rn rn0x70rn $VOLUME_INFORMATION(卷信息)rn 卷信息rn rn0x80rn $DATA(数据属性)rn 这是文件的内容rn rn0x90rn $INDEX_ROOT(索引根属性)rn 索引根rn rn0xA0rn $INDEX_ALLOCATION(索引分配属性)rn 索引分配rn rn0xB0rn $BITMAP(位图属性)rn 位图rn rn0xC0rn $SYMBOLIC_LINK(符号链接)rn 符号链接rn rn0xD0rn $EA_INFORMATION(EA信息)rn 扩充属性信息:主要为与OS/2兼容rn rn0xE0rn $EArn 扩充属性:主要为与OS/2兼容rn rn0x100rn $OBJECT_IDrn 对象ID:一个具有64个字节的标识符,其中最低的16个字节对卷来说是唯一的rn rnrnrn读到这里,我们来实际编码读点数据来加深印象。rnrnrn第一步:读入引导扇区rnrnrn定义一个引导区的结构rnrnTypernrnPBOOT_SEQUENCE = TBOOT_SEQUENCE^; rnrnTBOOT_SEQUENCE = packed record // 引导扇区数据结构rnrn _jmpcode : array[1..3] of Byte;rnrn cOEMID: array[1..8] of Char;rnrn wBytesPerSector: Word;rnrn bSectorsPerCluster: Byte;rnrn wSectorsReservedAtBegin: Word;rnrn Mbz1: Byte;rnrn Mbz2: Word;rnrn Reserved1: Word;rnrn bMediaDescriptor: Byte;rnrn Mbz3: Word;rnrn wSectorsPerTrack: Word;rnrn wSides: Word;rnrn dwSpecialHiddenSectors: DWord;rnrn Reserved2: DWord;rnrn Reserved3: DWord;rnrn TotalSectors: Int64;rnrn MftStartLcn: Int64;rnrn Mft2StartLcn: Int64;rnrn ClustersPerFileRecord: DWord;rnrn ClustersPerIndexBlock: DWord;rnrn VolumeSerialNumber: Int64;rnrn _loadercode: array[1..430] of Byte;rnrn wSignature: Word;rnrnend;rnrn rnrnprocedure SaveDebugInfo(var buffer; bufSize: Cardinal; filename: string);rnrnvarrnrn debugF : TFileStream;rnrnbeginrnrn debugF := TFileStream.Create(filename,fmCreate);rnrn tryrnrn debugF.Write(buffer,bufSize);rnrn finallyrnrn debugF.Free;rnrn end;rnrn rnrnend;rnrnprocedure Button1Click(Sender: Tobject);rnrnvarrnrn hDevice : THANDLE;rnrn PbootSequence : PBOOT_SEQUENCE;rnrn dwRead : Cardinal;rnrnbeginrnrn hDevice := CreateFile( PChar('\\.\E'),rnrn GENERIC_READ,rnrn FILE_SHARE_READ or FILE_SHARE_WRITE,rnrn nil,rnrn OPEN_EXISTING,rnrn FILE_ATTRIBUTE_NORMAL,rnrn 0);rnrn if (hDevice = INVALID_HANDLE_VALUE) thenrnrn beginrnrn Showmessage('无法读写磁盘!');rnrn CloseHandle(hDevice);rnrn exit;rnrn end;rnrn New(PBootSequence);rnrn ZeroMemory(PBootSequence, SizeOf(TBOOT_SEQUENCE));rnrn SetFilePointer(hDevice, 0, nil, FILE_BEGIN);rnrn ReadFile(hDevice,PBootSequence^, 512,dwread,nil);rnrnSaveDebugInfo(PBootSequence^,sizeof(TBOOT_SEQUENCE),'boot_sector.bin');rnrnDispose(PBootSequence);rnrnClosehandle(hDevice);rnrnEnd;rnrn读入的引导区为下图:rnrnrn每扇区字节数(红色):0x0200rnrn每簇扇区数(蓝色): 0x08rnrn$MFT的逻辑簇号(黄色): 0x0000000000000004rnrn每MFT记录簇数(绿色): 0x000000F6rnrn[img=http://p.blog.csdn.net/images/p_blog_csdn_net/a00553344/EntryImages/20091219/boot633968490707195084.JPG][/img]rnrn第二步 读入MFTrnrn我们知道MFT的第一条记录是本身。现在已经知道了rnrn1. 每扇区字节数(红色):0x0200rnrn2. 每簇扇区数(蓝色): 0x08rnrn3. $MFT的逻辑簇号(黄色): 0x0000000000000004rnrn4. 每MFT记录簇数(绿色): 0x000000F6rnrn可以计算出$MFT的位置和MFT中每条记录的大小(通常是1KB):rnrn$MFT位置(偏移量) := $MFT的逻辑簇号 *每簇扇区数 *每扇区字节数rnrn每MFT记录簇数不能直接拿来计算每条记录的大小,要看它是否小于0x80,计算公式如下:rnrn if (每MFT记录簇数 < $80) thenrnrn 每MFT记录字节数 := 每MFT记录簇数*每簇字节数;rnrn elsernrn 每MFT记录字节数 := 1 shl ($100 -每MFT记录簇数)rnrn我们现在获得$MFT的偏移动位置及$MFT中每条记录的大小,这样我们就可以读出$MFT中的第一条记录,即对应$MFT文件自身的那条记录。rnrn代码:rnrn SetLength(存放数据的缓冲区, 每MFT记录字节数);rnrn SetFilePointer(hDevice, Int64Rec($MFT位置).Lo,rnrn @Int64Rec($MFT位置).Hi, FILE_BEGIN);rnrn Readfile(hDevice, PChar(存放数据的缓冲区)^, 每MFT记录字节数, dwread, nil);rnrnSaveDebugInfo(存放数据的缓冲区, 每MFT记录字节数,'MFT.bin');rnrn读到的对应$FMT文件的记录为:rnrn[img=http://p.blog.csdn.net/images/p_blog_csdn_net/a00553344/EntryImages/20091219/MFT.JPG][/img]rnrnrn完整内容Blog地址:http://blog.csdn.net/A00553344/archive/2009/12/19/5039884.aspx 论坛

编码实现NTFS格式删除文件恢复

12-18

[b]主要内容[/b]rnrn一、NTFS系统结构原理rnrn二、编码实现NTFS磁盘删除文件扫描rnrn三、编码实现NTFS磁盘删除文件恢复rnrn rnrn([url=http://d.download.csdn.net/down/1913794/A00553344]编码实现的磁盘文件恢复小工具下载地址[/url])rnrnrn 工具截图rnrn[img=http://p.blog.csdn.net/images/p_blog_csdn_net/a00553344/EntryImages/20091218/NTFS.JPG][/img]rnrn[b]第一部分 NTFS系统结构原理[/b]rnrn rnrnNTFS是Windows NT引入的新型文件系统,由于NTFS的结构复杂,内容繁多,这里仅对NTFS卷上的底层结构做分析。rnrn rnrn主要内容rnrn一、NTFS系统结构原理rnrn二、编码实现NTFS磁盘删除文件扫描rnrn三、编码实现NTFS磁盘删除文件恢复rnrn rnrn(编码实现的磁盘文件恢复小工具下载地址)rnrnrn 工具截图rnrn rnrn第一部分 NTFS系统结构原理rnrn rnrnNTFS是Windows NT引入的新型文件系统,由于NTFS的结构复杂,内容繁多,这里仅对NTFS卷上的底层结构做分析。rnrn rnrn1. 基本概念rnrn rnrn在NTFS格式中,文件以簇的形式分配。最小的单位为扇区,N个扇区为一簇。其中,N的值由引导扇区规定。卷与簇的关系如下表。rnrn卷大小(分区大小) 每簇的扇区 缺省的簇大小rn rn小于等于512MB 1 512字节rn rn513MB~1024MB(1GB) 2 1024字节(1KB)rn rn1025MB~2048MB(2GB) 4 2048字节(2KB)rn rn大于等于2049MB 8 4KBrn rnrn rnrn[b]2. 基本结构[/b]rnrn rnrnNTFS格式磁盘的数据分为4大部分。 rnrn rnrn rnrn引导区 主文件列表 系统文件 文件数据区 rnrnrn rnrn rnrnl 引导区(Partition boot sector):所有的磁盘格式都有这个区,占用了磁盘的第一个扇区。rnrnl 主文件列表(Master File Table,MFT):它记录了卷上所有的文件,每一个文件对应表中的一条记录。NTFS中目录也是以文件的形式存在的。因此,每一个目录也可以看作一个文件。rnrnl 系统文件(System files):NTFS系统一共有16个系统文件,和8个保留文件。rnrnl 文件数据区(File area):存放文件数据。rnrn rnrn3. 引导区rnrn rnrn字节偏移 长度(字节) 常用值 意义rn rn0x00 3 JMP指令rn rn0x03 4 “NTFS” 文件系统 IDrn rn0x0B 2 0x0200 每扇区字节数rn rn0x0D 1 0x08 每簇扇区数rn rn0x0E 2 保留扇区rn rn0x10 3 总为0rn rn0x13 2 NTFS未使用,为0rn rn0x15 1 介质描述 rn rn0x16 1 总为0rn rn0x18 2 每磁道扇区数 rn rn0x1A 2 磁头数rn rn0x1C 4 隐含扇区rn rn0x20 4 NTFS未使用,为0rn rn0x24 4 NTFS未使用,为0rn rn0x28 8 扇区总数rn rn0x30 8 $MFT的逻辑簇号rn rn0x38 8 $MFTMirr的逻辑簇号rn rn0x40 4 每MFT记录簇数rn rn0x44 4 每索引簇数rn rn0x48 8 卷标rn rn0x50 4 校验和rn rn0x54 430 引导代码rn rn0x1FE 2 0x55AA 引导扇区标志rn rn rnrn[b]4. 主文件列表(MFT)[/b]rnrn rnrnl MFT是一个对应的数据库,由一系列的文件记录组成。卷中每一个文件都有一个文件记录(对于大型文件还可能有多个记录与之相对应)。主文件表本身也有它自己的文件记录。rnrnl 实际上,MFT自身也是一个文件,因此,主文件列表的第一个记录就是它自身。MFT的每个记录都有一个编号,这里我们称它为ID号。这个ID从0开始。我们知道MFT自身是NTFS系统的第一个文件,所以文件$MFT的ID号为0。rnrnl MFT和其他23个文件一起(共24个),组成所谓的“Metafiles”(元文件,也是之前提到的System files,系统文件)。这24个文件中,前16(ID为0-15)个文件是固定的,剩下的8个文件为保留文件。rnrnl 用户的文件(也包括目录)的MFT中的ID号从24开始排。用户每添加一个文件ID号加1,当某文件被删除时,与之对应的MFT记录将被空出来,如果此时再次添加文件,系统会优先填充ID小的空位。rnrnl 无论簇的大小,文件记录大小都是1K。理论上MFT在卷中的分配空间(占12%)。rn逻辑上,MFT在卷中会占用一块连续的空间,但实际情况$MFT可能会被分散在磁盘的几个不同的区域。甚至,可能在元文件的部分就被拆分开。rnrn rnrn[b]5. 系统文件(System files)[/b]rnrn rnrn序号(ID) 元文件 功能 rn rn0 $MFT 主文件列表本身rn rn1 $MFTMirr 主文件表的部分镜像 rn rn2 $LogFile 日志文件rn rn3 $Volume 卷文件rn rn4 $AttrDef 属性定义列表rn rn5 $Root 根目录rn rn6 $Bitmap 位图文件,文件$Bitmap标识的是该卷中簇的占用情况。它用一位代表一簇。为0代表此簇空闲,为1代表此簇已使用rn rn7 $Boot 引导文件rn rn8 $BadClus 坏簇文件rn rn9 $Secure 安全文件rn rn10 $UpCase 大写文件rn rn11-15 $Extend 扩展文件(一共5个文件)rn rn16-23 保留 rn rn rn(待续)rnrn论坛发贴编辑框有点简陋,完整的看BLOG: [url=http://blog.csdn.net/A00553344/archive/2009/12/18/5031993.aspx]http://blog.csdn.net/A00553344/archive/2009/12/18/5031993.aspx[/url]rnrn rn 论坛

没有更多推荐了,返回首页