ByteScope

OLE2 / CFB ファイル形式

Compound File Binary 形式 — .doc/.xls/.ppt と .msi インストーラーの土台となる旧来のコンテナ。

MIME タイプ
application/x-ole-storage
拡張子
.doc, .xls, .ppt, .msi
カテゴリ
ドキュメント

マジックナンバー(ファイル署名)

0x00000000D0CF11E0A1B11AE1········CFB / 'docfile' magic

OLE2 / CFB 形式について

Compound File Binary 形式は、1 つのファイルに丸ごと収まったファイルシステムです。セクタがあり、アロケーションテーブルがあり、名前付きストリームのディレクトリツリーがあり、小さなストリーム専用の 2 つ目のアロケーション方式まであります。保存のたびに文書全体を書き直さずに、独立した部品をいくつも 1 ファイルに収められるよう Microsoft が作ったもので、Word 97 の文書から Windows Installer のパッケージ、Outlook の .msg まで今もこれに乗っています。読むにはバイトを前方に走査するのではなくセクタ番号の鎖をたどることになり、テキストが無圧縮で入っているのに .doc の hex ダンプがノイズにしか見えないのはそのためです。

ヘッダーの構造(バイト単位)

オフセット長さフィールド意味
08Header signature常に D0 CF 11 E0 A1 B1 1A E1。先頭 4 バイトは狙ったダジャレで、D0CF11E は leetspeak で 'docfile' と読めます。拡張子については何も示唆しません。.doc も .xls も .ppt も .msi も .msg も、この同じ 8 バイトで始まります。
816Header CLSID予約されたクラス識別子で、仕様はすべてゼロであることを要求しています。ここが非ゼロなら、正当な派生というより手作りか意図的に壊されたファイルの兆候です。
242Minor versionリトルエンディアンで、実際に出回っているファイルではほぼ 0x003E です。機能上の影響はなく、読む側は無視します。
262Major version0x0003 か 0x0004 で、こちらは重要です。バージョン 3 はセクタ 512 バイトでストリームサイズは 32 ビット、バージョン 4 はセクタ 4096 バイトでストリームが 4 GiB を超えられます。Office 文書はほぼすべてバージョン 3 です。
282Byte order markFE FF、つまりリトルエンディアン。ビッグエンディアンは結局仕様化されなかったので実質は定数であり、ファイルがずれているのではと疑ったときの 2 つ目の健全性チェックとして使えます。
302Sector shiftセクタサイズの 2 を底とする対数です。メジャーバージョン 3 の 512 バイトセクタなら 0x0009、バージョン 4 の 4096 バイトセクタなら 0x000C。セクタ N はバイトオフセット (N + 1) × セクタサイズから始まります。セクタ番号が 512 バイトのヘッダの後ろから数え始めるためです。
322Mini sector shiftミニセクタサイズの 2 を底とする対数で、0x0006(64 バイト)と定められています。ミニストリームがあるおかげで、小さなプロパティストリームを何百も持つファイルが 1 つあたり 0.5 KB も無駄にせずに済みます。
346Reservedゼロを書き、読む側は無視すべき 6 バイト。後続のフィールドを 4 バイト境界に揃えるためだけに存在します。
404Number of directory sectorsディレクトリエントリを保持するセクタの数です。バージョン 3 のファイルはここにゼロを書き、代わりにアロケーションテーブル経由でディレクトリの鎖をたどらなければなりません。この値を使うのはバージョン 4 だけです。
444Number of FAT sectorsfile allocation table に割り当てられたセクタの数。FAT セクタ 1 つはセクタサイズ ÷ 4 個の次セクタポインタを持つので、512 バイトセクタなら 128 セクタ分を写像し、テーブルは文書の大きさに比例して伸びます。
484First directory sectorディレクトリの鎖が始まるセクタ番号。最初のディレクトリエントリは必ずルートで、名前は UTF-16 の 'Root Entry'、その子ツリーがファイル内のすべてのストリームに名前を与えています。中に実際に何が入っているかを知りたいなら、たどるべきフィールドはここ 1 つです。
524Transaction signatureトランザクション保存に対応した実装が増やす値で、それ以外ではゼロです。実務上は、どのアプリが書いたファイルかを見分ける指紋として役に立ちます。
564Mini stream cutoff size0x00001000(4096)と定められています。これより短いストリームは mini FAT 経由でミニストリームに格納され、これ以上なら専用のセクタを丸ごともらいます。1 つのファイルの中に 2 系統のアロケーション経路があり、その分岐をこの数値 1 つが決めています。
604First mini FAT sectorミニアロケーションテーブルの先頭。小さなストリームがまったく無い文書では、鎖の終端マーカー FFFFFFFE が入ります。
644Number of mini FAT sectorsその鎖のセクタ数での長さ。大きなストリームだけでできた文書ならゼロが普通です。
684First DIFAT sectorヘッダ内の 109 個の枠を使い切ったあと、二重間接アロケーションテーブルがどこへ続くか。FFFFFFFE なら続かなかったということで、512 バイトセクタでおよそ 7 MB 未満のファイルはすべてこれに当たります。
724Number of DIFAT sectorsその継続の鎖の長さ。DIFAT では位置がそのまま意味を持ちます。i 番目の枠は FAT インデックスの決まったブロックを担当するので、読めない枠をプレースホルダで埋めずに飛ばしてしまう読み手は、それ以降のセクタ番号を全部黙って読み違えます。
76436DIFAT array最初の 109 個の FAT セクタを指す 4 バイトのセクタ番号が 109 個並び、ヘッダをちょうど 512 バイトに埋めます。未使用の枠は FFFFFFFF です。小さな compound file が DIFAT セクタを持たずに済むのはこのためで、ヘッダだけですべてを写像できています。

似た形式との見分け方

紛らわしい形式見分け方
Word 文書(docx)Office の世代の分かれ目です。同じ「documents」フォルダに並んでいて、どちらも Word で開きますが、2007 年より前の .doc は D0 CF 11 E0、.docx は 50 4B 03 04 です。拡張子は証拠になりません。Office は旧形式のファイルを平気で .docx という名前で保存しますし、その逆もあり、開くときはバイトを見ています。オフセット 0 を読んでください。
doc/xls/ppt/msi4 つとも同じ 8 バイトのマジックナンバーを共有していて、ヘッダからは一切区別できません。コンテナは中身について何も語らないのです。答えはオフセット 48 からたどるディレクトリツリーにあります。'WordDocument' というストリームがあれば .doc、'Workbook'(古くは 'Book')なら .xls、'PowerPoint Document' なら .ppt、base64 めいた読めない名前のストリーム群なら Windows Installer のパッケージです。
msgOutlook の .msg も compound file で、マジックナンバーも同じなので、判定器は OLE2 と答えてそこで止まります。正体を示すのは、プロパティタグと型が続く __substg1.0_ という名前のストリームで埋まったディレクトリと、__properties_version1.0 の存在です。文書のレイアウトではなく MAPI のプロパティ格納レイアウトということです。
SQLite データベース「1 ファイルに丸ごとファイルシステム」という形式として実際に出会う 2 つなので、並べておく価値があります。SQLite は ASCII 文字列 'SQLite format 3' と NUL で始まり、CFB は D0 CF 11 E0 で始まります。どちらも固定サイズのページとフリーリストを使いますが、SQLite の形式は公開・版管理され、余すところなく文書化されています。一方 CFB は、Microsoft が公開するまでの 10 年間リバースエンジニアリングの対象でした。

よくある壊れ方

  • FAT の鎖の断裂。ストリームは連続した領域ではなくセクタ番号の連結リストなので、アロケーションテーブルの 1 エントリが壊れてもストリームは途中で終わりません。よその領域へ迷い込むのです。文書は開き、途中の段落が別の段落になっていたりバイナリのゴミになっていたりします。しかもそれに気づけるチェックサムはどこにもありません。
  • 途中切れ。512 バイトのヘッダは残るので、どのツールもファイルを正しく識別し、バージョンとセクタサイズまで報告します。そのうえで展開に失敗します。オフセット 48 が指すディレクトリセクタがファイルの末尾より先にあるからです。CFB にはトレーラーが無いので、PNG や ZIP のような安上がりな末尾チェックが存在しません。
  • DIFAT のループ。二重間接テーブルのセクタ番号は検証されないので、壊れたファイルは鎖を自分自身へ向けられます。素朴なパーサーは永遠にたどり続けます。compound file のリーダーにおける典型的なサービス拒否の形で、防ぎ方はオフセット 44 や 72 の宣言値を信じることではなく、ファイルサイズから見て存在し得るセクタ数で走査に上限を課すことです。
  • テキストモード転送。CFB のフィールドはすべてバイナリなので、ASCII モードの改行変換はセクタ境界をずらし、オフセット 24 から先のヘッダを壊します。オフセット 0 のマジックナンバーには 0D 0A が含まれておらず無傷で残るのが、まさに罠です。ファイルは依然 OLE2 と識別され、そして完全に読めません。
  • バージョン 4 のファイルをバージョン 3 として読む。オフセット 26 のメジャーバージョンがセクタを 512 バイトとみなすか 4096 バイトとみなすかを決めます。これを無視するとセクタのオフセットが 8 倍ずれ、綺麗に失敗する代わりに、それらしく見えて完全に位置のずれたデータが出てきます。

この形式の現在地

OLE2 は死にきれないレガシーコンテナです。乗っているものが多すぎるからです。Office は 2007 年に ZIP + XML の形式へ移り、それ以前の文書はもう本当に古いのですが、それでも compound file が日々流通し続ける理由が 3 つあります。1 つは Windows Installer のパッケージで、今も CFB のままであり、今も Windows のソフトはこれで配られます。2 つ目は Outlook の .msg で、「このメールを保存」ボタンが吐き出すのはこれです。3 つ目は法務・行政・企業の文書倉庫に眠る膨大な .doc と .xls で、誰も変換する気はありません。セキュリティ上の面倒の種でもあり続けています。古い .doc のマクロと、形式自体の複雑さのせいで、compound file は 20 年にわたりマルウェアの定番の乗り物でした。メールゲートウェイが拡張子を問わず D0 CF 11 E0 を怪しむのはこのためです。新規に作る理由はもう何も残っていません。OOXML は ZIP なので普通のツールで中を覗け、圧縮も遥かに効き、公開された標準です。一方 CFB の仕様が [MS-CFB] として公開されたのは、世間がとっくにリバースエンジニアリングし終えた後でした。

OLE2 / CFB ファイルをこのサイトで開く

どれもブラウザ内で動きます。ファイルが端末から出ることはありません。

関連する形式

OLE2 / CFB と混同しやすい形式です。先頭バイトを見比べてください。

形式先頭バイト拡張子
Word 文書(docx)50 4B 03 04.docx
Excel ブック(xlsx)50 4B 03 04.xlsx
PowerPoint プレゼン(pptx)50 4B 03 04.pptx
PDF25 50 44 46 2D.pdf

よくある質問

ファイルのマジックナンバーとは何ですか?

ファイル先頭の数バイトで、名前が何であろうとその形式を示すものです。PNG は必ず 89 50 4E 47 で始まり、ZIP は 50 4B 03 04 で始まります。OS もブラウザも file コマンドも、拡張子を信用せずこのバイト列を読みます。だからファイル名を変えても中身の正体は変わりません。

マジックナンバーを自分で確認する方法は?

macOS や Linux なら xxd -l 16 ファイル名 で先頭 16 バイトが表示されます。Windows なら PowerShell で Format-Hex -Path ファイル名 -Count 16 です。あるいはこのサイトのファイル形式判別ツールにドロップすれば、ローカルでバイト列を読んで形式を教えてくれます。アップロードはありません。

2 つの形式が同じマジックナンバーを持つのはなぜ?

一方が他方の上に作られているからです。docx、xlsx、pptx、apk、jar、epub はすべて中身が ZIP アーカイブなので ZIP の署名で始まり、区別するには内部のエントリを見る必要があります。Java の class ファイルと macOS のユニバーサルバイナリはどちらも CA FE BA BE で始まり、直後のフィールドで見分けます。

マジックナンバーがまったくないファイルもある?

あります。XML、HTML、JSON、SVG、CSV といったテキストベースの形式には固定のバイト署名がないため、構造から判別します。先頭の <?xml 宣言、<svg 要素、あるいは { に続く引用符付きのキーなどです。これは確定ではなく推測なので、このリファレンスではそうした形式をプローブ判別として示しています。

マジックナンバーが一致すればそのファイルは安全?

いいえ。わかるのは形式であって、中身が無害かどうかではありません。正規の PDF や docx でも悪意のあるペイロードを含んでいることがあります。特に拡張子とバイト列が食い違うときに真の形式を知るのは有用な第一段階ですが、マルウェアスキャンではありません。

OLE2 / CFB かもしれないファイルをお持ちですか?ファイル形式判別ツールで調べる — マジックナンバーをローカルで読み取ります。アップロードは一切ありません。またはすべての形式を見る。