手动编辑$BadClus标记坏扇区

高能警告:本文系给文件系统动手术,意在折腾与学习,实际操作中请务必小心谨慎,最好备份重要文件以及要编辑的扇区,进行每一次编辑操作前请务必确保自己已经了解这一步的原理,否则请在分分钟把整个分区弄丢后执行chkdsk修复的过程中默念100遍“不作死就不会死”。

友情提醒:本文仅记录笔者个人案例,仅说明$BadClus文件相关,不介绍基础知识,请先了解硬盘分区、NTFS文件系统、MFT表等相关知识。

修复文件与定位坏扇区位置

这几天打算调整分区对齐,因为没对齐的分区若要对齐必须全部数据平移而不能借助无损分区工具(所有的簇全部是没对齐的必须全部平移,分区工具只能按簇的单位滑动才能尽量少地移动数据),所以只能考虑在对齐的位置新建分区,将全部数据拷进来。

往移动硬盘拷数据时有一集动画片复制失败,使用WinHex拷贝选区到新文件写入到80%的时候报告错误,新文件不完整。查看新文件的大小在源文件中找到出错位置附近,跳过报告错误的位置将剩余部分手动复制到新文件中,出错的位置粘贴0字节补齐,这样即可得到基本修复的文件(当然没办法完整播放了,但是可以跳过那几秒)。之前用HDDREG修复过硬盘上的一些坏扇区,这次打算尝试通过NTFS的坏簇列表屏蔽。

用WinHex打开分区,找到出错的文件右键-位置-列出的簇,在簇窗口中右键-缩短连续的簇列表,手动计算之前编辑文件时出错的大概位置对应到哪个簇,并定位到这块位置,此时WinHex访问出错,并且应当能报告无法访问扇区的准确扇区编号,将扇区号记录下来,加上分区的起始扇区,即得到硬盘坏扇区的LBA。因为我是要重新分区,所以待重新分区后再用这个LBA计算出新分区的簇号,如果不是重新分区,直接记录簇号即可。

MarkBadClusTool是一个很好的作品,可根据LBA将坏簇填写到$BadClus里,但笔者使用时出现了一些问题,比如填写扇区扩展的数值填0的话程序报告无效数值,填小数目比如1的话程序最后执行完后压根没往$BadClus里写东西,估计是算法有缺陷。笔者硬盘的坏扇区不是机械故障,很小规模的,并且不会自己扩散,所以没必要把周边的好扇区一并屏蔽了。另外就是这个工具每次都要走两遍MFT,作用在于如果坏簇上已经存在文件,将尝试将该文件移走,而笔者已经手动把那个文件弄走并且修复了,默认坏簇现在处于free空间,仅需要把它添加到$BadClus这个文件里即可。因为MarkBadClusTool有提供源代码,遂决定自己折腾一下。

data runs、稀疏文件与NTFS压缩、$BadClus:$Bad研究笔记

对于硬盘上的数据,MFT中以data runs的结构存储文件的簇指针。简单地讲,就是一堆起始簇号-大小pairs的有序集合,这样就能表示一个文件了。pair使用可变长度整数记录,每个pair首字节高4位表示“起始簇号相对于上一块的delta”这个整数的长度,低4位表示“块大小”这个整数的长度。语言说起来比较绕,建议查阅已有文章,有图解的一目了然。

$BadClus的$Bad属性记录坏簇这个知识很容易就在网上找到,但是如果直接按上面的data runs填入坏簇的位置信息,写入后会发现分区丢了,说明“打开的姿势不对”。查阅MarkBadClusTool的代码,发现程序使用DataRunsToSpaceDataRuns“将常规Dataruns数据转换为用来描述空间信息的dataruns”。这句注释写的很不明所以,走读代码后发现这段代码是将坏簇的data runs两端与之间填入正常区域的长度。

原理上讲同为data runs是不应该有多种写法的,查阅了很多资料才得知真正含义:$BadClus:$Bad文件并不是一个将坏簇连接起来的文件,而是一个大小为整个分区的NTFS稀疏文件,其中正常的位置是稀疏文件的0,坏簇的地方指向磁盘上的坏簇。而稀疏簇的表示是将“起始簇号”设为-1,“起始簇号delta”设为0,表现在data runs里就是一个字节的整数长度接上正常块的长度数据。这一点MarkBadClusTool虽然执行的结果对,但写法与注释其实并不正确(那么真正的0簇开始的数据因该怎么写,答案是1x xx 00,见$Boot中的记录)。

顺便聊一下压缩。NTFS压缩是完全基于稀疏文件机制的。data runs只有真正簇(delta_lcn不为0)与稀疏簇(delta_lcn为0)之分,并不在乎存放的数据是压缩的还是未压缩的。数据是否压缩通过64K块是否在末尾有稀疏簇来判断。如果一个64K块尝试压缩后体积并没有减少4K以上,那么该数据依然会以未压缩形式存放,如果减小4K以上,那么就在末尾插入几个稀疏簇补齐到64K。

NTFS的文件属性查看压缩文件对于压缩后没有减小体积的其“占用空间”显示为文件大小,但是从上面的算法来看,有一定的几率是压缩后比未压缩大一个簇的。可实验建立一个刚好为4K的随机数据文件(无法被压缩),NTFS会将其补齐到64K然后尝试压缩,结果自然要比4K多几字节,这样就占用了2个簇的实际数据。

基于稀疏文件的NTFS压缩在对付迅雷下载刚开始创建文件时的卡死有奇效(迅雷脑残不在程序里指定创建稀疏文件。。。)

案例

下面以笔者的案例介绍一下手动修改的过程。

本次要处理的坏扇区为754546051到754546055连续的5个扇区,位于当前D盘,D盘起始扇区为83886080(40G整),持续400G。簇总数为104857599(最后一个簇为保留扇区,最后一个扇区为PBR的备份)。

754546051-754546055对应到D盘逻辑扇区为670659971-670659975,除以8得到簇号为83832496,刚好被包含在一个簇里。

构造整个分区大小的稀疏文件:第0到83832495共83832496个簇的0、第83832496簇开始长度为1的坏簇、第83832497到104857598共21025102个簇的0。写出来为:

04  B0 2E FF 04    41  01  B0 2E FF 04    04  4E D1 40 01    00

定位到$BadClus:$Bad的data runs位置($BadClus+0x168),填写上面的内容,然后将0x124位置的属性长度改为修改后长度,8字节对齐(本例改为0x60),在0x180位置填入MFT记录结尾的FF FF FF FF,在0x18位置填入修改后的MFT记录长度,8字节对齐(本例改为0x188)。然后找到$Bitmap文件,计算第83832496/8=10479062余0字节对应的扇区位置,将该字节第0位置1表示空间已分配。

然后即可写入磁盘。WinHex旧版本不支持DeviceIoControl卸载分区,换用新版本即可。

参考文献

1、MarkBadClusTool及其源代码:http://bbs.pediy.com/showthread.php?t=162539
2、上述源码中layout_ntfs.h中Attribute compression一节的注释
3、$BadClus:$Bad是稀疏文件:http://0cch.net/ntfsdoc/files/badclus.html
4、data run:http://blog.csdn.net/begges/article/details/6699236
5、《数据恢复技术深度揭秘》相关章节

2 Replies to “手动编辑$BadClus标记坏扇区”

  1. 硬盘坏扇区标记工具MarkBadClusTool, 作者已放出源码,PO主继续雄起!!!

Leave a Reply

Your email address will not be published. Required fields are marked *