当你看到下面的fdisk 输出信息,你能想到什么呢?
Disk /dev/sda: 120.0 GB, 120034123776 bytes
255 heads, 63 sectors/track, 14593 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Disk identifier: 0x00000080
Device Boot Start End Blocks Id System
/dev/sda1 * 1 5099 40957686 7 HPFS/NTFS
/dev/sda2 5100 11473 51199155 f W95 Ext'd (LBA)
/dev/sda3 11474 12542 8586742+ 83 Linux
/dev/sda4 12543 14593 16474657+ 83 Linux
/dev/sda5 5100 10198 40957686 7 HPFS/NTFS
/dev/sda6 10199 11473 10241406 b W95 FAT32
没错,它们表示的是硬盘的各个分区的起始柱面,结束柱面,分区大小,分区类型以及分区是否可以引导。
柱面信息是近似的。真正精确表示分区起始,终止位置的是硬盘的扇区位置。比如:
Disk /dev/sda: 120.0 GB, 120034123776 bytes
255 heads, 63 sectors/track, 14593 cylinders, total 234441648 sectors
Units = sectors of 1 * 512 = 512 bytes
Disk identifier: 0x00000080
Device Boot Start End Blocks Id System
/dev/sda1 * 63 81915434 40957686 7 HPFS/NTFS
/dev/sda2 81915435 184313744 51199155 f W95 Ext'd (LBA)
/dev/sda3 184313745 201487229 8586742+ 83 Linux
/dev/sda4 201487230 234436544 16474657+ 83 Linux
/dev/sda5 81915498 163830869 40957686 7 HPFS/NTFS
/dev/sda6 163830933 184313744 10241406 b W95 FAT32
这些扇区的位置精确表示了各个分区的信息。有个这个信息,以后即使不小心删除了分区,我们还是可以用上面的信息来还原所有硬盘分区。
要了解整个过程,我们必须了解分区表信息在硬盘扇区上是如何存放的。
OK,接下来,我们在Linux下面做一个小小的试验。
一:搭建一个分析硬盘分区表的环境。
1:建立一个虚拟的硬盘。
不得不承认,Linux是个好东西。虚拟硬盘是如此的简单。
user@pclinux: dd if=/dev/null of=diskb seek=2097152 count=0 bs=1024
或者,头个懒,用qemu-img,怎么也可以少敲几个字母,:)。
user@pclinux: qemu-img create diskb 2G
到目前为止,diskb还只是一个文件。我们可以利用loop设备,将它模拟成一个硬盘。
user@pclinux: sudo losetup /dev/loop0 diskb
好了,现在loop0就是diskb对应的硬盘了。
2:开始分区。
我把整个diskb成一个FAT32主分区,一个扩展分区。在扩展分区里边建立一个FAT32的逻辑分区。分区表如下:
Disk /dev/loop0: 2147 MB, 2147483648 bytes
255 heads, 63 sectors/track, 261 cylinders, total 4194304 sectors
Units = sectors of 1 * 512 = 512 bytes
Disk identifier: 0xe89bd33e
Device Boot Start End Blocks Id System
/dev/loop0p1 63 417689 208813+ c W95 FAT32 (LBA)
/dev/loop0p2 417690 4192964 1887637+ 5 Extended
/dev/loop0p5 417753 835379 208813+ c W95 FAT32 (LBA)
主分区和逻辑分区都不能引导。
3:用hexedit/dd等工具来分析分区表。
硬盘的访问模式有两种,一种叫CHS方式,一种是LBA方式。CHS方式比较古老。它是沿袭硬盘的物理方式来访问硬盘的。也就是说,如果要访问硬盘的某个逻辑扇区,它要先确定这个扇区所在的柱面(Cylinder),然后,在这个柱面上确定该扇区所在的磁头(Header),最后,在该磁头上,确定这个逻辑扇区。CHS方式访问大容量硬盘。大容量的硬盘都是按照LBA方式访问的。LBA将整个硬盘看成一串扇区数组。其中0号扇区着MBR和硬盘的主分区表。
我们先把0号扇区搞下来:
user@pclinux: sudo dd if=/dev/loop0 of=boot0.bin bs=512 count=1
user@pclinux: hexedit -s boot0.bin
00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000000A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000000B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000000C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000000D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000000E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000000F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000100 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000110 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000120 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000130 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000140 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000150 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000160 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000170 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000180 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000190 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000001A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000001B0 00 00 00 00 00 00 00 00 3E D3 9B E8 00 00 00 01 ........>.......
000001C0 01 00 0C FE 3F 19 3F 00 00 00 5B 5F 06 00 00 00 ....?.?...[_....
000001D0 01 1A 05 FE 7F 04 9A 5F 06 00 2B 9B 39 00 00 00 ......._..+.9...
000001E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000001F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 AA ..............U.
由于这个diskb并没有主引导程序,所以从0字节开始,所有引导代码为零。主分区表信息从偏移0x1be开始,一直最后倒数第三个字节结束(64字节) 。最后的55AA是标志位。
这64个字节分成4部分,每个16字节。描述了整个硬盘的主分区和整个扩展分区的信息。从这里我们可以看到,硬盘只能有4个主分区。这16个字节的含义如下:
字节 含义 值
00 分区是否可引导。 0,不可引导。80,可引导
01-03 分区开始的CHS值(Head,Sector,Cylinder,Sector的高 位是Cylinder的第9,10位)
04 分区类型 7,NTFS,C, FAT32,5,F 扩展分区等等
05-07 分区结束的CHS值(Head,Sector,Cylinder,Sector的高 位是Cylinder的第9,10位)
08-11 LBA方式下,相对的起始扇区号
在MBR分区里边,相对0扇区,
扩展分区表示相对于扩展分区的起
始扇区(little endion 格式)
12-15 该分区拥有的扇区数量 (little endion)
OK,回到我们的diskb,我们可以从这张分区表看到,diskb的第一个分区是类型C(FAT32)的主分区。它从硬盘的63个扇区开始(3f 00 00 00),一共有0x065f5b个扇区,本分区不可引导(00)。Diskb的第二个扇区是一个扩展分区,起始地址是0x065f9a,共有扇区0x399b2b个。
据我分析,CHS的值和LBA表示的逻辑扇区是可以相互转换的。大概是:
CHS==>LBA
Value of Cylinder *每柱的磁道数*每磁道的扇区数+ Value of Header * 每磁道扇区数 + Value of Sector = 结束扇区LBA 扇区值+1。
验证一下:
上面的FAT32分区结束CHS值为:0x19 0xFE 0x3F,那么,该分区结束扇区的LBA值应该是:
0x19*255*63+0xFE*63+0x3F-1 = 417689
上面的分区告诉我们,这个分区占有0x00065f5b个扇区,那么它的结束LBA值应该是:0x00065f5b+63-1
=417689
结果正确。(柱面和磁道编号是从零开始,而扇区是从1开始的。)
那么反过来,如果知道LBA值是不是也可以推算CHS值?
试一下:
Value of Cyliner = ( Value of LBA+1)/每柱磁道数/每磁道扇区数. 如果整除,柱面数减1。
Value of Header = ( Value of LBA+1 – Value of Cylinder * 每柱磁道数字 * 每磁道扇区数 ) / 磁道扇区数,如果整除,磁头数减1。
Value of Sector 依次类推。
(417689+1)/255/63 = 0x1A ,整除,减1,变成0x19.
(417689 +1 – 0x19*255*63)/63=0xFF,整除,减1,变成0xFE
(417689 +1 – 0x19*255*63 – 0xfe*63)=0x3F
Very Good,结果正是我们想的。
接着看下面的分区表,MBR所在的分区告诉我们,下一个分区是扩展分区,它的LBA起始地址是417690,也就是上面的0x065f9a。我们把它dump出来看看
user@pclinux : sudo dd if=/dev/loop0 of=ext_fat skip=417690 bs=512 count=1
验证一下:
user@pclinux: hexedit -s ext_fat
00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000000A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000000B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000000C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000000D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000000E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000000F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000100 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000110 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000120 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000130 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000140 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000150 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000160 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000170 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000180 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000190 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000001A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000001B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 ................
000001C0 01 1A 0C FE 3F 33 3F 00 00 00 5B 5F 06 00 00 00 ....?3?...[_....
000001D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000001E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000001F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 AA ..............U.
这个扩展分区里边只有一个为C(FAT32)的逻辑分区,逻辑分区的起始地址在:417690+63处。
一共有扇区0x065f5b个。
Ok,到此,硬盘的两个分区表就已经搞清楚了。
如果分区表不小心丢失,想恢复的话,那就简单了。将这两个分区表复制到相应的位置就可以了。
简单的看一个复杂一点的例子:
Disk /dev/loop0: 6442 MB, 6442450944 bytes
255 heads, 63 sectors/track, 783 cylinders, total 12582912 sectors
Units = sectors of 1 * 512 = 512 bytes
Disk identifier: 0x1009e660
Device Boot Start End Blocks Id System
/dev/loop0p1 63 1606499 803218+ 83 Linux
/dev/loop0p2 1606500 12578894 5486197+ 5 Extended
/dev/loop0p5 1606563 3212999 803218+ 83 Linux
/dev/loop0p6 3213063 4819499 803218+ 83 Linux
/dev/loop0p7 4819563 6425999 803218+ 83 Linux
/dev/loop0p8 6426063 11245499 2409718+ 83 Linux
/dev/loop0p9 11245563 12578894 666666 83 Linux
上面的硬盘被分成1个主分区,5个逻辑分区,从这个表中,我们就可以看出整个硬盘所有分区表的位置了(很明显,这个硬盘被完全分区了,没有空白区)。
Name offset of LBA sector
FAT1 0
FAT2 1606500
FAT3 3213000
FAT4 4819500
FAT5 6426000
FAT6 11245500
6个扇区都不可引导。
大家用hexedit来验证。
备份的时候可以生成一个自己定义的格式,比较方便的一种为:
aa bb cc dd + FAT Sector
...
其中aa bb cc dd 是FAT Sector的LBA扇区号的16进制。这样,恢复的时候就非常方便了。
也许有人已经看出来了,最简单的备份/恢复就是利用fdisk的信息了。从根本上来说知道各个分区的大小,起始位置也就完全知道了整个硬盘的分区情况了。
如果不小心把所有的分区表都删掉了怎么办?是不是就不能恢复了呢?
放心,还是可以的。每个分区在建立文件系统时,都会将本分区的类型,大小等信息放在这个分区的头上。研究这个,我们还是可以确定当前这个分区在硬盘上的位置。有了这个位置信息,基本上还是可以大致的恢复出整个硬盘的分区表(有些信息不太能确定,比如说到底是主分区还是逻辑分区)。如果文件系统的信息也丢失了呢?那就只能碰运气了。运气好的话,你能找到一些系统在隐含扇区备份的分区表信息。你可以全盘查找55AA这个特征值,然后看它像不像分区表。
最后套用一句口号:”不抛弃,不放弃“。即使软件提醒你找不到分区表,别灰心,手工在处理一下。Windows用winhex, Linux用hexedit,也许能找到点希望。