
微信 4.x はローカルのチャットデータベースを SQLCipher の中にロックしました。プログラムでチャット記録、画像、音声を読ませたいなら、避けて通れないことがあります。まず復号用の key を手に入れることです。
「key を取ってからデータベースを読む」ということをめぐって、コミュニティには成熟した二つの道があります。一つは wechat-use——macOS 上でメッセージ送信 + データベース読み取り + リアルタイム監視を行うあの一式です。もう一つはオープンソースの wechat-decrypt——クロスプラットフォームの復号 + 一括エクスポート + 音声テキスト変換 + ネイティブ MCP です。
この二つはよく比較されますが、比較の方向がずれています。本当の違いは「どちらの機能が多いか」ではなく、その key をどう取得するか、そして取得したあとに何ができるかにあります。この記事では両者を原理レベルまで分解します。書き終えたあと、自分のマシンで wechat-use を実際に走らせてみました——その結果、自分の二つの誤判定を訂正することになりました。後ほど説明します。
まず暗号化モデルをきっちり説明する
WeChat 4.x のローカル DB は標準の SQLCipher 4 で暗号化された SQLite で、場所はここです:
macOS: ~/Library/Containers/com.tencent.xinWeChat/Data/Documents/xwechat_files/<wxid>/db_storage

SQLCipher の鍵モデルには、先に理解しておくべきポイントが三つあります。ここを押さえないと、この後二つのツールが何をこじ開けているのか分かりません:
- 1 DB 1 key。 グローバルな鍵が一本あるわけではありません。
contact.db、message_*.db、sns.db…それぞれの DB が自分専用の 32 バイト raw key を持っています。私のマシンでwechat-useが保存した~/.wx-rs/keys.jsonを見ると、ちょうど 19 個の per-DB エントリがあり、各行は{key_hex: 64 文字, salt_hex: 32 文字}でした。 - salt はファイルヘッダーに隠れている。 各暗号化 DB ファイルの先頭 16 バイトはランダム salt です。暗号化された SQLite を開いても
SQLite format 3で始まらないのはそのためです——その 16 バイトが salt に占有されています。wechat-decryptの C コードにもmemcmp(header, "SQLite format 3", 15) == 0 → return -1という一文があります。平文 DB に当たったらスキップするわけです。 - raw key はメモリ内にしかない。 32 バイトの raw key はディスクには落ちません。WeChat 実行時にだけ派生され、プロセスのメモリ内に保持されます。形式は
x'<64桁 key hex><32桁 salt hex>'です(つまり SQLCipherPRAGMA keyの raw 形式で、96 個の 16 進文字)。
つまり一つの DB を復号するには、二つをそろえる必要があります: raw key(プロセスメモリから抜き出す)+ salt(DB ファイルヘッダー先頭 16 バイトから読む)。wechat-decrypt の find_all_keys_macos.c にある HEX_PATTERN_LEN 96、key_hex[65]、salt_hex[33] という定数は、まさにこのモデルに対応しています。
「salt はファイルヘッダーにある」というのは私の当てずっぽうではありません。hexdump 一回で検証できます。 私のマシンの contact.db の先頭 16 バイトはこうでした:
$ xxd -l 16 contact/contact.db
00000000: 90f7 c71d 17b5 bfe6 24b1 76ac df40 df7f
平文 SQLite なら 53 51 4c 69 74 65 …("SQLite format 3\000")で始まるはずです。ここではランダムなバイト列になっています——この 16 バイトこそ salt で、暗号化によってファイルヘッダーが置き換わっています。wechat-decrypt が「すでに平文 DB かどうか」を判断するのに使っているのも、この memcmp(header, "SQLite format 3", 15) です。
1 アカウントにつき一式の DB があり、単一ファイルではありません。 WeChat は用途ごとに 20 個近い暗号化 DB に分割しており、それぞれ別々の key を持っています。私のマシンの ~/.wx-rs/keys.json には 19 件あり、対応関係は次の通りです:
| DB | 入っているもの |
|---|---|
message/message_0.db、message_1.db | チャット本文(容量に応じた分割) |
message/message_fts.db | チャット全文検索インデックス |
message/media_0.db、message_resource.db | メッセージ内のメディア/リソース |
message/biz_message_0.db | 公式アカウント/サービスアカウントのメッセージ |
session/session.db | 会話リスト(左側のあの欄) |
contact/contact.db、contact_fts.db | 連絡先 + 連絡先検索 |
sns/sns.db | モーメンツ |
favorite/favorite.db、favorite_fts.db | お気に入り |
emoticon/emoticon.db / head_image/head_image.db | スタンプ / アバター |
hardlink/hardlink.db | ファイルのハードリンクインデックス |
bizchat、general、solitaire、weclaw | 企業アカウント会話 / 汎用設定 / 接龍 / など |
難しいのは復号そのものではありません——SQLCipher 標準ライブラリは、正しい key を渡せば開けます——難しいのは、その key をメモリから抜き出すことです。 二つのツールの本当の差が出るのは、まさにこのステップです。
原理の核心:メモリから key をこじ開ける二つのルート

WeChat プロセスのメモリを読むには、macOS 側に一つ壁があります。WeChat は hardened runtime 付きで署名されており、システムはデフォルトで他のプロセスが task_for_pid で attach することを許しません——たとえ root でも。二つのツールがこの壁を越える方法こそが最大の違いであり、私がこの記事の修正でいちばん無様に迷走した部分でもあります(下で、どう二回間違えたかを書きます)。
ルート A:wechat-decrypt —— replace-mode 再署名 + sudo メモリスキャン
sudo codesign --force --deep --sign - /Applications/WeChat.app # ① replace-mode で ad-hoc に再署名
cc -O2 -o find_all_keys_macos find_all_keys_macos.c -framework Foundation
sudo ./find_all_keys_macos # ② root でメモリスキャン
codesign --force --deep --sign - は replace-mode(置換式) の再署名です。WeChat 全体を ad-hoc 署名に変更し、hardened runtime だけでなく WeChat 自身の entitlements もまとめて消し去り、その後 root 権限で mach_vm_read を使ってメモリをブロック単位(1 ブロック 2MB)でスキャンし、96 桁 hex の key+salt パターンを正規表現で探し、ヒットしたものを all_keys.json に書き込みます。salt は別途 DB ファイルヘッダから読みます。考え方は単純明快で、リバースエンジニアリング界隈では標準的なやり方であり、完全にオープンソースで監査可能です。代償は、root が必要なこと、そして置換式の再署名によって WeChat の元の権限まで一緒に消してしまうことです(極端なケースでは WeChat 自身の TCC に影響する可能性があります)。
ルート B:wechat-use —— key 読み取りは再署名なし(ログイン瞬間のデバッグインターフェース)
ここは私が最初にいちばんねじれて理解していたところなので、二層に分けて説明します。
key の読み取り(init)自体は再署名も sudo も不要です。 これは WeChat にログインするその瞬間に、macOS の公開デバッグインターフェースを使って復号材料を一度だけ取得し、取得後すぐ detach します——codesign --force --deep はせず、root も使いません。ルート A とは完全に別物です。ルート A は、先に置換式で再署名してから root で力ずくのメモリスキャンをします。
メッセージ送信が必要な場合だけ再署名が必要で、しかも merge-mode です。 送信用の slot_send アダプタには WeChat の get-task-allow=true が必要で、そのために一度 merge-mode(合併式) の再署名を走らせます——追加する entitlement は get-task-allow ただ一つで、WeChat が元から持つすべての権限は保持します(SKILL では replace-mode を使うなと明確に警告しています。なぜなら、それを使うと WeChat の TCC 権限が消えるからです)。ここがルート A より抑制的な点です。同じく署名を触るにしても、こちらは外科手術的な合併であって、一刀両断の置換ではありません。
私のローカルでの wechat-use doctor の出力です。
✓ wechat_get_task_allow get-task-allow = true (LLDB が attach 可能)
✓ wechat_codesigned signer: ad-hoc (ローカル再署名済み、get-task-allow 含む)
✓ wechat_dylib_fingerprint SHA-256=fc162db6… raw_key ✓ (keymap)
✓ wechat_update_guard ✓ disabled (Tencent が MacUpdate に書き込めない)
ここで罠にはまらないよう注意してください(私ははまりました)。ここに「ローカル再署名済み」と表示されているのは、このマシンでは送信機能を設定済みで、その merge-mode 再署名を実行したことがあるからです。これは key 読み取りの必須条件ではありません——読み取りだけで送信しないなら、init のログイン瞬間インターフェースだけで十分です。もう二つ細かい点があります。wechat_dylib_fingerprint は、WeChat の dylib フィンガープリントに応じて keymap を選び raw key の位置を特定していることを示します(固定 pattern を力ずくでスキャンするよりアップグレード耐性があります)。wechat_update_guard: disabled は、MacUpdate ディレクトリを書き込み不能にして、再署名がアップデートで上書きされないようにしていることを示します。
key 抜き出しを一言で比較すると、wechat-decrypt の key 読み取り = replace-mode 再署名 + root でメモリ総当たりスキャン;wechat-use の key 読み取り = ログイン瞬間のデバッグインターフェース、再署名なし・sudo なし(メッセージ送信時だけ別途 merge-mode 再署名) です。key 読み取りというステップでは、wechat-use のほうが明らかに軽く、抑制的です。一方で wechat-decrypt は粗いものの、完全オープンソースで、クロスプラットフォームに一貫しています。
真似する価値のある工夫:画像 key はメモリスキャンしない
wechat-decrypt には、なかなか賢い細部があります。画像の key はプロセスメモリから取らず、ディスク上の kvcomm キャッシュから派生します(find_image_key_macos.py)。WeChat は画像 .dat の key をディスクキャッシュに残しているため、画像を復号するだけならプロセスに attach する必要も、root も不要です。自分で画像復号を作るなら、このルートはクリーンなので、そのまま真似できます。
復号そのもの:両者はまったく同じ、手動でも数行
raw key を抜き出し、ファイルヘッダの salt と組み合わせれば、その後に謎はありません——どちらも標準 SQLCipher 4 です。key を手に入れた後、手動で DB を一つ復号するなら、たったこれだけです(key は伏せ字)。
$ sqlcipher contact/contact.db
sqlite> PRAGMA key = "x'<64桁 key hex…>'"; -- メモリから抜いた raw key
sqlite> PRAGMA cipher_compatibility = 4; -- SQLCipher 4 を指定
sqlite> .tables -- テーブルが列挙できれば復号成功
key が正しければ、.tables で連絡先テーブルが表示されます。key が間違っていれば、即座に file is not a database と出ます。salt を手動で渡す必要はありません——ファイルヘッダ先頭 16 バイトにあり、SQLCipher が自分で読みます。二つのツールがやっているのは、この数行の自動化です。前段の再署名 / attach / メモリスキャンといったすべての労力は、あの x'…' を手に入れるためだけにあります。どちらにも独自の復号アルゴリズムなどありません。「どちらの復号が強いか」は偽の問いであり、違いはすべて前段の key 抜き出しにあります。
データベース取得後:能力は分岐する

key の抽出は入場券であり、手に入れた後、二つのツールは別々の方向へ進みます。この表は、私が実測して訂正した後の版です(バツが付いている箇所は、第一版で書き間違えたところです)。
| 観点 | wechat-use | wechat-decrypt |
|---|---|---|
| メッセージ送信 | バックグラウンドで UI の点滅なし、配信状態付き | 送信不可、読み取り専用 |
| DB 読み取り(会話 / 連絡先 / 履歴 / 画像) | 対応(手元の実測では sessions が正常に返る) | 全量を平文 SQLite に復号 |
| 音声文字起こし | ✅ 対応(v1.17: silk-decoder + whisper-cli + ggml-medium) | ✅ SILK→WAV→テキスト |
| key 抽出方式(macOS) | key 読み取り:ログイン直後のデバッグインターフェイス、再署名なし・sudo なし(メッセージ送信時のみ別途 merge-mode 再署名) | replace-mode 再署名 + sudo mach_vm ハードスキャン |
| アップグレード追従 | dylib フィンガープリント keymap + probe-build による自適応 | 固定メモリ pattern、作者の更新待ち |
| プラットフォーム | macOS のみ | Win / Mac / Linux |
| 企業微信 | なし | 5.x は Windows のみ実測 |
| Claude 用(MCP) | HTTP/gRPC 経由、自分でラップが必要 | ネイティブ MCP、1 行で接続、20+ ツール |
| リアルタイム監視 | daemon RPC → SSE | Web UI SSE / CLI / MCP |
| リモート接続 | Cloudflare Tunnel で REST を公開 | 基本はローカル |
| コスト | 有料アクティベーションコード | 無料・オープンソース |
ここにこそ実測の価値があり、しかも私は一度ならず間違えました。 第一版ではドキュメントを読んだだけで「wechat-use は再署名せず、音声文字起こしもしない」と書きました。実際に動かすと doctor に「ローカル再署名」と表示されたため、間違いを見つけたと思い、「両方とも再署名しないと読めない」と直しました——しかし結果的に行き過ぎた訂正でした。その時の再署名はメッセージ送信用の設定であり、key 読み取り自体は再署名しません。SKILL 全体とソースコードを読んで、ようやく正確につながりました。key 読み取りは再署名なし、メッセージ送信時だけ merge-mode 再署名。文字起こしは v1.17 の時点で元からあります。 ドキュメント読みで一度間違え、半端な証拠を見てまた間違え、ツールを動かし切り、ドキュメントとソースを読み切って、ようやく結論を出せました。
この表を一言で読むなら、こうです。wechat-use は「送信 + 読み取り + 文字起こし + リアルタイム」の万能 bot プラットフォーム(有料・クローズドソース・macOS のみ)であり、wechat-decrypt は「復号 + エクスポート + 文字起こし + ネイティブ MCP」のオープンソースデータツール(無料・クロスプラットフォーム・企業微信あり、ただしメッセージ送信不可)です。
それぞれの workflow
wechat-use(送信 + 読み取り + リアルタイム)
① TG チャンネルを購読してアクティベーションコードを取得
② wechat-use init # ログイン瞬間にデバッグインターフェースで key を抜く。再署名なし、sudo なし(送信時だけ別途 merge-mode 再署名)。daemon は必要時に起動
├─ 読み取り: wechat-use sessions / history / contacts / search / image (YAML、低 token)
├─ 送信: wechat-use send "テキスト" <名前またはwxid> (バックグラウンドでゼロ点滅)
└─ リアルタイム: wechat-use listen または wechat-bridge → HTTP /messages/stream?since=
③ リモート: wechat-use tunnel setup → Cloudflare Tunnel で REST を公開
④ アップグレード: wechat-use probe-build → 新 build に適配
wechat-decrypt(復号 + エクスポート + MCP、macOS)
① python venv + pip install -r requirements.txt + brew install whisper-cpp
② WeChat を終了 → sudo codesign で再署名 → cc でコンパイル → sudo ./find_all_keys_macos # root でメモリをスキャンして key を抜く
③ python decrypt_db.py # 全量復号 → 平文 SQLite(-i で増分)
├─ エクスポート: python export_all_chats.py -t # JSON/CSV/HTML + 音声文字起こし + 増分/日付ウィンドウ
├─ リアルタイム: python main.py # Web UI localhost:5678 (SSE)
└─ Claude へ: claude mcp add wechat -- python mcp_server.py # 20+ 個の検索ツール
mcp_server.py は 1 行で Claude に接続でき、get_chat_history / search_messages / decode_voice で直接検索できます。モーメンツなどの XML を解析する際には XXE 防護(DOCTYPE/ENTITY の拒否 + サイズ上限)も入っており、この点は多くの同類より厳密です。
組み合わせる(実際の場面:agent を WeChat に接続)
メッセージ送信 / リアルタイム応答 / グループ @ bot ──────────→ wechat-use (成熟、実運用済み)
履歴の一括取得 / 企業微信 / Claude でネイティブ検索 ──→ wechat-decrypt MCP (MCP + クロスプラットフォームを補完)
両者は競合しませんが、同時に走らせないでください——どちらも WeChat に attach し、署名と DB を触るため、1 台のマシンで 2 つ同時に上げると、署名と attach が衝突します。
見落とされがちな 2 つの点
音声をどうテキスト化するかは、どちらも同じです。 WeChat の音声は mp3 ではなく、SILK(Skype がオープンソース化した狭帯域音声 codec)です。そのため、テキスト化は 3 段のパイプラインになります:SILK → WAV にデコード → whisper に渡して文字起こし。wechat-decrypt は silk decoder + whisper.cpp/OpenAI を内蔵しています。wechat-use v1.17 も silk-decoder + whisper-cli + ggml-medium を同梱しており、グループ履歴を読む際に音声を自動で文字起こしします。この流れは、TTS の歓迎メッセージとはちょうど逆です——あちらはテキスト→音声、こちらは音声→テキストですが、どちらも whisper に依存しています。
個人 WeChat と企業微信は同じ鍵ではありません。 個人 WeChat 4.x は SQLCipher 4(前述の仕組み:ファイルヘッダーの salt + メモリ上の raw key)を使います。企業微信 5.x は別物で、wxSQLite3 の AES-128 です。暗号化パラメータも key の位置も異なるため、wechat-decrypt は find_wxwork_keys.py を別途用意しており、しかも実測済みなのは Windows のみです。wechat-use はそもそも企業微信には触れません。企業微信を復号したい場合、現時点では wechat-decrypt + Windows という選択肢しかありません。
リスクと境界(これは復号ツールなので、明確にしておくべきこと)
- どちらも WeChat の署名を変更する可能性がありますが、方法とタイミングが異なります。
wechat-decryptは key を読むために replace-mode で再署名(WeChat 既存の権限をまとめて消す)+ root を行います。wechat-useは key の読み取りでは再署名せず、メッセージ送信時だけ merge-mode でget-task-allowを追加(既存の権限は保持)し、それを維持するために自動更新を能動的に無効化します。いずれにせよ、ad-hoc 再署名によって WeChat は公式署名からローカル署名に変わるため、理論上は検出されたり、Gatekeeper の警告が出たりする可能性があります。手を動かす前に、自分が何を変更しているのか理解しておきましょう。 - 自分のアカウント、自分のデータだけを復号してください。 この種のツールの正当な用途は、自分のチャットをエクスポート/バックアップすることであり、他人のものを読むことではありません。
- key とチャット内容を外部に漏らさないでください。 raw key が一度漏れれば、誰でもあなたのデータベースを復号できます。この記事内の実際の key やチャット内容はすべてマスキングしています——この種の記事を書いたり、ログを貼ったりするときは、必ずそうするべきです。
- Developer Mode / attach 権限が必要です。
wechat-useには macOS Developer Mode +get-task-allowが必要で、wechat-decryptには root が必要です。どちらも「任意のプロセスのメモリを読める」レベルの権限なので、付与する前によく考えてください。
では、彼の実装は私たちのものより優れているのか
分けて見ると:
- key を抜く手法:
wechat-useのほうが軽く、控えめです。 key を読むだけならそもそも再署名しません(ログイン直後にデバッグインターフェースを呼ぶだけで、sudoも不要)。メッセージ送信が必要なときだけ merge-mode で再署名します(get-task-allowを追加するだけで、WeChat の元の権限は保持)。一方wechat-decryptは key を読むだけでも replace-mode で再署名 + root で力技スキャンが必要で、より荒く、WeChat の既存権限まで一緒に消してしまいます。ただし、完全にオープンソースで、監査可能で、クロスプラットフォームで一式そろっています。 - 復号自体:同じです。 どちらも標準の SQLCipher 4 で、誰かが黒魔術を持っているわけではありません。
- 機能範囲:それぞれ得意分野があります。
wechat-useは「メッセージ送信」を独占し、wechat-decryptは「ネイティブ MCP + クロスプラットフォーム + 企業 WeChat」を独占しています。音声文字起こしは両方にあります(この点は最初、私が勘違いしていました)。
正確に言えば、これは「どちらの実装が優れているか」ではなく、2つの路線です。 key 抽出のスマートさと「メッセージを送れる」点では wechat-use の勝ち。オープンソース、無料、クロスプラットフォーム、ネイティブ MCP では wechat-decrypt の勝ちです。
選定結論
- メッセージを送るなら、
wechat-useは不可欠です。wechat-decryptはそもそも送信できないので、代替にはなりません。 wechat-decryptを導入する価値は、補完する2点にあります。 無料のネイティブ MCP(Claude から1行で接続し、チャット履歴を直接検索できること)、そしてクロスプラットフォーム + 企業 WeChat 対応です。音声文字起こしは、もはや独自の売りではありません——両方にあります。- 実運用では、
wechat-useは引き続き送信 + リアルタイム + DB 読み取りの主力として使い、「Claude からネイティブに WeChat データを検索したい」または「企業 WeChat を読む / Linux で動かす」必要があるときに、wechat-decryptの MCP を追加導入するのがよいです。同じマシンで2セットを同時に起動しないこと。
技術的には、相手側から2つ真似できます。画像 key をディスク上の kvcomm キャッシュから派生すること(プロセスに attach しなくてよい)、そして x'key+salt' という 96-hex のメモリ形式を keymap と組み合わせて位置特定すること(pattern を力技でスキャンするよりアップグレードに強い)。いつか自前実装や強化をするなら、この2つの trick はそのまま使えます。
最後に方法論を一言。この文章で最も価値があるのは、あの比較表ではなく、私が2回間違えた過程です——ドキュメントを読んで一度書き間違え、doctor の再署名という半分の証拠を見てまた反対方向に行きすぎ、ツールを最後まで走らせ、SKILL とソースコードを読み切って、ようやく結論を出せました。比較を書くときに一番危ないのは、読んでいないことではなく、半分だけ読んで書き始めることです——そして誤解の源は、まさにツール自身のドキュメントにあった、「key を読む」と「メッセージを送る」を区別していない no re-signing という一文でした。

微信
支付宝
コメント
コメントは即時公開されますが、ポリシー違反時は非表示になる場合があります。