第13章
プログラミングによる MBR の読み取りと変更
DOS ブートレコード (DBR) / DOS ブートセクター
パーティション テーブルの次に、DOS ブート レコード (DBR)、または DOS ブート セクターと呼ばれることもある情報は、ハード ドライブ上で 2 番目に重要な情報です。
DBR の詳細については、この本の前半で説明した「ディスクと OS への論理的アプローチ」の章を参照してください。
各 DOS パーティションの最初の論理セクターには、DOS ブート レコード (DBR) または DOS ブート セクターが含まれます。 DBR の役割は、オペレーティング システムをハード ディスクからコンピューターのメイン メモリにロードし、システムの制御をロードされたプログラムに渡すことです。
ハードディスクの最初のパーティションの DOS ブート レコード (DBR) は、通常、絶対セクター 63 (ディスクの 64 番目のセクター) または CHS 形式に配置されます。つまり、ほとんどのディスクでは、C–H–S = 0–1–1 と言えます。
ただし、この配置はドライブの SPT (トラックあたりのセクター数) によって異なる場合があります。たとえば、SPT が 31 個しかない古い 245 MB ドライブでは、ブート レコードはセクター 32 (絶対セクター 31) に配置されていました。
フロッピー ディスクにはパーティションがないため、最初のセクターには MBR (マスター パーティション テーブル) はなく、代わりに最初のセクターに DBR が含まれます。
DBR は、FDISK コマンドでパーティション分割した後、FORMAT DOS コマンドによって作成されます。 DBR が存在するセクターは、DOS の特定のパーティションの論理セクター 1 になります。 DOS で使用されるセクター番号は、DBR が配置されている物理セクターから始まります。
DBR には、マスター ブート レコード (MBR) 実行可能プログラムによって実行される小さなプログラムが含まれています。すべての DOS パーティションには、マシンを起動するためのプログラム コードが含まれています。オペレーティング システムを起動しますが、パーティション テーブル エントリでアクティブ パーティションとして指定されているマスター ブート レコードから制御を受け取るのはこのパーティションのみです。
DBR が何らかの形で破損している場合でも、ブートフロッピー ディスクまたは CD からシステムを起動すればディスクにアクセスできるはずです。ハード ドライブは起動できませんが (アクティブ パーティションの DBR が破損している場合)、通常はドライブ上のデータへのアクセスには影響しません。ブートディスクからシステムを起動すると、データにアクセスできます。
/*フロッピーディスクのブートパラメータを表示します*/
# <dos.h> をインクルードする
# <stdio.h> をインクルードする
基本( )
{
荷重構造
{
符号なし文字コード[3]; /* 遷移コード */
unsigned char system_id[8] ;/* OEM名とバージョン*/
1秒あたりのバイト数; /* セクターあたりのバイト数 */
シンボル sec_per_clus ; /* クラスターあたりのセクター数 */
整数res_sec; /* 予約済みセクター */
char fat_copies ; /* FAT の数 */
ルートディレクトリエントリ; /* ルート番号
ディレクトリエントリ */
符号なし整数 no_sects ; /* セクター数
論理ボリューム */
符号なしcharフォーマットID; /* メディア記述子バイト
*/
秒あたりの脂肪量; /* FAT 上のセクター */
秒あたりの秒数; /* トラックあたりのセクター数 */
int ノーサイド; /* ヘッドの数 */
整数 no_sp_res_sect ; /* 隠し要素の数
セクター */
符号なしchar rest_code[482] ; /* 残りのコード */
} ;
荷重構造b;
シンボルtemp[4];
int 値、ドライブ;
val = absread(0, 1, 0, &b) ; /* フロッピーディスクに使用*/
( 値 == -1 ) の場合
{
printf ( "ディスクの読み取りエラー...不良セクタ\n" );
出力(1)
}
clrscr() ;
printf("システム識別子 = %s\n",
b.システム識別子 ;
printf ( "セクターあたりのバイト数 = %d\n",
b.バイト数(秒);
printf ( "クラスターあたりのセクター数 = %d\n",
b.クラスあたりの秒数);
printf ( "予約済みセクター = %d\n",
b.res_sec ) ;
printf ( "FATコピー数 = %d\n",
b.fat_copies ) ;
printf ( "ルートディレクトリエントリ = %d\n",
b.root_dir_entry ) ;
printf ( "ディスク上のセクター数 = %u\n",
b. セクションなし ) ;
printf ( "メディア記述子バイト = %X\n",
b.フォーマットID ) ;
printf ( "FAT あたりのセクター数 = %d\n",
b.sec_per_fat ) ;
printf ( "トラックあたりのセクター数 = %d\n",
b.sec_per_trk ) ;
printf ( "辺の数 = %d\n",
b.側面なし) ;
printf ( "予約セクター数 = %d\n",
b.no_sp_res_sect ) ;
0を返します。
}
このプログラムを実行して、70 トラック、両面、トラックあたり 18 セクター、セクターあたり 512 バイトの 1.44M、3½ インチ フロッピー ディスクの DBR をテストすると、プログラムの出力は次のように表示されます。
システム ID = +1<*uIHC
セクターあたりのバイト数 = 512
クラスターあたりのセクター数 = 1
予約済みセクター数 = 1
FAT コピー数 = 2
ルート ディレクトリ エントリ
数 = 224 ディスク上のセクター数 = 2880
メディア記述子バイト = F0
FAT あたりのセクター数 = 9
トラックあたりのセクター数= 18
面数= 2
予約済みセクター数 = 0
大容量のDBRの読み取り
サイズが 32 MB を超えるパーティション ボリュームの DBR 形式は、32 MB 以下のボリュームの DBR 形式と多少異なります。
これは、大容量のディスクをサポートするためです (詳細な説明については、この本の前半で説明した「ディスクと OS への論理的アプローチ」の章を参照してください)。
FAT32 ボリュームの DOS ブート レコードの形式は次の表に示されています。

次のプログラムは、サイズが 32 MB を超える大きなボリュームの DBR を読み取ります。
/*大容量ディスクボリュームのブートパラメータを表示するプログラム*/
# "dos.h" をインクルードする
# "stdio.h" をインクルードする
void main()
{
構造体ブート
{
unsigned char code[3] ; /* ジャンプコード */
unsigned char system_id[8] ; /* OEM名とバージョン */
int bytes_per_sec ; /* セクターあたりのバイト数 */
文字sec_per_clus; /* クラスターあたりのセクター数*/
unsigned int res_sec; /* 予約数
セクター */
char fat_copies ; /* FAT の数 */
unsigned int root_dir_entry ;/* ルートディレクトリの番号
ディレクトリエントリ */
unsigned int no_sects; /* セクター数
論理ボリューム(
ボリュームは 32MB 以下) */
unsigned char Media_id ; /* メディア記述子バイト
*/
unsigned int sec_per_fat ; /* FAT あたりのセクター数 */
unsigned int sec_per_trk; /* トラックあたりのセクター数 */
unsigned int no_sides ; /* 表の数 */
unsigned long no_sp_res_sect ; /* 隠し要素の数
セクター */
unsigned long long_sec_num; /* 合計セクター数
論理ボリューム
( サイズ >32MB) */
unsigned long num_sec_per_FAT; /* FAT あたりのセクター数 */
unsigned int binary_flags; /* バイナリフラグ */
unsigned char version_of_FAT1; /* FATの最初のバイト
バージョン */
unsigned char version_of_FAT2; /* FATの2番目のバイト
バージョン */
符号なしロング root_dir_start_cluster;
/* ルートディレクトリ
クラスターの開始
番号 */
符号なし整数 sec_num_of_file_sys;
/* セクター番号
ファイルシステム
情報部門
*/
符号なし整数 sec_num_of_backup_boot_sec;
/* セクター番号
バックアップブートセクター
*/
unsigned char reserved[12]; /* 予約済み */
符号なしchar論理ドライブ番号;
/* 物理ドライブ
論理数
音量 */
unsigned char unused_byte; /* 未使用バイト */
符号なしchar hex_extd_boot_signature;
/* 拡張ブート
署名(29H) */
unsigned long binary_volume_ID;/* バイナリボリュームID */
unsigned char volume_label[11];/* ボリュームラベル */
unsigned char FAT_name[8]; /* FAT名 */
unsigned char rest_code[420] ; /* 残りの420バイト
DBR */
unsigned char magic_number[2]; /* マジックナンバー */
} ;
構造体ブートb;
文字 temp[4] ;
int 値、ドライブ、i;
val = biosdisk( 2, 0x80, 1,0,1,1, &b ) ;
/* 最初のハードディスクの場合 */
( 値 == -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 ",
b. 1秒あたりのバイト数 );
printf ( "クラスターあたりのセクター数 = %u\n ",
b.sec_per_clus );
printf ( "予約セクター = %u\n ",
b.res_sec ) ;
printf ( "FATコピー数 = %d\n ",
b.fat_copies ) ;
printf ( "ルートディレクトリエントリ = %u\n ",
b.root_dir_entry ) ;
printf ( "ディスク上のセクター数 = %u\n ",
b. セクションなし ) ;
printf ( "メディア記述子バイト = %X(H)\n",
b.メディアID ;
printf ( "FATあたりのセクター数 = %u\n ",
b.sec_per_fat ) ;
printf ( "トラックあたりのセクター数 = %u\n ",
b.sec_per_trk ) ;
printf ( "辺の数 = %u\n ",
b.側面なし) ;
printf ( "予約済み(隠し)セクター数= %lu\n ",
b.no_sp_res_sect ) ;
printf ( "========== 大容量(>32MB)ディスクの場合 ========\n");
printf ( "セクター数、(ボリュームが32MBを超える場合) = %lu\n "、
b.long_sec_num) ;
printf ( “FATあたりのセクター数 = %lu\n “,
b.num_sec_per_FAT );
printf ( "ルートディレクトリ開始クラスタ = %lu\n ",
b.root_dir_start_cluster);
printf ( "ファイルシステム情報セクター = %u\n ",
b.ファイルシステムの秒数);
printf ( "バックアップブートセクターのセクター番号 = %u\n ",
b.バックアップブート秒数の秒数);
printf ( "物理ドライブ番号 = %X(H)\n",
b.論理ドライブ番号);
printf ( "拡張ブート署名 = %X(H)\n",
b.hex_extd_boot_signature);
printf ( "32 ビットバイナリボリューム ID = ");
小数点からバイナリへ(b.binary_volume_ID,32);
printf ( " (B)\n ");
printf ( "ボリュームラベル = ");
(i=0;i<=10;i++) の場合
{
printf ( "%c",b.volume_label[i]);
}
printf ( "\n FAT名 = ");
(i=0;i<=7;i++) の場合
{
printf ( "%c",b.FAT_name[i]);
}
printf ( "\n ");
printf ( "マジックナンバー = %X%X(H)",
b.マジックナンバー[0]、b.マジックナンバー[1]);
getch();
}
//////// 10 進数から 2 進数への変換関数\\\\\\\\
Decimal_to_Binary(符号なしlong入力)
{
符号なしロングi;
整数カウント = 0;
int binary [32]; /* 32ビットMAXのみ32
要素の合計 */
する
{
i = input%2; /* MOD 2 で 1 または 0 を取得します*/
binary[count] = i; /* 要素を読み込む
バイナリ配列 */
input = input/2; /* 入力を2で割って
バイナリによる減算 */
count++; /* 要素数を数える
必要です*/
}while (入力 > 0);
/* 2進数を反転して出力します*/
する
{
printf ("%d", バイナリ[count - 1]);
カウント - ;
} while (count > 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)
プログラムの出力では、次のパラメータがゼロになっていることがわかります。
- ルートディレクトリエントリ
- ディスク上のセクター数
- FAT あたりのセクター数
これらのパラメータは、パーティション ボリュームのサイズが 32 MB を超えており、実際の情報が DBR の拡張ボリューム情報ブロック内にある場合、これらの値がゼロに設定されるためです。
たとえば、DBR 情報の最初の部分では、FAT あたりのセクター数は 0 ですが、DBR の拡張ボリューム情報ブロックでは、FAT あたりのセクター数は 11003 です。これが、この大きなボリュームの実際の値です。
ボリュームの DBR には、ディスク パラメータに関する重要な情報が含まれており、プログラミングの目的ですべてのデータ情報をリンクするために使用できます。たとえば、ディスク上の他のパーティション ボリュームの DBR にアクセスする場合は、DBR に書き込まれたセクター数やその他の関連情報によって計算できます。
クラスター アプローチを使用してディスクにアクセスする場合は、クラスターあたりのセクター数、FAT あたりのセクター数、およびその他の情報を使用して計算を行うことができます。
8.4 GB を超えるハードディスクを使用している場合は (本書の前半で説明した「ディスクと OS への論理的アプローチ」の章を参照)、拡張機能を使用して 8.4 GB を超えるディスクのすべての DBR にアクセスします。前の章で説明した拡張読み取り/書き込み機能を参照してください。
プログラミングでDBRを回復する方法
いくつかの巧妙なアプローチと論理計算を使用することで、ディスク ボリュームの DBR を最大 100 パーセントまで回復できます。本書の前半の「ディスクと OS への論理的アプローチ」の章でファイル システムの論理的アプローチについて説明したように、DBR 内のすべての情報は、何らかの制限またはルールの範囲内で書き込まれます。
DBR に書き込まれるすべてのパラメータには特定の意味があり、特定のルールと理由に従って書き込まれます。そのため、DBR の情報が失われた場合、これらのルールに従い、巧妙な頭脳を使って何をどのように修正すればよいかを見つければ、手動で再リンクまたは書き換えることができます。
たとえば、次の表は、さまざまなファイル システムのクラスターあたりのセクター数を示しています。この表を使用して、ディスクのクラスターあたりのセクター数を調べることができます。ディスクに約 10 GB のボリュームがあり、使用しているオペレーティング システムが Windows 98 であると仮定します。
さて、ボリュームの DBR の「クラスターあたりのセクター数」情報が破損しているかどうかを確認します。ディスクのボリュームにどのファイル システムがあり、クラスターあたりのセクター数がいくつあるかを調べてみましょう。
ディスクのオペレーティング システムは Windows 98 であり、FAT ファイル システムのみをサポートしているため、ボリュームのファイル システムは FAT でした。ここで、ボリュームのサイズについて考えてみましょう。これは約 10 GB でした。
10GB パーティションは FAT16 ではサポートされていないため (次の表を参照)、ボリュームのファイル システムは FAT32 である必要があります。
次に、ボリュームのクラスターあたりのセクター数を計算してみましょう。表からわかるように、8 GB から 16 GB の範囲内のパーティションには、8 つのセクターのクラスターが 1 つあります。

したがって、ボリューム内のファイル システムは、クラスターごとに 8 つのセクターを持つ FAT32 であると結論付けることができます。同様に、この本の前の章で説明した他の論理的アプローチを使用して、DBR のその他の情報をまとめることができます。
以下のプログラムは、80 トラック、2 ヘッド (サイド)、トラックあたり 18 セクターの 1.44Mb、3½ インチ フロッピー ディスクの DBR のディスク パラメータ情報を書き換えるために作成されました。
/* 1.44MB、3½ インチフロッピーディスクのパラメータを DBR に書き換えるプログラム*/
# "dos.h" をインクルードする
# "stdio.h" をインクルードする
構造体ブート
{
unsigned char code[3] ; /* ジャンプコード */
unsigned char system_id[8] ; /* OEM IDとバージョン*/
int bytes_per_sec ; /* セクターあたりのバイト数 */
char sec_per_clus; /* セクター数
クラスターあたり */
int res_sec ; /* 予約済みセクター */
char fat_copies ; /* FAT の数 */
int root_dir_entry; /* ルートディレクトリの番号
ディレクトリエントリ */
unsigned int no_sects; /* 合計数
セクター */
unsigned char format_id ; /* メディア記述子
バイト */
int sec_per_fat ; /* FAT あたりのセクター数 */
int sec_per_trk; /* FATあたりのセクター数 */
int no_sides; /* サイド数
サイド(ヘッド) */
int no_sp_res_sect; /* 隠し要素の数
セクター */
unsigned char rest_code[482] ;/* 残りの482バイトのコード
DBRの*/
} ;
構造体ブートb;
主要( )
{
ヒント付き;
val = absread(0, 1, 0, &b); /* フロッピーディスクに使用 */
( 値 == -1 ) の場合
{
printf ( "\n ディスク読み取りエラー...不良セクタ\n" );
出口(1);
}
clrscr() ;
情報を表示します。
getch();
printf("\n フロッピーの BDR を回復しています.....\n");
値を回復します。
printf ( "\n ディスクが正常に回復されました。" );
情報を表示します。
0を返します。
}
/* DBR のパラメータを変更する関数*/
値を使用して回復する()
{
整数値 =0;
/* フロッピー用の 3 バイトのジャンプ コード */
b.コード[0] = 0xEB;
b.コード[1] = 0x3E;
b.コード[2] = 0x90;
/* 8 バイトのシステム ID */
strcpy(b.system_id, "+05PSIHC");
/* セクターあたりのバイト数 = 512 */
b. 1秒あたりのバイト数 = 512;
/* 1.44M 3.5 インチフロッピーのクラスターあたりのセクター数 = 1 */
b.sec_per_clus = 1;
/* 予約セクター数 = 1 */
b.res_sec = 1;
/* FAT コピーの数 = 2 */
b.fat_copies = 2;
/* ルートディレクトリエントリの数 = 224 */
b.root_dir_entry = 224;
/* ディスク上のセクター数 = 2880 */
b.no_sects = 2880;
/* フロッピーのメディア記述バイト = F0 (H) */
b.フォーマットID =0xF0;
/* FAT あたりのセクター数 = 9 */
b.sec_per_fat =9;
/* トラックあたりのセクター数 = 18 */
b.sec_per_trk = 18;
/* 辺の数 = 2 */
b.no_sides =2;
/* 特別予約セクター(または隠しセクター)の数
セクター) = 0 */
b.no_sp_res_sect = 0;
/* フロッピーディスクに使用*/
val = abswrite ( 0, 1, 0, &b ) ;
( 値 == -1 ) の場合
{
printf ( "\n ディスク書き込みエラー...不良セクタ\n" );
printf ( " ディスクは回復されませんでした。" );
出口(1);
}
0を返します。
}
表示情報()
{
printf ( "\n ジャンプコード (16進数) = %X%X%X (H)\n",
b.コード[0]、b.コード[1]、b.コード[2]);
printf ( " システム ID = %s\n",
b.システムID ) ;
printf ( " セクターあたりのバイト数 = %d\n",
b. 1秒あたりのバイト数 );
printf ( " クラスターあたりのセクター数 = %d\n",
b.sec_per_clus );
printf ( " 予約済みセクター = %d\n",
b.res_sec ) ;
printf ( " FAT コピー = %d\n",
b.fat_copies ) ;
printf ( " ルートディレクトリエントリ = %d\n",
b.root_dir_entry ) ;
printf ( " ディスク上のセクター数 = %u\n",
b. セクションなし ) ;
printf("メディア記述子バイト = %X\n",
b.フォーマットID ) ;
printf("FAT 上のセクター = %d\n",
b.sec_per_fat ) ;
printf("トラックあたりのセクター数 = %d\n",
b.sec_per_trk ) ;
printf("辺の数 = %d\n",
b.側面なし) ;
printf("予約済みセクター数 = %d\n",
б.no_sp_res_sect ) ;
0を返します。
}
コーディングコメント:
ブート構造は、DBR にアクセスし、ディスク パラメータを読み書きするために使用されます。 display_info() 関数は、DBR から読み取ってさまざまなディスク パラメータを表示します。 Recover_with_values() 関数は、DBR フロッピー パラメータを変更および復元するために使用されます。
Recover_with_values() 関数で使用される値は、1.44 MB、3 ½ インチ DBR フロッピー ディスク用です。これらの値の説明は以下の表に示されています。
