编码实现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
...全文
901 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)
RAR 是一个让你在命令行模式中管理压缩文件的控制台应用。RAR 提供压缩、加 密、数据恢复和许多其它此手册中描述的其它功能。 RAR 只支持 RAR 格式压缩文件,它默认有 .rar 扩展名。不支持ZIP 和其他格 式。即使创建压缩文件时指定了 .zip 扩展名,它仍然是 RAR 格式的。Windows 用户 可以 WinRAR,它支持更多的压缩文件类型,包括 RAR 和 ZIP 格式。 WinRAR 提供了图形用户界面和命令行模式。虽然控制台 RAR 和图形界面 WinRAR 有相似的命令行语法,但是它们还有有一些不同。所以推荐使用此 rar.txt 手册用于 控制台 RAR(rar.exe 在 Windows 版本的情况下),winrar.chm 是图形界面 WinRAR (winrar.exe) 的帮助文件。 配置文件 ~~~~~~~~ Unix 版本的 RAR 从用户的 home 或 /etc 目录中的 .rarrc 文件读取配置文件信息 (存储在 HOME 环境变量中) Windows 的版本 RAR 从 rar.ini 文件读取配置文件信息,它放在 rar.exe 文件相 同的目录中。 这个文件包含下列字符串: switches=任何 RAR 开关,用空格分开 例如: switches=-m5 -s 环境变量 ~~~~~~~~ 可以通过建立"RAR"环境变量来添加默认参数到命令行中. 例如,在 Unix 中,下列命令行可以被添加到你的配置中: RAR='-s -md1024' export RAR RAR 将使用这个字符串作为命令行的默认参数,并将使用 1024KB 字典大小来创建 “固实”压缩文件。 RAR 控制选项使用下列优先级: 命名行开关 最高优先级 在 RAR 变量中的开关 低优先级 保存在配置文件中的开关 最低优先级 日志文件 ~~~~~~~~ 如果在命令行或配置文件中指定开关 -ilog ,RAR 将会把处理压缩文件中遇到的错误 等写到日志文件中。读取开关 -ilog 描述获得更多信息。 固实压缩的文件列表 - rarfiles.lst ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ rarfiles.lst 包含一个用户定义的文件列表,告诉 RAR 添加文件到固实压缩文件时的顺 序。它可以包含文件名通配符和指定项目 -$default。默认项目定义了这个文件中与 其他项目不相符时的顺序清单位置。 注释字符是 ';'. 在 Windows 中,这个文件应该放在 RAR 所在的或 %APPDATA%\WinRAR 目录中, 在 Unix 中- 放在用户的 home 目录或在 /etc 中。 提高压缩率和操作速度的提示: - 在压缩文件中,小文件应该被组织在一起; - 频繁被处理的文件应该放在开始的位置。 普通的掩码越靠近顶端优先权就越高,但是这个规则存在例外。如果 rarfiles.lst 包含两个掩码,并且所有文件既匹配第一个掩码,也匹配第二个掩码, 较小的子集 或者更精确的匹配拥有更高的优先权。例如,如果你用 *.cpp 和 f*.cpp 掩码, f*.cpp 拥有更高的优先权。 RAR 命令行语法 ~~~~~~~~~~~~~~ 语法 RAR [ - ] [ ] [ ] [ ] 描述 命令行选项 (命令和开关) 提供了使用 RAR 创建和管理压缩文件的控制方法。命 令是一个字符串(或单个的字母),命令 RAR 去执行一个相应的操作。开关被用来 改变 RAR 执行操作的方法。其它参数是压缩文件名和被压缩的文件或要从压缩文件 中被解压文件。 列表文件是一个包括处理的文件名的纯文本文件。第一列应该以文件名开始。可以 在//字符后添加注释。例如,你可以创建包含下列字符串的 backup.lst: c:\work\doc\*.txt //备份文本文档 c:\work\image\*.bmp //备份图片 c:\

1,183

社区成员

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

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