本文へスキップ
郭立 (leeguoo)

WeChatを起動せずにメッセージを送受信する:独立した通信コアの復元記録

QRコード認証、通信および業務データの暗号化から、同期カーソル、メッセージトランザクション、アンインストール後の双方向検証まで、独立したWeChatテキスト通信コアを段階的に復元した過程を振り返ります。

このページの目次
1.一、{目標|もくひょう}:アプリから{何|なに}を{切|き}り{離|はな}すのか?2.二、まず三つを区別する:伝送、業務、保存3.三、プロセス:まずチャネルを{確立|かくりつ}し、その{後|あと}にアカウントを{扱|あつか}う4.1. {暗号化接続|あんごうかせつぞく}の{要点|ようてん}は、{相手|あいて}が{誰|だれ}であるかを{証明|しょうめい}すること5.2. QRコードはログインフローへの{入口|いりぐち}6.3. ログイン{内部|ないぶ}には、さらにもう一{段階|だんかい}の{鍵合意|かぎごうい}がある7.四、ログイン{後|ご}、なぜすぐに{通常|つうじょう}のメッセージ{受信|じゅしん}を{開始|かいし}できないのか?8.{同期|どうき}カーソルは「{最後|さいご}のメッセージ ID」ではない9.なぜメッセージとカーソルを{同時|どうじ}にコミットする{必要|ひつよう}があるのか?10.5. 1{件|けん}のテキストは、どのようにネットワークリクエストになるのか?11.{圧縮|あっしゅく}と{暗号化|あんごうか}の{順序|じゅんじょ}は{逆|ぎゃく}にできない12.そのまま{移植|いしょく}するのが{最|もっと}も{難|むずか}しいのは、プロトコル{固有|こゆう}の{計算|けいさん}ロジック13.6.{受信|じゅしん}は{逆方向|ぎゃくほうこう}のアンパックだが、{送信|そうしん}コードを{逆|ぎゃく}に{実行|じっこう}することではない14.メッセージの{受信|じゅしん}には{継続的|けいぞくてき}なポーリングが{必須|ひっす}なのか?15.七、デスクトップ版 WeChat から本当に{独立|どくりつ}していることを、どう{証明|しょうめい}するのか?16.八、なぜ{操作記録|そうさきろく}も{通信|つうしん}の{中核|ちゅうかく}に{含|ふく}まれるのか?17.九、{結論|けつろん}:{何|なに}ができ、{何|なに}がまだできていないのか?18.{復習|ふくしゅう}では、この7つの{問|と}いに{沿|そ}って{確認|かくにん}する

WeChatのチャット履歴りれきをツールに移行いこうすると、ごく自然しぜんに一つの疑問ぎもんが生うまれます。ツールはメッセージを読よみ取とり、画像がぞうを復号ふくごうできるのに、なぜ送信そうしんするときにはパソコン上じょうのWeChatに依存いぞんしなければならないのでしょうか。ネットワーククライアントを呼よび出だすように、自みずからログインし、リクエストを送信そうしんし、結果けっかを受信じゅしんすることはできないのでしょうか。

今回こんかいの調査ちょうさは、ここから始はじまりました。目標もくひょうを検証可能けんしょうかのうな範囲はんいに絞しぼりました。デスクトップ版ばんWeChatを起動きどうせず、QRコードによるログイン、初期化しょきか、テキストの送受信そうじゅしんを独立どくりつして完了かんりょうし、状態じょうたいを保存ほぞんする。最後さいごにツール専用せんようのWeChatを削除さくじょし、もう一度いちど双方向そうほうこうの送受信そうじゅしんを行おこなう。

現在げんざい、この一連いちれんの処理しょりは、自分じぶんのアカウントとファイル転送てんそうアシスタントを使つかった実機検証じっきけんしょうに成功せいこうしています。スマートフォンでは独立どくりつしたプログラムから送おくられた全文ぜんぶんを確認かくにんでき、独立どくりつしたプログラムでもスマートフォンからの返信へんしんを受信じゅしんできました。本文ほんぶんはバイト単位たんいで完全かんぜんに一致いっちしています。以下いかでは、実際じっさいに学まなんだ順序じゅんじょに沿そって、その仕組しくみと復元過程ふくげんかていを改あらためて説明せつめいします。

これは、特定とくていのバージョンと特定とくていのプロトコル経路けいろを対象たいしょうとした調査記録ちょうさきろくです。コードはプライベートリポジトリで個別こべつに開発かいはつされており、WeChat Useには同梱どうこんされません。本文ほんぶんには、実在じつざいするアカウントの認証情報にんしょうじょうほう、ログイン用ようQRコード、チャットの原文げんぶんは含ふくまれていません。

一、目標もくひょう:アプリから何なにを切きり離はなすのか?

まず、WeChatで「こんにちは」と送信そうしんする場面ばめんを想像そうぞうしてください。ウィンドウは、連絡先れんらくさきの選択せんたく、テキストの入力にゅうりょく、送信そうしんボタンのクリックを担当たんとうします。しかし、その背後はいごでは、アカウント認証にんしょう、シリアライズ、暗号化あんごうか、ネットワーク接続せつぞく、サーバーからの応答おうとう、ローカル状態じょうたいの管理かんりも必要ひつようです。

独立どくりつして実装じっそうしたいのは、この後半部分こうはんぶぶんです。

ここでいう「コア」とは、通信つうしんプロトコルとステートマシンを指さし、OSカーネルのことではありません。また、WeChatの全機能ぜんきのうを一いちから作つくり直なおすという意味いみでもありません。最小限さいしょうげんの独立どくりつしたテキストクライアントであれば、まずは明示的めいじてきな受信者じゅしんしゃIDだけを受うけ付つけるようにし、完全かんぜんな連絡先一覧れんらくさきいちらん、グループメンバー、モーメンツ、メディアシステムまで最初さいしょから実装じっそうする必要ひつようはありません。

これにより、検収目標けんしゅうもくひょうが具体的ぐたいてきになります。

  1. 新あたらしいセッションは、スマートフォンでQRコードをスキャンして確認かくにんし、確立かくりつしなければなりません。デスクトップ版ばんWeChatの実行中じっこうちゅうプロセスが保持ほじするログイン状態じょうたいを流用りゅうようしてはなりません。
  2. 送信そうしんするアプリケーションリクエストは、独自どくじのプログラムでエンコード、暗号化あんごうか、転送てんそうしなければなりません。
  3. 受信時じゅしんじには、独自どくじの同期状態どうきじょうたいを更新こうしんし、独自どくじのメッセージデータベースへ書かき込こまなければなりません。
  4. プログラムの終了後しゅうりょうごも、新あたらしいプロセスが状態じょうたいを読よみ戻もどせなければなりません。終了しゅうりょうしていないプロセスを常駐じょうちゅうさせ、見みせかけの状態じょうたいを維持いじするものではありません。
  5. デスクトップ版ばんWeChatが起動きどうしておらず、ツール専用せんようコピーを削除さくじょした後あとでも、双方向そうほうこうにメッセージを送受信そうじゅしんできなければなりません。

前回ぜんかいのWeChatの画像がぞうはどのように暗号化あんごうかされ、私たちはそれをどのように段階的だんかいてきに復元ふくげんしたのかでは、画像がぞうオブジェクトとキャッシュの復元ふくげんについて調査ちょうさしました。今回こんかいは、そこからさらに一段階いちだんかい手前てまえへ進すすみます。メッセージは、ローカルのチャット履歴りれきになる前まえに、どのようにネットワークからクライアントへ届とどくのでしょうか?

二、まず三つを区別する:伝送、業務、保存

「WeChatはAESを使つかっている」と言いうだけでは、まったく不十分ふじゅうぶんです。なぜなら、同おなじ内容ないようでも、置おかれている場所ばしょによって異ことなる形式けいしきで封入ふうにゅうされ、使用しようされる鍵かぎや状態じょうたいも異ことなるからです。

今回こんかいは、それを三つの層そうに分わけます。

層そう解決かいけつする問題もんだい今回こんかいの調査ちょうさにおける対象たいしょう
伝送保護でんそうほごこの接続せつぞくで、信頼しんらいできる暗号化通信路あんごうかつうしんろをどのように確立かくりつするか、レコードが改かいざんされていないかMMTLSハンドシェイク、レコード認証にんしょう、短時間接続たんじかんせつぞくの再開さいかい
業務封入ぎょうむふうにゅうアカウントがどのように本人性ほんにんせいを証明しょうめいし、1回かいの送信そうしんまたは同期要求どうきようきゅうをどのようにエンコードするかログインプロトコル、業務暗号化ぎょうむあんごうか、リクエストヘッダー、メッセージ本文ほんぶん
ローカル永続化えいぞくか受信じゅしんしたメッセージと次回じかいの同期位置どうきいちをどのように確実かくじつに保存ほぞんするか独自どくじの受信じゅしんデータベース、トランザクション、カーソル、操作記録そうさきろく

画像がぞうDATの復号ふくごうは、通信つうしんセッションの解読かいどくと同おなじではありません。伝送でんそうハンドシェイクの成功せいこうも、アカウントへのログイン成功せいこうを意味いみするわけではありません。さらに、アカウントへのログイン後ごも同期状態どうきじょうたいを初期化しょきかして、はじめて差分さぶんメッセージを正ただしく受信じゅしんできます。

まずは、処理全体しょりぜんたいの流ながれを次つぎのように捉とらえてください。

mermaid
flowchart TD
    A[独自クライアント] --> B[認証済み伝送チャネルの確立]
    B --> C[ログイン用QRコードの取得]
    C --> D[スマートフォンでスキャンして確認]
    D --> E[アカウント認証の完了]
    E --> F[初回初期化と同期]
    F --> G[独自のアカウント状態とメッセージDBへ保存]
    G --> H[テキスト送信リクエスト]
    G --> I[メッセージの増分同期]
    H --> J[サーバー応答とスマートフォンでの照合]
    I --> K[メッセージと新しいカーソルを同一トランザクションでコミット]

この図ずは、「curlで送信そうしんするだけ」が見みた目めほど単純たんじゅんではない理由りゆうも示しめしています。HTTPリクエストは、あくまで外殻がいかくの一つにすぎません。真しんに独立どくりつさせるべきなのは、リクエストの前まえにどのような状態じょうたいを準備じゅんびするのか、パケット内ないのバイト列れつをどのように生成せいせいするのか、そしてレスポンスの後あとにどの状態じょうたいの変更へんこうを許可きょかするのかという点てんです。

三、プロセス:まずチャネルを確立かくりつし、その後あとにアカウントを扱あつかう

1. 暗号化接続あんごうかせつぞくの要点ようてんは、相手あいてが誰だれであるかを証明しょうめいすること

この転送実装てんそうじっそうは、新あたらしい楕円曲線だえんきょくせんの一時鍵いちじかぎから開始かいしし、サーバー署名しょめいを検証けんしょうして、ハンドシェイク完了段階かんりょうだんかいの検証値けんしょうちを確認かくにんします。その後あとではじめて、送信側そうしんがわと受信側じゅしんがわそれぞれの鍵かぎとシーケンス番号ばんごうを確立かくりつします。

ここでは、二つの概念がいねんを分わけて考かんがえる必要ひつようがあります。

鍵交換かぎこうかんによって双方そうほうは共通きょうつうの秘密ひみつを導出どうしゅつできます。一方、身元認証みもとにんしょうによってクライアントは、秘密ひみつを交換こうかんした相手あいてが確たしかに想定そうていしたサーバーであることを確認かくにんできます。前者ぜんしゃだけでは、データを復号ふくごうできることが、その接続せつぞくを信頼しんらいできることを自動的じどうてきに意味いみするわけではありません。

レコードのシーケンス番号ばんごうも同様どうように重要じゅうようです。これは一つの接続せつぞくにおける暗号化状態あんごうかじょうたいの管理かんりに関与かんよするため、送信方向そうしんほうこうと受信方向じゅしんほうこうで共用きょうようすることはできず、失敗しっぱいしたコンテキストを流用りゅうようして次つぎのパケットを組くみ立たてることもできません。この実装じっそうでは、シーケンス番号ばんごうがオーバーフローした場合ばあいは直ただちに拒否きょひし、失敗しっぱいしたコンテキストの再利用さいりようを停止ていしします。

この経路けいろでは P-256 などの暗号要素あんごうようそを使用しようしますが、MMTLS には独自どくじのメッセージと状態じょうたいに関かんする規約きやくがあります。これをそのまま「標準ひょうじゅん TLS 1.3」と呼よび、汎用はんよう TLS ライブラリがプロトコル全体ぜんたいを実装済じっそうずみだと仮定かていすることはできません。

短時間接続たんじかんせつぞくでは、認証済にんしょうずみのセッションチケットと再開鍵さいかいかぎの導出どうしゅつも関係かんけいします。その目的もくてきは、接続せつぞくを再確立さいかくりつするたびにかかるコストを削減さくげんすることです。前回ぜんかいの一時秘密鍵いちじひみつかぎと暗号化あんごうかコンテキスト一式いっしきをディスクに保存ほぞんし、そのまま繰くり返かえし使用しようするという意味いみではありません。

2. QRコードはログインフローへの入口いりぐち

チャネルが確立かくりつされると、クライアントはQRコードをリクエストできます。しかし、有効ゆうこうなPNGを取得しゅとくできたことは、画像がぞうを取得しゅとくしたことを証明しょうめいするだけで、アカウントへのログインが完了かんりょうしたことを証明しょうめいするものではありません。

復元ふくげんしたログインフローは、次つぎのように要約ようやくできます。

text
Get QR → QRコードを表示 → スマートフォンでスキャンして確認
       → Checkで同一QRコードの状態を確認
       → 最終アカウント認証 → 認証済みアカウント情報を保存

このバージョンの経路けいろでは、取得しゅとくと確認かくにんはそれぞれ Get 502 と Check 503 に、最終認証さいしゅうにんしょうは Manual 252 に対応たいおうします。これらの番号ばんごうは、このプロトコル経路けいろの分析ぶんせきで使用しようした操作識別子そうさしきべつしであり、外部向がいぶむけの安定あんていしたAPIではありません。

ここで最もっとも見落みおとしやすいのは、「同一どういつのQRコード」であることです。確認応答かくにんおうとうは、元もとのリクエストの識別情報しきべつじょうほうおよびQRコードの発行元はっこうもとと結むすび付つける必要ひつようがあります。古ふるいQRコードの確認結果かくにんけっかを使つかって新あたらしい認証処理にんしょうしょりを完了かんりょうさせることはできません。また、ユーザーが「スキャンした」と言いっただけで、サーバーの状態確認じょうたいかくにんを省略しょうりゃくすることもできません。

スマートフォンでのスキャン確認かくにんは、認可操作にんかそうさです。プログラムができるのはプロトコルフローを完了かんりょうさせることであり、ユーザーによるアカウントログインの確認かくにんを代行だいこうすることではありません。

3. ログイン内部ないぶには、さらにもう一段階だんかいの鍵合意かぎごういがある

最終認証さいしゅうにんしょうの内部ないぶで行おこなわれるのは、単に「スキャン結果けっかを返送へんそうする」ことだけではありません。このバージョンの経路けいろでは、ネストされた secp224r1 の鍵合意かぎごういを復元ふくげんしました。非圧縮公開鍵ひあっしゅくこうかいかぎは57バイト、得えられる共有きょうゆう X 座標ざひょうは28バイトで、その後あと、観測かんそくしたアルゴリズムに従したがってパッケージの復号ふくごうに使用しようする鍵かぎを導出どうしゅつします。

これは、前述ぜんじゅつの P-256 とは役割やくわりが異ことなります。P-256 は転送てんそうハンドシェイクの経路けいろに、secp224r1 はこのログイン処理しょりの経路けいろに現あらわれます。どちらも単に「ECDH鍵かぎ」と略記りゃっきすると、実装時じっそうじに入力にゅうりょくを誤接続ごせつぞくしやすくなります。

このログイン分岐ぶんきでは、共有きょうゆう X の MD5 結果けっかが CBC ラッピングに使用しようされ、key と IV に同一どういつのバイト列れつが用もちいられることを確認かくにんしました。これは既存きそんプロトコルとの互換性ごかんせいのために復元ふくげんしたものであり、新規しんきシステムに推奨すいしょうする暗号設計あんごうせっけいではありません。

同様どうように、ここでの MD5 をサーバーの身元認証みもとにんしょうと見みなすことはできません。ハッシュ、業務上ぎょうむじょうの検証値けんしょうち、ハンドシェイク署名しょめいは、それぞれ異ことなる役割やくわりを担になっています。いずれかが欠かけている場合ばあいに、別べつのものが「こちらも検証けんしょうしているように見みえる」という理由りゆうで代用だいようすることはできません。

四、ログイン後ご、なぜすぐに通常つうじょうのメッセージ受信じゅしんを開始かいしできないのか?

新あたらしい入館にゅうかんカードを受うけ取とったと想像そうぞうしてください。そのカードは入館にゅうかんできることを示しめしますが、前回ぜんかいどのメッセージまで読よんだのかは教おしえてくれません。

独立どくりつクライアントも、初回しょかいログイン後ごに初期しょき同期どうき状態じょうたいを取得しゅとくする必要ひつようがあります。今回こんかいのフローでは、まず NewInit 139 を実行じっこうし、レスポンスに含ふくまれるバインド済ずみの初期化しょきかフィールドを用もちいて自身じしんの同期どうき開始点かいしてんを確立かくりつした後あと、最初さいしょの NewSync を実行じっこうします。

ここでは、ある細部さいぶを明確めいかくに確認かくにんしました。使用しようするのは Init レスポンスの f2 フィールドです。あるサンプルで f2 と f3 の内容ないようがたまたま同一どういつだったとしても、それを理由りゆうにフィールドの識別しきべつを無視むしすることはできません。偶然ぐうぜんの一致いっちは、相互そうご交換こうかん可能かのうなプロトコル契約けいやくを意味いみしません。

最初さいしょの同期どうきが完了かんりょうしてから、自身じしんの受信じゅしんデータベースをコミットし、実行じっこう構成こうせいを生成せいせいします。これにより、「初期化しょきか完了かんりょう」とは、ある関数かんすうが 0 を返かえしたことではなく、永続化えいぞくかされ、新あたらしいプロセスから再読さいどくみ込こみできる一連いちれんの状態じょうたいを意味いみします。

同期どうきカーソルは「最後さいごのメッセージ ID」ではない

チャットソフトウェアの差分さぶん状態じょうたいは、通常つうじょうタイムスタンプよりも複雑ふくざつです。解析かいせきした SyncKey は、識別子しきべつしを持もつ状態値じょうたいちの集合しゅうごうであり、プロトコルのルールに従したがってマージする必要ひつようがあります。最後さいごのメッセージ ID で安易あんいに代用だいようすることはできません。

1 回かいのレスポンスに含ふくまれるのも、1 件けんのテキストだけではありません。そこにはコマンドのリストが含ふくまれ、コマンドごとに異ことなる変化へんかを表あらわします。メッセージコマンドについては、ネストされた文字列もじれつ、元もとのフィールド、完全かんぜんな整数値せいすうちを保持ほじしています。認識にんしきできないコマンドについても生なまデータを保持ほじし、暗黙あんもくのうちに破棄はきしたにもかかわらず、同期どうきが完全かんぜんであるかのように扱あつかうことを避さけています。

メッセージ ID は JavaScript の Number が安全あんぜんに表現ひょうげんできる整数せいすう範囲はんいを超こえることもあります。ストレージとインターフェースでは、完全かんぜんな 64 ビット値ちを保持ほじしなければなりません。JSON を経由けいゆする箇所かしょでは、いったん浮動ふどう小数点数しょうすうてんすうに変換へんかんしてから戻もどすのではなく、正確せいかくな 10 進数しんすう文字列もじれつを使用しようする必要ひつようがあります。

なぜメッセージとカーソルを同時どうじにコミットする必要ひつようがあるのか?

メッセージのバッチ M と、新あたらしいカーソル K を受信じゅしんしたと仮定かていします。

K を先さきに保存ほぞんし、その後あとプロセスがクラッシュすると、M は保存ほぞんされません。すると次回じかい、サーバーは K より後あとから処理しょりを続行ぞっこうし、メッセージの欠落けつらくが発生はっせいする可能性かのうせいがあります。反対はんたいに M を先さきに保存ほぞんし、K を保存ほぞんしなかった場合ばあいは、次回じかいに同おなじメッセージバッチを再度さいど受信じゅしんする可能性かのうせいがあります。

この実装じっそうでは、元もとのレスポンスと取得元しゅとくもとの要約ようやくを保持ほじしたうえで、独自どくじのデータベーストランザクション内ないで、メッセージのバージョン、バッチの情報じょうほう、および新あたらしいカーソルを同時どうじにコミットします。

text
バッチレスポンス全体を検証
    ↓
追跡可能な元のレスポンスを保存
    ↓
BEGIN
    メッセージのバージョンを書き込む
    バッチの重複排除情報を書き込む
    同期カーソルを更新
COMMIT

いずれかの検証けんしょうに失敗しっぱいした場合ばあい、カーソルは進すすめません。この設計せっけいでは、デスクトップ版ばん WeChat のオンラインデータベースを読よみ取とったり変更へんこうしたりする必要ひつようはありません。管理かんりするのは、独立どくりつクライアント自身じしんのデータです。

5. 1件けんのテキストは、どのようにネットワークリクエストになるのか?

ここまでで、アカウント状態じょうたいと同期どうきの開始点かいしてんがそろいました。ここでようやく「こんにちは」を送信そうしんできます。

まず、受信者じゅしんしゃ、本文ほんぶん、および関連かんれんするビジネスフィールドを protobuf バイト列れつにエンコードします。protobuf が担になうのは構造化こうぞうかエンコーディングだけであり、暗号化あんごうかは行おこないません。続つづいて、ビジネス層そうが選択せんたくされたモードに応おうじて圧縮あっしゅくと暗号化あんごうかを処理しょりし、ビジネスヘッダーとチェック値ちを加くわえ、最後さいごにトランスポート層そうのレコードへ格納かくのうして送信そうしんします。

mermaid
flowchart LR
    A[受信者とテキスト] --> B[protobuf ビジネスペイロード]
    B --> C[モードに応じた圧縮と暗号化]
    C --> D[ビジネスヘッダーとチェック値]
    D --> E[トランスポート暗号化レコード]
    E --> F[サーバー]

圧縮あっしゅくと暗号化あんごうかの順序じゅんじょは逆ぎゃくにできない

今回こんかいの静的せいてきな復元ふくげんでは、ordinary mode 5 と mode 13 という 2 つのビジネスペイロードのエンコード分岐ぶんきを対象たいしょうとしています。

mode 5 では、zlib 圧縮あっしゅくに効果こうかがあるかを判定はんていしてから、AES-128-CBC を使用しようします。パケットヘッダーにある元もとの長ながさと、選択せんたくされた暗号化前あんごうかまえの長ながさには、それぞれ異ことなる意味いみがあるため、すべてを暗号文あんごうぶんの長ながさとして記録きろくすることはできません。

一方、mode 13 では強制的きょうせいてきな圧縮あっしゅくと AES-GCM を採用さいようし、観測かんそくされたフォーマットには、暗号文あんごうぶん、12 バイトの nonce、16 バイトの tag が含ふくまれています。AEAD の tag は、暗号文あんごうぶんと対応たいおうする入力にゅうりょくの完全性かんぜんせいを検証けんしょうするために使用しようされ、nonce の生成せいせいに関かんする制約せいやくもプロトコルの正当性せいとうせいの一部いちぶです。RFC 5116 には、このような認証付にんしょうつき暗号あんごうインターフェースと nonce の要件ようけんについての一般的いっぱんてきな説明せつめいがありますが、WeChat プロトコルの仕様書しようしょではありません。

今回こんかい、実在じつざいするアカウントでの送受信そうじゅしんに使用しようされたのは、確認済かくにんずみの通常つうじょうの CBC5 経路けいろです。もう一方いっぽうのエンコード分岐ぶんきについてオフラインテストを実装じっそうしたからといって、実際じっさいのすべての送受信そうじゅしんが GCM を経由けいゆするわけでも、未識別みしきべつのすべてのモードに自動的じどうてきに対応たいおうできるわけでもありません。

そのまま移植いしょくするのが最もっとも難むずかしいのは、プロトコル固有こゆうの計算けいさんロジック

標準的ひょうじゅんてきな AES、楕円曲線だえんきょくせん、zlib には、いずれも成熟せいじゅくした実装じっそうがあります。しかし、プロトコル固有こゆうのチェック値ちは、「よく使つかわれるアルゴリズムを 1 つ選えらぶ」だけでは再現さいげんできません。

ここでは、ある固定こていモジュール内ないの計算けいさんロジックに遭遇そうぐうしました。デスクトップ版ばん WeChat の関数かんすうをそのまま呼よび出だし続つづけると、「独立どくりつクライアント」でありながら、アプリケーション本体ほんたいへの依存いぞんが残のこります。そこで、これをデータとして解析かいせきし、実際じっさいに使用しようされる命令めいれいをデコードして、制限付せいげんつきインタープリターを実装じっそうしました。

インタープリターがアクセスするのは、自身じしんがマッピングしたメモリだけです。出所でどころの不明ふめいなアドレスをホストポインターとして扱あつかわず、任意にんいの外部がいぶコールも許可きょかせず、命令めいれいステップ数すうの上限じょうげんも設定せっていしています。現在げんざいは、実際じっさいに使用しようされる 55 種類しゅるいの命令めいれいをカバーしており、モジュールのバイト列れつにも固定こていのダイジェスト制約せいやくを設もうけています。

この経路けいろでは、暗号化後あんごうかごのビジネスペイロードから入力にゅうりょくを生成せいせいし、それをモジュールに渡わたして計算けいさんさせ、最終的さいしゅうてきに規定きていされた長ながさの結果けっかを取得しゅとくします。戻もどり値ち、出力長しゅつりょくちょう、および実際じっさいの書かき込こみを検証けんしょうし、いずれか 1 つでも条件じょうけんを満みたさなければ、パケットの組くみ立たてを続行ぞっこうしません。

ここで得えられた重要じゅうような教訓きょうくんは、プロトコルの復元ふくげんとは、単たんに鍵かぎを探さがすことではなく、正当せいとうなリクエストの生成せいせいに必要ひつような計算けいさんと状態じょうたいも復元ふくげんすることである、ということです。局所的きょくしょてきなチェック値ちを計算けいさんできたとしても、それで証明しょうめいできるのは局所きょくしょの関数かんすうが出力しゅつりょくを返かえしたことだけです。最終的さいしゅうてきには、完全かんぜんなリクエストと実際じっさいのレスポンスを通つうじて検証けんしょうする必要ひつようがあります。

6.受信じゅしんは逆方向ぎゃくほうこうのアンパックだが、送信そうしんコードを逆ぎゃくに実行じっこうすることではない

サーバーからレスポンスを受信じゅしんしたら、まず転送てんそうレコードを検証けんしょうし、対応たいおうするビジネス層そうのカプセル化かを解除かいじょし、コマンドとメッセージを解析かいせきして、最後さいごに同期どうきトランザクションへ進すすみます。

これは、方向ほうこうは反対はんたいでも役割やくわりは近ちかい経路けいろですが、送信側そうしんがわのすべての前提ぜんていを機械的きかいてきに再利用さいりようすることはできません。たとえば、あるエンコーダーが自作じさくデータを暗号化あんごうかし、さらに復号ふくごうして元もとに戻もどせたとしても、それで証明しょうめいできるのは内部的ないぶてきな整合性せいごうせいだけです。双方そうほうがフィールドの意味いみを同おなじように誤あやまって実装じっそうしていれば、ラウンドトリップテストはそれでも成功せいこうする可能性かのうせいがあります。

そのため、固定こていサンプルのフィールドと境界きょうかい、改変かいへんされたデータを拒否きょひする動作どうさ、実際じっさいのサーバーレスポンス、そしてスマートフォン側がわの完全かんぜんな本文ほんぶんとの対応関係たいおうかんけいを、それぞれ分わけて検証けんしょうします。これらの証拠しょうこが一連いちれんにつながってはじめて、その受信経路じゅしんけいろが正常せいじょうに動作どうさしたと判断はんだんできます。

メッセージの受信じゅしんには継続的けいぞくてきなポーリングが必須ひっすなのか?

ここでは、公式こうしきのネットワークコンポーネントと、現在げんざいの私わたしたちの実装じっそうを区別くべつする必要ひつようがあります。

Tencent が公開こうかいしている Mars は、ネットワーク通信つうしんコンポーネントを提供ていきょうしており、STN には長短ちょうたんコネクションやハートビートなどの仕組しくみが含ふくまれています。これはネットワーク全体ぜんたいのアーキテクチャを理解りかいするうえで役立やくだちますが、公開こうかいされているネットワークコンポーネントが、WeChat のアカウント、ログイン、ビジネスプロトコルを含ふくむ完全かんぜんな実装じっそうであるわけではありません。

私わたしたちの独立どくりつツールでは、現在げんざい、明示的めいじてきな差分取得さぶんしゅとくと、ハートビートの通知後つうちごに同期どうきする経路けいろまでが接続済せつぞくずみです。長時間接続ちょうじかんせつぞくによるプッシュ通知つうちはまだ完全かんぜんには接続せつぞくされていません。そのため、現在げんざいのツールが公式こうしきのプッシュ機構きこうを完全かんぜんに再現さいげんしているとはいえませんし、逆ぎゃくに WeChat 公式こうしきが固定間隔こていかんかくのポーリングだけに依存いぞんしているともいえません。

ツールに設定せっていされている待機間隔たいきかんかくとタイムアウトは、私わたしたち独自どくじの運用方針うんようほうしんです。プロトコル内ないに待機時間たいきじかんらしき数値すうちがあっても、その単位たんいがまだ明確めいかくに特定とくていされていなければ、数値すうちの大おおきさだけを根拠こんきょに「何秒なんびょう」と解釈かいしゃくすることはできません。

七、デスクトップ版 WeChat から本当に独立どくりつしていることを、どう証明しょうめいするのか?

ウィンドウを閉とじるだけでは不十分ふじゅうぶんです。アプリケーションがバックグラウンドで動作どうさしているかもしれませんし、私わたしたちのプログラムが密ひそかに元もとのアプリケーション内ないのリソースを読よみ取とったり、以前いぜんのバックグラウンドサービスを流用りゅうようしたりしている可能性かのうせいもあります。

そのため、最終検証さいしゅうけんしょうでは「コマンドの終了コードしゅうりょうコードが 0」であることに加くわえ、さらにいくつかの確認かくにんを行おこないました。

まず、独立どくりつした QR コードのスキャンで作成さくせいした新あたらしいアカウント情報じょうほうを使つかい、初期化しょきかと独自どくじのメッセージ保存ほぞんを完了かんりょうさせました。その後ご、新あたらしいプロセスをソースコードのディレクトリ外がいから起動きどうし、ネットワークを禁止きんしした状態じょうたいで受信箱じゅしんばことカーソルを読よみ戻もどしました。これは、状態じょうたいが確実かくじつに保存ほぞんされたことを証明しょうめいします。ただし、オフラインの status コマンドがサーバーへ再度さいどログインしたことを証明しょうめいするものではありません。

次つぎに、現在げんざいのコンピューターでツール専用せんようの WeChat を通常つうじょうどおり終了しゅうりょうし、このコピーをゴミ箱ばこへ移動いどうしました。チャットデータは削除さくじょしておらず、アプリケーションは復元ふくげんできます。メインの WeChat は残のこしましたが、起動きどうしていません。

「起動きどうしていなくても、アプリケーションから密ひそかに何なにかを取得しゅとくしているのではないか」という疑問ぎもんを避さけるため、プロトコルのランタイムにはシステムのサンドボックス制限せいげんを適用てきようしました。メインの WeChat とゴミ箱ばこにある専用せんようコピーのどちらに対たいしても読よみ取とりを拒否きょひし、関連かんれんする元もとのアプリケーションのデータディレクトリとサービスへのアクセスも制限せいげんしました。実際じっさいに読よみ取とりを試行しこうすると、アクセス権限けんげんの拒否きょひが返かえされました。

最後さいごに、この条件下じょうけんかで送信そうしんと受信じゅしんをそれぞれ 1 回かいずつ実行じっこうしました。

確認対象かくにんたいしょう実際じっさいの結果けっか何なにを示しめすか
テキスト送信そうしんサーバーが受理じゅりし、スマートフォンにテスト本文ほんぶんが完全かんぜんに表示ひょうじされた独立どくりつした送信経路そうしんけいろがスマートフォンまで到達とうたつした
テキスト受信じゅしん新着しんちゃくメッセージの本文ほんぶんがスマートフォンからの返信へんしんとバイト単位たんいで一致いっちし、サーバーのメッセージ ID が 0 ではなかった独立どくりつした同期どうきによって該当がいとうメッセージを取得しゅとくできた
同期状態どうきじょうたいシーケンスが 2 から 3 に進すすみ、累計るいけい 130 件けんのメッセージバージョンを保存ほぞんした受信じゅしんトランザクションと状態じょうたいの永続化えいぞくかが実際じっさいに行おこなわれた
実行環境じっこうかんきょう送受信中そうじゅしんちゅうのサンプリングでは、いずれもデスクトップ版 WeChat のプロセスが検出けんしゅつされなかったこの 2 回かいの操作そうさは、実行中じっこうちゅうのデスクトップ版 WeChat に依存いぞんしていなかった
アプリケーションへの依存いぞん専用せんようコピーの元もとのパスは存在そんざいせず、メインアプリケーションとゴミ箱ばこのコピーへの読よみ取とりはサンドボックスによって拒否きょひされたランタイムは、この 2 つのアプリケーションを読よみ取とって操作そうさを完了かんりょうすることができない
ライフサイクル元もとの子こプロセスの終了記録しゅうりょうきろく、結果けっかとリクエストの対応関係たいおうかんけいをすべて照合しょうごうした成功せいこうが別べつのリクエストや残存ざんそんプロセスによるものではない

ここでいう 130 は、保存ほぞんされたメッセージバージョンの件数けんすうであり、130 件けんの独立どくりつした新規しんきチャットを受信じゅしんしたと主張しゅちょうするものではありません。最後さいごの差分受信さぶんじゅしんでは 2 件けんのメッセージバージョンが追加ついかされ、そのうち 1 件けんの新規しんきメッセージの本文ほんぶんが、スマートフォンからのテスト返信へんしんと完全かんぜんに一致いっちしました。

より正確せいかくにいうと、結論けつろんは次つぎのとおりです。**ツール専用せんようの WeChat を移動いどうし、メインの WeChat を起動きどうせず、さらにプロトコルプロセスから読よみ取とれない状態じょうたいで、独自どくじのテキスト双方向送受信そうほうこうそうじゅしんを完了かんりょうしました。**コンピューター上じょうのすべての WeChat ファイルを削除さくじょしたという意味いみではありません。

八、なぜ操作記録そうさきろくも通信つうしんの中核ちゅうかくに含ふくまれるのか?

送信要求そうしんようきゅうでは、サーバーはすでに処理しょりしたものの、クライアントが応答おうとうを受うけ取とれないという厄介やっかいな状況じょうきょうが起おこりえます。このとき自動的じどうてきにもう一度いちど送信そうしんすると、重複配信ちょうふくはいしんになるおそれがあります。

そのため、まず送信意図そうしんいとを永続化えいぞくかしてから、実行じっこうを担になう具体的ぐたいてきな子こプロセスを生成せいせいします。要求ようきゅう、パラメーターの要約ようやく、プロセスの識別情報しきべつじょうほう、結果けっか、終了記録しゅうりょうきろくを、すべて同一どういつの操作単位そうさたんいに関連付かんれんづけます。結果けっかが不明ふめいな場合ばあいは記録きろくを保持ほじして自動再試行じどうさいしこうを停止ていしし、ファイルが一時的いちじてきに現あらわれないからといって、未送信みそうしんだったとみなしてはなりません。

受信じゅしんにも同様どうようの問題もんだいがありますが、こちらはバッチ単位たんいの重複排除ちょうふくはいじょとアトミックコミットによって、ローカルでの重複ちょうふくを制御せいぎょできます。これに対たいして、送信側そうしんがわの状態じょうたいが不明ふめいな場合ばあい、ローカルの重複排除ちょうふくはいじょだけでは、リモート側がわで実行じっこうされていないことを証明しょうめいできません。

これが、今回こんかいのコンピューター間かん移行いこうで、ログイン情報じょうほうだけをコピーするのでは不十分ふじゅうぶんだった理由りゆうでもあります。整合性せいごうせいのある受信じゅしんデータベースと過去かこの操作記録そうさきろくもコピーし、さらに旧きゅうコンピューターが同おなじ実行状態じっこうじょうたいを使つかい続つづけないようにする必要ひつようがあります。そうしなければ、2 つのクライアントが同時どうじにカーソルを進すすめたり、結果不明けっかふめいの操作そうさについて互たがいに矛盾むじゅんする判断はんだんをしたりするおそれがあります。

セッションファイルを 1 つ保存ほぞんするのは簡単かんたんです。しかし、「これまでに何なにを行おこない、次つぎに何なにができるのか」を説明せつめいできるクライアント状態じょうたいを保存ほぞんしてこそ、永続化えいぞくかの完全かんぜんな意味いみになります。

九、結論けつろん:何なにができ、何なにがまだできていないのか?

今回こんかい完成かんせいしたのは、独立どくりつしたテキスト通信つうしんコアです。スマートフォンによる QR コード認証にんしょう、アカウント認証にんしょう、初回しょかい初期化しょきか、独自どくじのメッセージデータベース、差分同期さぶんどうき、テキスト送信そうしん、そして新あたらしいプロセスによる状態じょうたいの復元ふくげんに対応たいおうしています。ツール専用せんようのデスクトップ版ばん WeChat を削除さくじょしたあとも、テキストの双方向そうほうこう送受信そうじゅしんについて、スマートフォンとローカルの記録きろくが相互そうごに対応たいおうしていることを実測じっそくで確認かくにんできました。

ただし、これはまだ完全かんぜんな WeChat クライアントではありません。完全かんぜんな連絡先れんらくさきリストとグループメンバーのマッピング、任意にんいの送信先そうしんさきへの対応たいおう、メディアの送受信そうじゅしん、完全かんぜんな長時間接続ちょうじかんせつぞくによるプッシュ通知つうち、長時間稼働ちょうじかんかどうの安定性あんていせいについては、この 2 回かいのテキスト検証けんしょうから保証ほしょうすることはできません。以前いぜん実現じつげんした画像がぞうの復号ふくごうも、自動的じどうてきにこの新あたらしいコアのメディア機能きのうになるわけではなく、別途べっと接続せつぞくして検証けんしょうする必要ひつようがあります。

この研究けんきゅうを通とおして、もっとも伝つたえたい学習方法がくしゅうほうほうは、大規模だいきぼなアプリケーションを、入力にゅうりょく・出力しゅつりょく・状態じょうたいを持もついくつかの境界きょうかいに分解ぶんかいし、それぞれの境界きょうかいに対応たいおうする証拠しょうこを探さがすことです。

QR コードが表示ひょうじされたら、アカウント認証にんしょうまで完了かんりょうしたかをさらに確認かくにんする。レスポンスを解析かいせきできたら、メッセージとカーソルが一緒いっしょにコミットされているかをさらに確認かくにんする。サーバーから成功せいこうが返かえされたら、スマートフォンでも結果けっかを照合しょうごうする。新あたらしいプロセスが起動きどうできたら、元もとのアプリケーションを流用りゅうようしていないかをさらに確認かくにんする。

このように一層いっそうずつ仕組しくみを復元ふくげんしていくことで、「アプリケーションから独立どくりつしてリクエストを送おくる」という発想はっそうが、独立どくりつして動作どうさし、再検証さいけんしょうできる通信つうしんプログラムへと変かわったのです。

復習ふくしゅうでは、この7つの問といに沿そって確認かくにんする

  1. ウィンドウを閉とじた後あと、通信つうしんしているのは誰だれか? アプリケーションのUI、プロトコルクライアント、サーバーを区別くべつする。
  2. なぜAES鍵かぎを1つだけ探さがさないのか? 転送てんそう、ビジネスロジック、ストレージでは、鍵かぎと状態じょうたいの用途ようとが異ことなる。
  3. QRコードが表示ひょうじされたらログイン完了かんりょうなのか? さらにスマートフォンでの確認かくにん、同一生成元どういつせいせいげんの状態確認じょうたいかくにん、最終的さいしゅうてきなアカウント認証にんしょうが必要ひつようとなる。
  4. 最初さいしょのメッセージ受信じゅしんはどこから始はじめるのか? まず初期化しょきかし、その後あと、正確せいかくな取得元しゅとくもとの同期状態どうきじょうたいを使用しようする。
  5. なぜカーソルを先さきに保存ほぞんしてはいけないのか? メッセージとカーソルは、同おなじローカルトランザクションでコミットしなければならない。
  6. 送信成功そうしんせいこうは何なにで判断はんだんするのか? リクエストに対応たいおうする有効ゆうこうなレスポンスに加くわえ、受信側じゅしんがわで本文全体ほんぶんぜんたいを照合しょうごうする。結果けっかが不明ふめいな場合ばあいは自動再試行じどうさいしこうしない。
  7. 独立性どくりつせいをどう証明しょうめいするのか? 元もとのアプリケーションを実行じっこうせず、依存情報いぞんじょうほうの読よみ取とりを制限せいげんし、元もとのプロセスの証拠しょうこを保存ほぞんしたうえで、実環境じつかんきょうにおける双方向そうほうこうの受入試験うけいれしけんを行おこなう。

本稿ほんこうのWeChat固有こゆうのフィールドと検収結果けんしゅうけっかは、今回こんかいの非公開実装ひこうかいじっそうおよび保存ほぞんされた原始記録げんしきろくに基もとづく。外部がいぶリンクはネットワークアーキテクチャと暗号技術あんごうぎじゅつの背景はいけいを補足ほそくするためだけに用もちい、これらの実測結果じっそくけっかに代かわる証拠しょうことはしない。

同じカテゴリの記事 · 解析とセキュリティ

2026年10月17日
16分で読めます
WeChat画像はどう暗号化され、どのように段階的に復元できるのか
画像エンコード、アカウント鍵の導出、AESとXORによる分割処理から、DATの逆変換と高画質リソースのダウンロードまで、同じ再現可能なファイルを使ってmacOS版WeChat 4.1.9の画像処理経路を解説します。
→
2026年7月6日
16分で読めます
微信ローカルデータの二つの道——wechat-use と wechat-decrypt の原理レベルの比較(実測による訂正付き)
二つの微信復号ツールはよく比較されますが、比較の方向がずれています。本当の違いは機能の多さではなく、SQLCipher の key をどう取得するかにあります。この記事では両者を原理レベルまで分解します——SQLCipher の per-DB 鍵モデル、メモリから key を取り出す二つの仕組み(LLDB+entitlement vs sudo+mach_vm)——さらに実際に自分のマシンで走らせ、初版を書いたときの二つの誤判定もついでに訂正しました。
→
2026年7月3日
19分で読めます
Claudeのアカウント停止で見るべき3点:地域、IPタイプ、リクエスト指紋、そして自己チェック方法
Claudeのアカウント停止は、出口がどの地域か、出口IPの種類、クライアントとリクエストが自分で送っている情報、の3点に分けて考えられる。2026年10月の更新:日付の透かしは撤去済み、IPv6と分割ルーティングの抜け道、引っ越しやカード再利用での停止、10月初めにクリーンな環境でも停止された事例、検出ページに追加したチェック項目。
→
次の記事 →
WeChat画像はどう暗号化され、どのように段階的に復元できるのか

コメント

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

最大 1000 文字。