パーティションテーブル解析結果


 やまざき氏のハードディスク(IBM DTLA-307030 30GB)が、パーティションのサイズを全部足すと48GBにもなるというトラブルで、そのパーティションテーブルのダンプを頂いて、解析した結果です。

 まず、MBRダンプの結果を以下に示します。

 MBR全体ではなく、下の方の主にパーティションテーブルの部分しか表示していません。数値は全てヘキサデシマル(16進数)です。以下文章中では、16進数は習慣通り、頭に必ず0xをつけて、10進数と区別します。

 オフセット 0x01BE からパーティションテーブルが始まっています。0x1BE から 0x1CD までが、第一パーティションエントリ、0x1CE から 0x1DD までが、第2パーティションエントリ、0x1DE から 0x1ED までが、第3パーティションエントリ、0x1EE から 0x1FD までが、第4パーティションエントリです。そして最後の2バイト「0x55AA」がシグニチャバイトです。

 

 まずこの第1パーティションエントリから解析します。

 第1パーティションエントリの最初の1バイト(オフセット0x01BE)が、ブートフラグですが、0x80なので、このパーティションがアクティブであることが分かります。

 次の3バイトがパーティションの開始位置(CHSアドレス)で、値は0x010100となっています。次の1バイトが、システムIDで、値が0x07になっており、このパーティションがNTFSであることが分かります。更にその次の3バイトが、パーティションの終了位置(CHSアドレス)で、値が0xFEBF7Cとなっています。

 次の4バイト(オフセット0x1C6)が、パーティション開始位置(LBAアドレス)で、値が0x3F000000となっています。更にその次の4バイトが、パーティションの総セクター数(LBAアドレス)で、値が0xFE259C00となっています。

 CHSアドレスの3バイトの内訳は次のようになります。先頭の1バイトは、そのままヘッド値です。

 次の2バイトがちょっと面倒ですが、2バイト目の後ろ6bitが、セクター値で、3バイト目全部とそれの頭に2バイト目の先頭2bitをつけたものが、シリンダー値となります。計算方法としては、2バイト目を64(0x40)で割った余りがセクター値となり、2バイト目を64(0x40)で割った商に256(0x100)を掛けて、それに3バイト目を足したものがシリンダー値となります。

 例えば、このエントリの終了位置「0xFEBF7C」の場合、先頭の1バイト「0xFE」はそのままヘッド値。次の1バイト「0xBF」を前2bit、後ろ6bitに分けると、「0x02」「0x3F」に分かれるので、後者がそのままセクター値。前者と3バイト目をくっつけた「0x27C」がシリンダー値となる訳です。

 LBAアドレスは単純ですが、後ろのバイトから並べます。つまり、このエントリの総セクター数の0xFE259C00は、0x9C25FEということになります。

 これを整理して、更に10進数に換算したものも加えて表にします。

[第1パーティションエントリ]

ブートフラグ システムID CHSアドレス LBAアドレス
開始位置 終了位置 開始位置 総セクター数
C H S C H S
16進数 80 07 0 1 1 27C FE 3F 3F 9C25FE
10進数 128 7 0 1 1 636 254 63 63 10,233,342

 PC/AT互換機の仕様通り、第2トラック(シリンダー0、ヘッド1)から始まっているのが分かります。また終了位置も、PC/AT互換機の仕様通り、ヘッド値とセクター値は、その最大値(それぞれ254と63)になっています。尚、シリンダー値とヘッド値は、0から始まりますが、セクター値だけは1から始まります。

 CHS値をLBA値に変換しても、計算がぴったり合います。総シリンダー数は、637、これにヘッド数255、セクター数63を掛けて、先頭トラックの63を引きます。637×255×63 - 63 = 10,233,342 となります。

 従ってこのパーティションは、全くPC/AT互換機の仕様通りの正しい値となっています。

 因みに、総セクター数に、1セクターのサイズ(512bytes)を掛ければ、このパーティションのサイズがでます。5,239,471,104 bytes となりますね。約5GBであることが分かるでしょう。

 

 さて次に第2パーティションエントリを見てみましょう。もう計算方法は省略します。上記のように表にすると以下となります。

[第2パーティションエントリ]

ブートフラグ システムID CHSアドレス LBAアドレス
開始位置 終了位置 開始位置 総セクター数
C H S C H S
16進数 00 0F 21B 0 1 21B 3F 3F 9C4500 3C19C80
10進数 0 15 539 0 1 539 63 63 10,241,280 63,020,160

 ブートフラグが「0x00」ですから、このパーティションがアクティブでないのはいいでしょう。システムIDが0x0Fとなっていて、この領域がLBA対応の拡張領域であることが分かります。

 さてアドレスですが、CHS値に関しては一見して不正であることがわかるでしょう。開始と終了が同じシリンダー値ですし、ヘッドの終了位置が63で、本来のヘッドの最大値になっていません。このCHS値からだと、このパーティションのサイズは、たった4032セクター、2,064,384 bytes つまり約2MBとなってしまいます。

 しかも、シリンダー値539というのは、前のパーティションの終了位置「636」よりも前方になってます。つまり前のパーティションと重複しているということになってしまう訳です。

 一方LBAアドレスを見ると、開始位置の方は一見よさそうに見えますが、ちゃんと計算してみると違います。本来は、前のパーティションの開始位置と総セクター数を足したものでなければなりません。つまり、0x3F + 0x9C25FE = 0x9C263D でないといけない訳です。ちょっと違いますね。

 総セクター数は、63,020,160×512bytes = 32,266,321,920 bytes、約32GBとなります。コンピュータの世界のお決まりとして、1024で割っていっても、30GBになるだけです。このハードディスクは30GBですから、前のパーティションと合わせて35GBとなり、全く矛盾します。

 この第2パーティションエントリは、どうみても不正と言えるでしょう。

 

 さて、次の第3パーティションエントリを見てみましょう。

[第3パーティションエントリ]

ブートフラグ システムID CHSアドレス LBAアドレス
開始位置 終了位置 開始位置 総セクター数
C H S C H S
16進数 00 0C 3FF DA 1 3FF D9 3F 9C4500 3C19C80
10進数 0 12 1023 218 1 1023 217 63 32,304,384 27,728,190

 このパーティションに至ってはひどいです。まあシステムIDは、「0x0C」なので、FAT32Xでいいのですが、CHSアドレスは、そもそも終了位置が開始位置よりも前です。たとえ逆にしても、パーティションサイズは、2セクター、1024 bytesになってしまいます。

 LBAアドレスも、開始位置は、先頭から、16,539,844,608 bytes、約16GB目ということで、やはり前のパーティション(拡張パーティション)の中に入ってしまっています。サイズも14,196,833,280 bytes、約14GBということですから、もし前のパーティションが正しいとしたら(正しい訳もないですが)、すっぽり入ってしまうことになります。

 

 さて、この値群を考察してみます。

 CHSアドレスは、本来的に8GB以降は常に不正となります。しかし不正なりに決まった値が入っているものなのですが、それも入っていません。また、CHSはハードディスクが返すジオメトリにより、必ずしもヘッド254やセクター63が最大値となる訳ではなりません。しかし、その場合でも、パーティションテーブルのデータから、ある程度はハードディスクが返すであろうジオメトリを推測することができますが、今回は全く規則性がないので、それもできません。

 ただ値によっては、それっぽい数値が入っている場合もあります。たとえば第2パーティションエントリのセクター値は63という、如何にもそれらしい数値が入っていますし、開始位置(LBA値)も少しずれているだけです。アナログな世界と違って、デジタルな世界では、ちょっと違うということはあまり起こらないはずなんです。

 全く不正と思われる第3パーティションエントリも、シリンダー値の1023や、セクター値の1や63の他、ブートフラグやシステムIDなど、ランダムなbitがたったにしては、あまりにもそれらしい数値が入っているので、何らかの事故で、全くパーティションの情報とは関係ない値が、書き込まれてしまったとは言い難い値となっています。

 また事故で、何らかのbitが反転するようなことがあったのなら、位置的に離れた、たとえば第2パーティションエントリの、開始シリンダー値と、終了シリンダー値が、同じ値で不正値となるのは、あまりにも考えにくいです。

 全く不可思議という他ありません。