LinuxにおけるgrubによるMBRの修復方法
「LinuxにおけるMBRのまとめとバックアップ方法」で調べたとおりHDDの先頭セクタに置かれるMBRはLinuxがブートするためには(Windowsでも)大変重要な512バイトになる。ここが壊れるとシステムがブートしなくなる。従って、LinuxにおけるMBRのまとめとバックアップ方法で考察したような方法でMBRをバックアップしておくことが必須と考える。*1
MBRには大きく分けてブートストラップローダの部分とパーティションテーブルの部分に分けられるが、パーティションテーブルの情報が失われるとHDDの何処にどのようなシステムが保存されているが分からなくなるので、基本的にはそのHDDにあるシステムを救うのは難しくなる。(シェルスクリプトでパーティションテーブル復旧用のプログラムを組んでみたが、HDD全体をなめる必要があるので気の長くなるような時間がかかる。その内、Cで組んでみたいととは思っているが。)そのためMBRのバックアップは必須になるが、一方でブートストラップローダの部分は再インストールが可能である。パーティションテーブルさえ生き残っていればシステムを救うことは比較的簡単かと思う。そこで、その方法をメモしておく。なお、ここではGRUBをブートストラップローダとして検証している。(LILOやWindowsの環境でのf復旧方法ではないのでアシカラズ。)
ちなみにMBRが壊れる原因はいくつか考えられるが、次のようなケースだろう。
- オペレーションミスによる破壊。
- 異なるOSをインストールすることによるMBRの上書き。
- ウィルスなどによる恣意的な破壊。(例えば「MBR感染機能付きルートキット「StealthMBR」」)
さて、まず実験の犠牲となるシステムを1つ選んで、次のようにしてMBRのブートストラップ部分をわざと壊しておく。(下手をするパーティションテーブルまで破壊するので、実験する際は注意すること。MBRのバックアップをとってから行う方がいい。バックアップは「MBRのバックアップ」を参照。)
[root@fedora-8 ~]# hexdump -C -n 512 /dev/sda : ←一応、内容を確認 00000000 eb 48 90 10 8e d0 bc 00 b0 b8 00 00 8e d8 8e c0 |.H..............| 00000010 fb be 00 7c bf 00 06 b9 00 02 f3 a4 ea 21 06 00 |...|.........!..| 00000020 00 be be 07 38 04 75 0b 83 c6 10 81 fe fe 07 75 |....8.u........u| 00000030 f3 eb 16 b4 02 b0 01 bb 00 7c b2 80 8a 74 03 02 |.........|...t..| 00000040 80 00 00 80 41 20 01 00 00 08 fa 90 90 f6 c2 80 |....A ..........| 00000050 75 02 b2 80 ea 59 7c 00 00 31 c0 8e d8 8e d0 bc |u....Y|..1......| 00000060 00 20 fb a0 40 7c 3c ff 74 02 88 c2 52 be 7f 7d |. ..@|<.t...R..}| 00000070 e8 34 01 f6 c2 80 74 54 b4 41 bb aa 55 cd 13 5a |.4....tT.A..U..Z| 00000080 52 72 49 81 fb 55 aa 75 43 a0 41 7c 84 c0 75 05 |RrI..U.uC.A|..u.| 00000090 83 e1 01 74 37 66 8b 4c 10 be 05 7c c6 44 ff 01 |...t7f.L...|.D..| 000000a0 66 8b 1e 44 7c c7 04 10 00 c7 44 02 01 00 66 89 |f..D|.....D...f.| 000000b0 5c 08 c7 44 06 00 70 66 31 c0 89 44 04 66 89 44 |\..D..pf1..D.f.D| 000000c0 0c b4 42 cd 13 72 05 bb 00 70 eb 7d b4 08 cd 13 |..B..r...p.}....| 000000d0 73 0a f6 c2 80 0f 84 ea 00 e9 8d 00 be 05 7c c6 |s.............|.| 000000e0 44 ff 00 66 31 c0 88 f0 40 66 89 44 04 31 d2 88 |D..f1...@f.D.1..| 000000f0 ca c1 e2 02 88 e8 88 f4 40 89 44 08 31 c0 88 d0 |........@.D.1...| 00000100 c0 e8 02 66 89 04 66 a1 44 7c 66 31 d2 66 f7 34 |...f..f.D|f1.f.4| 00000110 88 54 0a 66 31 d2 66 f7 74 04 88 54 0b 89 44 0c |.T.f1.f.t..T..D.| 00000120 3b 44 08 7d 3c 8a 54 0d c0 e2 06 8a 4c 0a fe c1 |;D.}<.T.....L...| 00000130 08 d1 8a 6c 0c 5a 8a 74 0b bb 00 70 8e c3 31 db |...l.Z.t...p..1.| 00000140 b8 01 02 cd 13 72 2a 8c c3 8e 06 48 7c 60 1e b9 |.....r*....H|`..| 00000150 00 01 8e db 31 f6 31 ff fc f3 a5 1f 61 ff 26 42 |....1.1.....a.&B| 00000160 7c be 85 7d e8 40 00 eb 0e be 8a 7d e8 38 00 eb ||..}.@.....}.8..| 00000170 06 be 94 7d e8 30 00 be 99 7d e8 2a 00 eb fe 47 |...}.0...}.*...G| 00000180 52 55 42 20 00 47 65 6f 6d 00 48 61 72 64 20 44 |RUB .Geom.Hard D| 00000190 69 73 6b 00 52 65 61 64 00 20 45 72 72 6f 72 00 |isk.Read. Error.| 000001a0 bb 01 00 b4 0e cd 10 ac 3c 00 75 f4 c3 00 00 00 |........<.u.....| 000001b0 00 00 00 00 00 00 00 00 f2 e3 02 00 00 00 80 01 |................| 000001c0 01 00 83 fe 3f 18 3f 00 00 00 9a 20 06 00 00 00 |....?.?.... ....| 000001d0 01 19 8e fe ff ff d9 20 06 00 3b ca f9 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.| 00000200 [root@fedora-8 ~]# dd if=/dev/zero bs=1 count=446 of=/dev/sda : ←ローダ部分を破壊 446+0 records in 446+0 records out 446 bytes (446 B) copied, 0.000633598 s, 704 kB/s [root@fedora-8 ~]# hexdump -C -n 512 /dev/sda : ←壊れていることを確認 00000000 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 80 01 |................| 000001c0 01 00 83 fe 3f 18 3f 00 00 00 9a 20 06 00 00 00 |....?.?.... ....| 000001d0 01 19 8e fe ff ff d9 20 06 00 3b ca f9 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.| 00000200 [root@fedora-8 ~]#
これでパーティションテーブルの手前まで全てゼロで潰した。この状態でリブートすると、当然システムは立ち上がらない。(赤い部分は後で解説。)
■ grub-installによるMBRの簡易修復
まず、CD/DVDからブートしてCD/DVDとメモリだけで動作するISO Linuxを起動する。ディストリビューションにより多少の違いはあるが、基本的には殆どのディストリビューションで提供している筈。ここではFedora 8のインストールDVDをレスキューモードで起動してシェルの状態にする。(UbuntuであればインストールDVDから“コンピュータに変更を加えないでUbuntuをつかてみる”を選択して起動すればウィンドウ環境のISO Linuxが動くので便利。Fedoraでのレスキューモードでの立ち上げ方は「ふろく:レスキューモードの起動手順」を参照。ここではFedoraを使って検証したが、シェルさえ使えればUbuntuでも他のディストリビューションでも大差はないと思う。)
レスキューモードで立ち上がったら grub-install というコマンドを使う。レスキューモードで問題なく立ち上がっていればHDDに入っているルートファイルシステムは“/mnt/sysimage/”というディレクトリにマウントされ、/bootのファイルシステム(がもしあれば)“/mnt/sysimage/boot/”というディレクトリのマウントされているはずである。つまり“/mnt/sysimage/”がHDDにインストールされている事実上の/(ルート)ディレクトリとなる。そこでまず、chrootコマンドでISO Linuxの環境からHDDのシステムの環境に移行する。
sh-3.2# chroot /mnt/sysimage/ sh-3.2#
chrootコマンドは何のメッセージも出さないので本当にルートディレクトリが変わっているか確認するには、/をlsしてみる。
sh-3.2# ls / bin dev halt lib lost+found mnt proc sbin srv tmp var boot etc home lib64 media opt root selinux sys usr sh-3.2#
例えば、/homeはISO Linuxには無いので、これがあればchrootできていることが確認できる。
そして次にgrub-installを実行する。
sh-3.2# grub-install /dev/sda Installation finished. No error reported. This is the contents of the device map /boot/grub/device.map. Check if this is correct or not. If any of the lines is incorrect, fix it and re-run the script `grub-install'. # this device map was generated by anaconda (hd0) /dev/sda sh-3.2#
これでsdaディスクのMBRが修復できた。確認のためMBRのダンプをとってみる。
sh-3.2# hexdump -C -n 512 /dev/sda 00000000 eb 48 90 00 00 00 00 00 00 00 00 00 00 00 00 00 |.H..............| 00000010 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 03 02 |................| 00000040 ff 00 00 20 01 00 00 00 00 02 fa 90 90 f6 c2 80 |... ............| 00000050 75 02 b2 80 ea 59 7c 00 00 31 c0 8e d8 8e d0 bc |u....Y|..1......| 00000060 00 20 fb a0 40 7c 3c ff 74 02 88 c2 52 be 7f 7d |. ..@|<.t...R..}| 00000070 e8 34 01 f6 c2 80 74 54 b4 41 bb aa 55 cd 13 5a |.4....tT.A..U..Z| 00000080 52 72 49 81 fb 55 aa 75 43 a0 41 7c 84 c0 75 05 |RrI..U.uC.A|..u.| 00000090 83 e1 01 74 37 66 8b 4c 10 be 05 7c c6 44 ff 01 |...t7f.L...|.D..| 000000a0 66 8b 1e 44 7c c7 04 10 00 c7 44 02 01 00 66 89 |f..D|.....D...f.| 000000b0 5c 08 c7 44 06 00 70 66 31 c0 89 44 04 66 89 44 |\..D..pf1..D.f.D| 000000c0 0c b4 42 cd 13 72 05 bb 00 70 eb 7d b4 08 cd 13 |..B..r...p.}....| 000000d0 73 0a f6 c2 80 0f 84 ea 00 e9 8d 00 be 05 7c c6 |s.............|.| 000000e0 44 ff 00 66 31 c0 88 f0 40 66 89 44 04 31 d2 88 |D..f1...@f.D.1..| 000000f0 ca c1 e2 02 88 e8 88 f4 40 89 44 08 31 c0 88 d0 |........@.D.1...| 00000100 c0 e8 02 66 89 04 66 a1 44 7c 66 31 d2 66 f7 34 |...f..f.D|f1.f.4| 00000110 88 54 0a 66 31 d2 66 f7 74 04 88 54 0b 89 44 0c |.T.f1.f.t..T..D.| 00000120 3b 44 08 7d 3c 8a 54 0d c0 e2 06 8a 4c 0a fe c1 |;D.}<.T.....L...| 00000130 08 d1 8a 6c 0c 5a 8a 74 0b bb 00 70 8e c3 31 db |...l.Z.t...p..1.| 00000140 b8 01 02 cd 13 72 2a 8c c3 8e 06 48 7c 60 1e b9 |.....r*....H|`..| 00000150 00 01 8e db 31 f6 31 ff fc f3 a5 1f 61 ff 26 42 |....1.1.....a.&B| 00000160 7c be 85 7d e8 40 00 eb 0e be 8a 7d e8 38 00 eb ||..}.@.....}.8..| 00000170 06 be 94 7d e8 30 00 be 99 7d e8 2a 00 eb fe 47 |...}.0...}.*...G| 00000180 52 55 42 20 00 47 65 6f 6d 00 48 61 72 64 20 44 |RUB .Geom.Hard D| 00000190 69 73 6b 00 52 65 61 64 00 20 45 72 72 6f 72 00 |isk.Read. Error.| 000001a0 bb 01 00 b4 0e cd 10 ac 3c 00 75 f4 c3 00 00 00 |........<.u.....| 000001b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 01 |................| 000001c0 01 00 83 fe 3f 18 3f 00 00 00 9a 20 06 00 00 00 |....?.?.... ....| 000001d0 01 19 8e fe ff ff d9 20 06 00 3b ca f9 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.| 00000200 sh-3.2#
あとはrebootコマンドでリブートすれば無事に立ち上がる。
確かに立ち上がるのだけども、MBR(=第0セクタ)のダンプの内容を確認するとなんか変だ。もともとのブートストラップローダ(1次ローダ)では2次ローダをHDDの 0x00012041セクタから読むが、grub-installでインストールした1次ローダは2次ローダをHDDの 0x00000001セクタ(つまり第1セクタ)から読むようになっている。
そこで第1セクタをダンプしてみると確かに2次ローダらしい情報が書き込まれている。色々しらべたら第1セクタ〜第24セクタまでext2/ext3用の1.5次ローダ(/boot/grub/e2fs_stage1_5をちょっと修正したもの)が書き込まれている。
つまり、grub-installでインストールした1次ローダはいきなり2次ローダを読み込むのではなく、ファイルシステムに合わせた1.5次ローダを読み込む形なっていた。
まぁ、無事にブートできるようになったのだから、良いのは良いのだが。
ここで、ちょっと実験をした。最初のMBRのバックアップを元に戻してみた。そしたらブートしない。GRUBがハングアップしたり暴走したりする。つまり、grub-installによって2次ローダに変更が加えられて、HDD上の位置が変ってしまったために立ち上がらなくなってしまった、と推測できる。
まとめるとgrub-installによるMBRの簡易修復の留意点は以下のようになる。
■ grubによるMBRの修復
/sbin/grub-installはシェルスクリプトで書かれたコマンドでgrubのプリプロセッサとなっている。grubは機能は高いが使いこなすにはある程度の知識が必要になるので、予めgrub-installでgrubへ渡すパラメータを用意した上でgrubを呼び出して使う形となる。逆に言えば、grub-installでは“お任せ”になってしまうので、きめの細かい設定ができない。
ブートストラップローダから直接2次ローダを呼び出すようにするためにはgrubを使わないとならないようだ。(grub-installの隠しオプションの含めて眺めてみたが、grub-installからは無理の様だ。)
そこで、grubの出番となるが、grubは機能が高く奥深いので調べ始めるとキリがない。ここではブートストラップローダから直接2次ローダを呼び出すように設定するところに限定して例を載せておく。
ISO Linuxが起動した時点でgrubを実行し、次のgrubコマンドを与える。(chrootする必要はない。)
sh-3.2# grub grub> root (hd0,0) grub> install /grub/stage1 d (hd0) /grub/stage2 p (hd0,0)/grub/grub.conf grub> quit sh-3.2#
“root (hd0,0)”はGRUGがインストールされているファイルシステム(つまり /bootのファイルシステム)のパーティションを指定している。この例では最初のHDDの最初のパーティションが/bootファイルシステムになっている(Fedoraのデフォルトの設定)。この指定をすれば次のinstallコマンドの引数で一々パーティションを指定する必要はなくなる。(逆にrootコマンドを実行しないでinstallの引数で一々指定してもインストールできる。)
installコマンドの引数は
- 1次ローダの指定
- 1次ローダのあるデバイスの指定オプション“d”:指定しないとMBRの0x40番地は“0xff”となり、BIOSから与えられたデバイスを使う。指定する場合はrootコマンドで指定されたデバイスとなり、通常は“0x80”が書き込まれる。
- 1次ローダをインストールするHDD ”(hd0)”
- 2次ローダの指定
- 2次ローダの修飾の指定オプション “p”:この“p”を指定すると2次ローダの0x208〜0x20B番地の“install_partition”を設定しなおす。
- grub.confの指定。この文字列が2次ローダ内部に書き込まれるのでパーティションの指定が必要。この文字列が2次ローダの0x217番地以降に埋め込まれる。
となる。rootコマンドでGRUBのファイルシステムを指定されていない場合は、次の様に引数を指定する。
grub> install (hd0,0)/grub/stage1 d (hd0) (hd0,0)/grub/stage2 p (hd0,0)/grub/grub.conf
さて、この結果のMBRは以下の通り。
sh-3.2# hexdump -C -n 512 /dev/sda 00000000 eb 48 90 00 00 00 00 00 00 00 00 00 00 00 00 00 |.H..............| 00000010 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 03 02 |................| 00000040 80 00 00 80 6f 28 01 00 00 08 fa 90 90 f6 c2 80 |....o(..........| 00000050 75 02 b2 80 ea 59 7c 00 00 31 c0 8e d8 8e d0 bc |u....Y|..1......| 00000060 00 20 fb a0 40 7c 3c ff 74 02 88 c2 52 be 7f 7d |. ..@|<.t...R..}| 00000070 e8 34 01 f6 c2 80 74 54 b4 41 bb aa 55 cd 13 5a |.4....tT.A..U..Z| 00000080 52 72 49 81 fb 55 aa 75 43 a0 41 7c 84 c0 75 05 |RrI..U.uC.A|..u.| 00000090 83 e1 01 74 37 66 8b 4c 10 be 05 7c c6 44 ff 01 |...t7f.L...|.D..| 000000a0 66 8b 1e 44 7c c7 04 10 00 c7 44 02 01 00 66 89 |f..D|.....D...f.| 000000b0 5c 08 c7 44 06 00 70 66 31 c0 89 44 04 66 89 44 |\..D..pf1..D.f.D| 000000c0 0c b4 42 cd 13 72 05 bb 00 70 eb 7d b4 08 cd 13 |..B..r...p.}....| 000000d0 73 0a f6 c2 80 0f 84 ea 00 e9 8d 00 be 05 7c c6 |s.............|.| 000000e0 44 ff 00 66 31 c0 88 f0 40 66 89 44 04 31 d2 88 |D..f1...@f.D.1..| 000000f0 ca c1 e2 02 88 e8 88 f4 40 89 44 08 31 c0 88 d0 |........@.D.1...| 00000100 c0 e8 02 66 89 04 66 a1 44 7c 66 31 d2 66 f7 34 |...f..f.D|f1.f.4| 00000110 88 54 0a 66 31 d2 66 f7 74 04 88 54 0b 89 44 0c |.T.f1.f.t..T..D.| 00000120 3b 44 08 7d 3c 8a 54 0d c0 e2 06 8a 4c 0a fe c1 |;D.}<.T.....L...| 00000130 08 d1 8a 6c 0c 5a 8a 74 0b bb 00 70 8e c3 31 db |...l.Z.t...p..1.| 00000140 b8 01 02 cd 13 72 2a 8c c3 8e 06 48 7c 60 1e b9 |.....r*....H|`..| 00000150 00 01 8e db 31 f6 31 ff fc f3 a5 1f 61 ff 26 42 |....1.1.....a.&B| 00000160 7c be 85 7d e8 40 00 eb 0e be 8a 7d e8 38 00 eb ||..}.@.....}.8..| 00000170 06 be 94 7d e8 30 00 be 99 7d e8 2a 00 eb fe 47 |...}.0...}.*...G| 00000180 52 55 42 20 00 47 65 6f 6d 00 48 61 72 64 20 44 |RUB .Geom.Hard D| 00000190 69 73 6b 00 52 65 61 64 00 20 45 72 72 6f 72 00 |isk.Read. Error.| 000001a0 bb 01 00 b4 0e cd 10 ac 3c 00 75 f4 c3 00 00 00 |........<.u.....| 000001b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 01 |................| 000001c0 01 00 83 fe 3f 18 3f 00 00 00 9a 20 06 00 00 00 |....?.?.... ....| 000001d0 01 19 8e fe ff ff d9 20 06 00 3b ca f9 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.| 00000200
あとはリブートすれば通常通り起動する。
この方法であれば、Linuxを最初にインストールした時と同様、1次ローダから直接2次ローダを起動するための第1セクタ〜第62セクタは使われない。
なお、grubでブートローダを設定する場合は、installコマンドではなくsetupコマンドを使うのが一般的のようだ。しかし、setupコマンドでは1.5次ローダを見つけると自動的に1.5次ローダをインストールしてしまう。そのため、1.5次ローダを使いたくない場合は直接 installコマンドを使う必要があるようだ。(ただし、setupコマンドで1.5次ローダが見つからないように1.5次ローダのファイルを予め別のディレクトリへ移動しておくと(つまり隠しておくと)、直接2次ローダを呼び出す構成でインストールする。)
ふろく:レスキューモードの起動手順
■ Fedora-8のインストールDVD
- メニューから“Rescue installed system”を選択
- 言語を選択”Japanese”
- しかし日本語使えないというメッセージが出る
- キーボードの選択。日本語キーボードであれば“jp106”
- ネットワークを使うかどうか。修復作業中に使わないのであれば“No”
- HDDの内容をマウントするかどうか。お任せマウントするのであれば“Continue”
(パーティションテーブルが壊れていればマウントできない)
- 無事にマウントできたメッセージ。環境を変えるときはchrootを使ってね、との説明
- 以上で設定は終了。レスキューモードでシェルが使えるようになる