今すぐ修復
- ファイルをドロップ
- 修復はローカルで実行
- 結果をダウンロード
WhatsApp(Android版)はすべての会話をmsgstore.dbという単一のSQLiteデータベースに保存します — メッセージの本文、タイムスタンプ、チャットや連絡先への参照が、すべてこの中にあります。アプリの突然終了、端末からファイルを取り出す途中で中断されたコピー、あるいは中途半端に終わった同期がこれを壊すと、WhatsAppも他のあらゆるSQLiteツールも、ファイル全体を "database disk image is malformed"(ディスク上のデータベースイメージが不正です)として拒否します。すでに復号済みのmsgstore.dbを上にドロップすれば、ツールがそのページをローカルに走査し、スキーマを組み直し、まだデコードできる行をすべて、新しく開けるデータベースへ再挿入します — あなたのメッセージ履歴すべてを保持するチャットのデータベースが、アップロードされることは一切ありません。
msgstore.dbの中身 — ページ、テーブル、そして -wal サイドカー
WhatsAppのデータベースはごく普通のSQLiteファイルなので、固定サイズのページが並んだフラットな配列です(SQLiteの既定値はたいてい4 KB)。先頭16バイトはマジック文字列SQLite format 3\0で、ページ 1の残りにはファイルヘッダーと、すべてのテーブルを列挙するsqlite_schemaが入っています。各テーブルはb-tree(Bツリー)です。内部ページは葉ページへ下っていくポインタを持ち、葉ページに実際の行が格納されています。
チャット履歴にとって重要なテーブルは決まっています。最近のWhatsAppはメッセージをmessageテーブル(古いバージョンではmessages)に、会話リストをchatに、電話番号やグループの識別子をjidに保存します。メッセージの本文はテキスト列(新しいスキーマではtext_data、古いスキーマではdata)にあり、各行にはUnixエポックのミリ秒単位のタイムスタンプが付いています。message_media、message_thumbnail、message_quoted、call_logといった補助テーブルが残りを補います。そして肝心なのは、写真・動画・ボイスメモそのものはデータベースの中には入っていないという点です — それらはWhatsAppのMediaフォルダにある別々のファイルで、データベースはそのファイルパスと小さなサムネイルだけを保持しています。
WhatsAppはこのデータベースをWAL(ライトアヘッドログ)モードで動かしているので、端末上ではその隣に2つの兄弟ファイルが見えます。msgstore.db-walとmsgstore.db-shmです。最近コミットされたメッセージは、メインの.dbへチェックポイントされるまで-walファイルの中だけに存在していることがあります。このサイドカーがあるなら、必ず取っておいてください — そのコミット済みフレームこそが、いちばん新しい行だからです。
なぜ "malformed" と出るのか — そして .crypt の罠
SQLiteは、ポインタをたどった先が有効なb-treeページでないもの — ゼロで埋まったページ、不正なセルオフセット、ファイルサイズと食い違うページ数 — に行き着いた瞬間に、SQLITE_CORRUPT(結果コード11)を投げます。これが"database disk image is malformed"(ディスク上のデータベースイメージが不正です)として表に出るのです。SQLiteは最初の不整合で止まります。だからこそ、内部ページが1つ壊れただけでファイル全体が倒れる一方で、その先にある無傷の葉ページにはあなたのメッセージがまだ残っているのです。近い仲間のエラー"file is not a database,"(ファイルがデータベースではありません)は、16バイトのヘッダーのマジックそのものが壊された、という意味で、その後ろのページは無事なことが多いです。
この破損はたいてい、書き込みの中断から生まれます。WhatsAppがまだファイルを開いたままの状態で、USB経由やファイルマネージャでmsgstore.dbを端末から取り出すと、チェックポイントが途中の、ちぎれたファイルをコピーしてしまうことがあります。故障しかけたSDカードや同期での1ビットの反転、あるいは書き込みの途中で電源を失った端末も、同じことを引き起こします。切り詰められた(truncated)コピーは、単純に末尾にあったページを丸ごと失います。
ほとんどの人が最初にはまる罠があります。WhatsAppのバックアップフォルダにあるファイルは、普通のデータベースではありません。バックアップはmsgstore.db.crypt14やmsgstore.db.crypt15という名前で、AES-GCMで暗号化されています(鍵は/data/data/com.whatsapp/files/keyにあり、crypt15の場合はあなたのエンドツーエンドのバックアップ用パスワードの背後にあります)。.crypt14/.crypt15ファイルは高エントロピーのノイズとして読み取られ — SQLiteのヘッダーがまったく無いので、普通のmsgstore.dbへ復号し直すまで、ページ復旧が手を付けることはできません。このツールは、暗号化されたバックアップではなく、すでに復号済みのデータベースを対象に動きます。
復旧で何が戻るのか — そしてチャットのDBを絶対にアップロードしない理由
壊れたポインタを信用する代わりに、ツールはファイルをページごとに読み取ります。スキーマを組み直し、各テーブルのb-treeを歩き、ポインタの連鎖ではもう届かないものについては、葉ページから自己記述型のレコードを直接デコードする、生ページの総なめ(raw page sweep)に切り替えます。見つけた行の周りにb-treeをゼロから組み直し、あなたがダウンロードする真新しいデータベースへ書き出します — SQLite自身の.recoverコマンドと同じ戦略です。既知のテーブルに割り当てられない行は、捨てずにlost_and_foundテーブルへ入れます。そしてmsgstore.db-walサイドカーを渡せば、そのコミット済みフレームが先に重ね合わされるので、結果は最後のチェックポイントではなく、あなたの最後にコミットされたメッセージを反映します。
正直な限界も述べます。物理的に上書きされた、あるいはファイル末尾から切り詰められたバイトは失われており、どんなツールもそれを作り出すことはできません。値はディスク上のストレージクラスのまま戻ってくるので、列のアフィニティ(型親和性)がずれることがあります。総なめはフリーリスト(freelist)や未圧縮(unvacuumed)のページも読むため、以前に削除されたメッセージが再び現れることもあります。復旧されたデータは常に疑わしいものです — SQLite自身のドキュメントがそう述べています — ので、頼りにする前に、信頼できる情報源と照らし合わせて検証してください。そしてメディアの本体は依然として別のMediaフォルダにあります。データベースが返してくれるのはテキストと参照であって、画像そのものではありません。
なぜこれをブラウザ内でやるのか?チャットのデータベースは、自分の管理下にないサーバーへ渡すには最悪のファイルです — あなたが今までにやり取りした、あらゆるメッセージ・電話番号・タイムスタンプを丸ごと含みうるからです。アップロード方式の「修復」ツールは、そのファイルを、あなたには中身を確かめられないインフラへ、あなたが書いたわけでもない保持期間の条件のもとでコピーします。ここではファイルはあなたのディスクから読み込まれ、あなたのタブの中で組み直されます。Networkパネル(ネットワーク)を開けば、データベースのバイトが1バイトもあなたの端末から出ていないことを確認できます。
修復できるものとできないもの
修復できる
- "Database disk image is malformed"(SQLITE_CORRUPT 11)— 壊れたページ、または壊れたb-treeポインタによるもの
- "File is not a database" — 16バイトのヘッダーのマジックだけが壊され、その後ろのページが無事な場合
- WhatsAppが開いたままの状態で端末からコピーしたために、ちぎれた、あるいはチェックポイントが途中のmsgstore.db
- 切り詰められたデータベース — 生き残ったページのメッセージ行をすべて取り出し、さらに渡された -wal サイドカーから未チェックポイント(未反映)の行も取り出します
- ポインタの連鎖がもう届かないページにある行 — 生ページの総なめでlost_and_foundへ復旧します
修復できない
- 鍵のない暗号化バックアップ .crypt14 / .crypt15 — SQLiteヘッダーを持たない暗号文なので、まず復号する必要があります
- 物理的に上書きされた、あるいはファイル末尾で切り詰められたメッセージ — そのバイトはもう存在しません
- 写真・動画・ボイスメモそのもの(Mediaフォルダにある別々のファイルであり、データベースの中にはありません)
- 復旧された各メッセージが完全である、あるいは正しいという保証 — 復旧データは信頼できる情報源と照合して検証してください
- 0バイトのファイル、またはヘッダーもページもすべてノイズのデータベース(それはまず、ストレージ復旧の問題です)
修復が失敗した場合、その理由(データの欠落か構造の破損か)をお伝えします。失敗した修復に料金が請求されることはありません。