第 13 章
使用编程读取和修改MBR
DOS 引导记录 (DBR)/DOS 引导扇区
继分区表之后,DOS 引导记录 (DBR)(有时称为 DOS 引导扇区)是硬盘上第二重要的信息。
有关 DBR 的详细讨论,请参阅本书前面讨论的“磁盘和操作系统的逻辑方法”一章。
每个 DOS 分区的第一个逻辑扇区将包含 DOS 引导记录 (DBR) 或 DOS 引导扇区。 DBR的工作是将操作系统从硬盘加载到计算机的主存储器中,并将系统的控制权转交给已加载的程序。
硬盘上第一个分区的 DOS 引导记录 (DBR) 通常位于绝对扇区 63(磁盘上的第 64 个扇区)或以 CHS 形式存在,也就是说,对于大多数磁盘,我们可以说 C–H–S = 0–1–1。
但是,这种安排可能根据驱动器的 SPT(每磁道扇区数)而有所不同。例如,在只有 31 个 SPT 的旧 245MB 驱动器上,引导记录位于扇区 32(绝对扇区 31)。
由于软盘没有分区,因此其第一个扇区中没有 MBR 或主分区表,而是在第一个扇区中包含一个 DBR。
DBR 是在使用 FDISK 命令进行分区后,由 FORMAT DOS 命令创建的。对于 DOS,DBR 所在的扇区成为该特定分区的逻辑扇区 1。 DOS使用的扇区号从DBR所在的物理扇区开始。
DBR 包含由主引导记录 (MBR) 可执行程序执行的一段小程序。所有 DOS 分区都包含启动机器的程序代码,即启动操作系统,但只有此分区接受主引导记录的控制,主引导记录在分区表项中被指定为活动分区。
如果 DBR 以任何方式损坏,则当您从启动软盘或 CD 启动系统时应该可以访问该磁盘。虽然硬盘无法启动(如果活动分区的 DBR 损坏),但一般来说这不会影响对驱动器上数据的访问。从启动盘启动系统后,即可访问数据。
/*显示软盘启动参数*/
#包括<dos.h>
# 包括 <stdio.h>
基本的( )
{
加载结构
{
无符号字符代码[3]; /* 转换代码 */
unsigned char system_id[8] ;/* OEM名称和版本*/
int 字节数/秒; /* 每扇区字节数 */
符号 sec_per_clus; /* 每簇扇区数 */
int res_sec; /* 保留扇区 */
字符 fat_copies; /* FAT 数量 */
int 根目录条目; /* 根数
目录条目 */
无符号整数无_sects; /* 扇区数
逻辑卷 */
无符号字符格式_id; /* 媒体描述字节
*/
int sec_per_fat; /* FAT 上的扇区 */
int sec_per_trk; /* 每磁道扇区数 */
int 无边数; /* 磁头数量 */
int no_sp_res_sect; /* 隐藏的数目
部门 */
无符号字符 rest_code[482]; /* 其余代码 */
};
荷载结构 b ;
符号 temp[4] ;
int val,驱动器;
val = absread(0, 1, 0,&b) ; /*用于软盘*/
如果(值==-1)
{
printf ( "读取磁盘错误...坏扇区\n" ) ;
输出(1);
}
clrscr();
printf("系统标识符 = %s\n",
b.系统标识符 );
printf ("每扇区字节数 = %d\n",
b.字节数(秒);
printf ("每簇扇区数 = %d\n",
sec_per_class);
printf("保留扇区 = %d\n",
b.res_sec );
printf("FAT 副本 = %d\n",
复制代码
printf("根目录条目 = %d\n",
根目录条目 );
printf("磁盘扇区数 = %u\n",
b.无_sects );
printf("媒体描述符字节 = %X\n",
格式ID );
printf("每个 FAT 的扇区数 = %d\n",
sec_per_fat );
printf("每磁道扇区数 = %d\n",
sec_per_trk );
printf("边数 = %d\n",
b.无边数 );
printf("保留扇区数 = %d\n",
否则,将导致结果不准确。
返回0;
}
如果你运行该程序来测试 1.44M、3½ 英寸软盘的 DBR,该软盘有 70 个磁道、两面、每个磁道有 18 个扇区、每个扇区有 512 个字节,则程序的输出将显示类似如下内容:
系统 ID = +1<*uIHC
每扇区字节数 = 512
每簇扇区数 = 1
保留扇区 = 1
FAT 副本 = 2
根目录条目 = 224
编号磁盘扇区数 = 2880
媒体描述符字节 = F0
每个 FAT 扇区数 = 9
每磁道扇区数= 18
编号边数= 2
号保留扇区数 = 0
读取大容量的 DBR
大小大于 32MB 的分区卷的 DBR 格式与小于或等于 32MB 的卷的 DBR 格式有所不同。
这是为了提供对大容量磁盘的支持(有关它的详细描述,请参阅本书前面讨论的“磁盘和操作系统的逻辑方法”一章)。
下表给出了 FAT32 卷的 DOS 引导记录的格式:

以下程序用于读取大卷(大小大于 32MB)的 DBR:
/*显示大磁盘卷的启动参数的程序*/
#包括“dos.h”
#包括“stdio.h”
空主()
{
引导结构
{
无符号字符代码[3]; /* 跳转代码 */
无符号字符系统ID[8]; /* OEM 名称和版本 */
int 字节数/秒; /* 每扇区字节数 */
字符 sec_per_clus; /* 每簇扇区数 */
无符号整数 res_sec; /* 保留数
部门 */
字符 fat_copies; /* FAT 的数量 */
unsigned int root_dir_entry;/* 根目录数量
目录条目 */
无符号整数无_sects; /* 扇区数
逻辑卷(如果
体积<= 32MB) */
无符号字符 Media_id; /* 媒体描述符字节
*/
无符号整数 sec_per_fat; /* 每个 FAT 的扇区 */
无符号整数 sec_per_trk; /* 每磁道扇区数 */
无符号整数无边数; /* 磁头数量 */
无符号长整型no_sp_res_sect; /* 隐藏数字
部门 */
无符号长整型long_sec_num; /* 总扇区数
逻辑卷
(大小> 32MB)* /
无符号长整型num_sec_per_FAT; /* 每个 FAT 的扇区数 */
无符号整数二进制标志; /* 二进制标志 */
无符号字符版本_of_FAT1; /* FAT 的第一个字节
版本 */
无符号字符版本_of_FAT2; /* FAT 的第二个字节
版本 */
无符号长整型root_dir_start_cluster;
/* 根目录
启动集群
数字 */
无符号整数 sec_num_of_file_sys;
/* 扇区数
文件系统
信息部门
*/
无符号整数 sec_num_of_backup_boot_sec;
/* 扇区数
备份引导扇区
*/
无符号字符保留[12]; /* 预订的 */
无符号字符逻辑驱动器号;
/* 物理驱动器
逻辑数
体积 */
无符号字符未使用的字节; /* 未使用的字节 */
无符号字符 hex_extd_boot_signature;
/* 扩展启动
签名(29H) */
无符号长整型二进制卷ID;/*二进制卷ID*/
unsigned char volume_label[11];/*卷标*/
无符号字符 FAT_name[8]; /* FAT 名称 */
无符号字符 rest_code[420]; /* 剩余 420 字节
DBR */
无符号字符 magic_number[2]; /* 魔法数字 */
};
结构启动b;
字符温度[4];
int val, 驱动器,i;
val = biosdisk( 2, 0x80, 1,0,1,1, &b ) ;
/* 对于第一个硬盘 */
如果(val==-1)
{
printf ( "磁盘读取错误...坏扇区\n" ) ;
退出(1);
}
clrscr();
printf(" 跳转指令代码 = ");
对于(i = 0;i <= 2;i ++)
{
printf("%X",b.code[i]);
}
printf("(H)\n ");
printf("OEM 名称和版本 = %s\n",
b.系统ID );
printf("每扇区字节数 = %u\n",
每秒字节数 );
printf("每簇扇区数 = %u\n",
sec_per_clus );
printf("保留扇区 = %u\n",
b.res_sec );
printf("FAT 副本 = %d\n",
复制代码
printf("根目录条目 = %u\n",
根目录条目 );
printf("磁盘扇区数 = %u\n",
b.无_sects );
printf("媒体描述符字节 = %X(H)\n",
b.媒体ID );
printf("每个 FAT 的扇区数 = %u\n",
sec_per_fat );
printf("每磁道扇区数 = %u\n",
sec_per_trk );
printf("边数 = %u\n",
b.无边数 );
printf ("保留(隐藏)扇区的数量= %lu\n",
否则,将导致结果不准确。
printf("========== 对于大型(>32MB)磁盘 ========\n");
printf ("扇区数,(如果卷大于 32MB)= %lu\n",
b.长_sec_num);
printf(“每个 FAT 的扇区数 = %lu\n“,
每个FAT的秒数);
printf ("根目录起始簇 = %lu\n",
b.root_dir_start_cluster);
printf("文件系统信息扇区 = %u\n",
b.文件系统的sec_num_of_file_sys);
printf ("备份引导扇区号 = %u\n",
备份启动秒数(sec);
printf("物理驱动器号 = %X(H)\n",
b.逻辑驱动器号);
printf ( "扩展启动签名 = %X(H)\n",
b.hex_extd_boot_签名);
printf("32位二进制卷ID = ");
十进制到二进制(b.二进制卷ID,32);
printf("(B)\n");
printf("卷标 = ");
对于(i = 0; i <= 10; i ++)
{
printf("%c",b.volume_label[i]);
}
printf("\nFAT 名称 = ");
对于(i = 0;i <= 7;i ++)
{
printf("%c",b.FAT_name[i]);
}
打印(“ \ n”);
printf("魔法数字 = %X%X(H)",
b.魔法数字[0],b.魔法数字[1]);
获取();
}
////////十进制到二进制转换函数\\\\\\\\
十进制转二进制(无符号长整型输入)
{
无符号长整型 i;
int 计数 = 0;
int二进制[32]; /* 32 位 MAX 仅 32
元素总数 */
做
{
我=输入%2; /* MOD 2 得到 1 或 0*/
二进制[计数] = i; /* 将元素加载到
二进制数组 */
输入=输入/2; /* 将输入除以 2 得到
通过二进制减少 */
计数++; /* 计算元素数量
是需要的 */
}while(输入>0);
/*反转并输出二进制数字*/
做
{
printf("%d",二进制[count-1]);
数数 - ;
} 当 (计数 > 0);
返回0;
}
当程序运行读取大量DBR时,程序的输出显示如下:
跳转指令代码 = EB5890 (H)
OEM 名称和版本 = MSWIN4.1
每扇区字节数 = 512
每簇扇区数 = 8
保留扇区 = 32
FAT 副本 = 2
根目录条目 = 0
编号磁盘扇区数 = 0
媒体描述符字节 = F8 (H)
每个 FAT 扇区数 = 0
每磁道扇区数 = 63
编号边
数
= 255保留(隐藏)扇区数 = 63 ============ 对于大型(>32MB)磁盘 ============否。扇区数(如果卷 > 32MB)= 11277567每个 FAT 的扇区数 = 11003根目录起始簇 = 2文件系统信息扇区 = 1备份引导扇区的扇区数 = 6物理驱动器编号 = 80(H)扩展引导签名 = 29(H)32 位二进制卷 ID = 110101010001100001110111100101(B)卷标 = SAAYA FAT 名称 = FAT32幻数 = 55AA(H)
在程序的输出中,我们看到以下参数显示为零:
这些参数之所以如此,是因为如果分区卷的大小大于 32MB,并且实际信息位于 DBR 的扩展卷信息块中,则这些值被设置为零。
例如,在 DBR 信息的初始部分,每个 FAT 的扇区数为 0,而在 DBR 的扩展卷信息块中,每个 FAT 的扇区数为 11003,这是此大卷的实际值。
Volume的DBR包含了有关磁盘参数的重要信息,这些信息可以用来链接所有数据信息以进行编程。比如你想访问磁盘上另外一个Partition卷的DBR,你可以通过DBR中写入的扇区数和其他相关信息来计算。
如果您想要以簇的方式访问磁盘,可以借助每簇扇区数、每个 FAT 扇区数等信息进行计算。
如果您使用的硬盘大于 8.4 GB(请参阅本书前面讨论的“磁盘和操作系统的逻辑方法”一章),请使用扩展来访问超过 8.4 GB 的磁盘的所有 DBR。参考前面章节给出的扩展读写函数
如何通过编程恢复 DBR
您可以使用一些巧妙的方法和逻辑计算将磁盘卷的 DBR 恢复至 100%。正如我们在本书前面的“磁盘和操作系统的逻辑方法”一章中讨论过的文件系统的逻辑方法一样,DBR 中的每条信息都是在某些限制或规则内编写的。
DBR 中写的每个参数都有特定的含义,并且遵循特定的规则和原因。这就是为什么如果 DBR 的信息丢失了,只要你遵循这些规则,并运用巧妙的思维来找出需要解决的问题和解决方法,就可以手动重新链接或重写。
例如,下表描述了不同文件系统每个簇的扇区数,您可以使用该表找到磁盘每个簇的扇区数。假设您的磁盘容量约为 10GB,并且您使用的操作系统是 Windows 98。
现在,如果来自卷的 DBR 的任何“每簇扇区数”信息损坏。让我们尝试找出您的磁盘卷中有哪些文件系统以及每个簇有多少个扇区。
由于您磁盘中的操作系统是 Windows 98,它仅支持 FAT 文件系统,因此您的卷的文件系统是 FAT。现在让我们考虑一下卷的大小,大约为 10GB。
我们知道 FAT16 不支持 10GB 分区(参见下表),因此该卷的文件系统应为 FAT32。
现在让我们尝试计算卷的每个簇的扇区数。从表中可以看出,8GB 到 16GB 范围内的分区有一个由 8 个扇区组成的簇。

因此,我们现在可以得出结论,在该卷中,文件系统是 FAT32,每个簇有 8 个扇区。类似地,我们可以使用本书前面章节中描述的其他逻辑方法来组装 DBR 的其他信息。
编写了下面的程序来重写 1.44Mb、3.5 英寸软盘的 DBR 中的磁盘参数信息,该软盘有 80 个磁道、2 个磁头(面)并且每个磁道有 18 个扇区。
/*程序将1.44MB、3.5英寸软盘的参数重写到其DBR */
#包括“dos.h”
#包括“stdio.h”
引导结构
{
无符号字符代码[3]; /* 跳转代码 */
无符号字符系统ID[8]; /* OEM ID 和版本 */
int 字节数/秒; /* 每扇区字节数 */
字符 sec_per_clus; /* 扇区数
每个集群 */
int res_sec; /* 保留部门 */
字符 fat_copies; /* FAT 的数量 */
int 根目录条目; /* 根数
目录条目 */
无符号整数无_sects; /* 总数量
部门 */
无符号字符格式_id; /* 媒体描述符
字节 */
int sec_per_fat; /* 每个 FAT 的扇区数 */
int sec_per_trk; /* 每个 FAT 的扇区数 */
int 无边数; /* 数量
侧面(正面) */
int no_sp_res_sect; /* 隐藏数字
部门 */
unsigned char rest_code[482] ;/* 剩余 482 字节代码
DBR */
};
结构启动b;
主要的( )
{
int 值;
val = absread(0, 1, 0,&b); /* 用于软盘 */
如果(val==-1)
{
printf ( "\n 磁盘读取错误...坏扇区\n" ) ;
退出(1);
}
clrscr();
显示信息();
获取();
printf("\n现在正在恢复软盘的 BDR.....\n");
恢复_使用_值();
printf ( "\n 磁盘恢复成功。" ) ;
显示信息();
返回0;
}
/*函数改变DBR的参数*/
恢复值()
{
int val = 0;
/* 软盘的 3 个字节跳转代码 */
b.代码[0] = 0xEB;
b.代码[1]= 0x3E;
代码[2]= 0x90;
/* 8 字节的系统 ID */
strcpy(b.system_id,“+05PSIHC”);
/* 每扇区字节数 = 512 */
b.字节每秒 = 512;
/* 1.44M 3.5 英寸软盘每簇扇区数 = 1 */
sec_per_clus = 1;
/* 保留扇区数 = 1 */
b.res_sec = 1;
/* FAT 副本数 = 2 */
b.fat_copies =2;
/* 根目录条目数 = 224 */
b.root_dir_entry = 224;
/* 磁盘扇区数 = 2880 */
b.无昆虫数 = 2880;
/* 软盘的媒体描述符字节 = F0 (H) */
b.格式_id = 0xF0;
/* 每个 FAT 扇区数 = 9 */
b.sec_per_fat = 9;
/* 每磁道扇区数 = 18 */
b.sec_per_trk = 18;
/* 边数 = 2 */
b.无边数 =2;
/* 特殊保留扇区(或隐藏扇区)的数量
部门)= 0 */
b.无_sp_res_sect =0;
/* 用于软盘 */
val = abswrite ( 0, 1, 0, &b ) ;
如果(val==-1)
{
printf ( "\n 磁盘写入错误...坏扇区\n" ) ;
printf ("磁盘未恢复。");
退出(1);
}
返回0;
}
显示信息()
{
printf ("\n 跳转代码 (十六进制) = %X%X%X (H)\n",
b.代码[0],b.代码[1],b.代码[2]);
printf("系统 ID = %s\n",
b.系统ID );
printf("每扇区字节数 = %d\n",
每秒字节数 );
printf("每簇扇区数 = %d\n",
sec_per_clus );
printf("保留扇区 = %d\n",
b.res_sec );
printf("FAT 副本 = %d\n",
复制代码
printf("根目录条目 = %d\n",
根目录条目 );
printf(" 磁盘扇区数 = %u\n",
b.无_sects );
printf("媒体描述符字节 = %X\n",
格式ID );
printf("FAT 上的扇区 = %d\n",
sec_per_fat );
printf("每磁道扇区数 = %d\n",
sec_per_trk );
printf("边数 = %d\n",
b.无边数);
printf("保留扇区数 = %d\n",
否则,将导致结果不准确。
返回0;
}
编码注释:
引导结构用于访问DBR,读取和写入磁盘参数。 display_info() 函数通过读取 DBR 显示各种磁盘参数。 Recover_with_values() 函数用于更改和恢复 DBR 软盘参数。
Recover_with_values() 函数使用的值适用于 1.44 MB、3 ½ 英寸 DBR 软盘。下表给出了这些值的描述:
