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

A00553344 2009-12-19 09:17:53
加精
上贴地址:http://hi.csdn.net/link.php?url=http://topic.csdn.net%2Fu%2F20091218%2F15%2F43f7e6e0-244f-4d45-9564-0e32cd1974d2.html

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文件的记录为:




完整内容Blog地址:http://blog.csdn.net/A00553344/archive/2009/12/19/5039884.aspx
...全文
899 47 打赏 收藏 转发到动态 举报
写回复
用AI写文章
47 条回复
切换为时间正序
请发表友善的回复…
发表回复
hqx663 2009-12-22
  • 打赏
  • 举报
回复
有点难
jylgs81 2009-12-22
  • 打赏
  • 举报
回复
受教了,谢谢
xuewen0116 2009-12-22
  • 打赏
  • 举报
回复
有用的东西
n915617214m 2009-12-22
  • 打赏
  • 举报
回复
继续
huxg123456 2009-12-22
  • 打赏
  • 举报
回复
很好,支持,顶。
sargehero 2009-12-21
  • 打赏
  • 举报
回复
谢谢,这是我想要的
jeam0402 2009-12-21
  • 打赏
  • 举报
回复
mark
agel0ver 2009-12-21
  • 打赏
  • 举报
回复
支持一下
quintard 2009-12-21
  • 打赏
  • 举报
回复
有没有续二?
yc_8301 2009-12-21
  • 打赏
  • 举报
回复
狂顶!!
IThurricane 2009-12-21
  • 打赏
  • 举报
回复
学习了
贝隆 2009-12-21
  • 打赏
  • 举报
回复
顶楼主
xz22503c 2009-12-21
  • 打赏
  • 举报
回复
成员 (All member
夏至溪檐 2009-12-20
  • 打赏
  • 举报
回复
顶了,慢慢研究一下
xnnnn 2009-12-20
  • 打赏
  • 举报
回复
细细观看之。感谢
小小土豆 2009-12-20
  • 打赏
  • 举报
回复
是在需要顶一下
mustcome 2009-12-20
  • 打赏
  • 举报
回复
再来顶,虽然有点看不懂了!!
tzc555 2009-12-20
  • 打赏
  • 举报
回复
hvhgjh
Longteng_Bruec 2009-12-20
  • 打赏
  • 举报
回复
这是操作系统的知识吧,咱国家须要你这样的人才。。
luozxl2009 2009-12-20
  • 打赏
  • 举报
回复
看一下,谢谢了
加载更多回复(25)

1,183

社区成员

发帖
与我相关
我的任务
社区描述
Delphi Windows SDK/API
社区管理员
  • Windows SDK/API社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧