ブラウザ環境検証モジュールの暗号化パラメータ構造と逆解析手法

検証対象リクエストの構造把握

前回の環境構築テストでは、ブラウザ固有のフィンガープリント抽出部分で完全な再現に成功していなかったため、今回は送信ペイロードの構造を詳細に再検証する。目標エンドポイントおよびクエリパラメータの構成は以下の通りである。

const targetEndpoint = "https://fp.tongdun.net/web3_8/profile.json";
const requestConfig = {
  partnerId: "jxhk",
  application: "jxhk_web",
  sessionToken: "jxhk-1746675420182-af90bc059850a",
  sigA: "IAlYstnFkTlBozAOlY0zQI4F4LUmr3RY20PMjtMXMaSLc5mfxRXewN2Tw7bY0nrYhef7JTU5YWmNHjPxw7tWf8bHKGiXKgE3CV4oPNonnj~aRTlvUbibJTbe3EglJqsMZPuLlhjPro6OWtjofLy/cbWaHNLz7APOkw~fhSvO9Qs5htGtwZaQZPwCbj4M7GTTvLDHHLQ2QXhkf2XqJc1RFP0MzcJ3~/yHcCdTp1y5JorOaLYmryoh9UxqJEzrv/Dq4m2q/Krv~F2t1R0Ym3PT6fSC9LfJwyTtzhyaZRGsdUnQNSKFV/efxcjEO5uEyIteOmrNjc1MStIc2tOk9BpX738IFz5tMdBWHjbXfUcKtUYfEGBaC65HVzQ/qrtktY9DRAXzBCISOkG73M3oTglDIetC9EzPBkh9~H47C0ImWycOztNe1ScfAWkKqJzpw4sG8j9ho9UAiEsw/J7kKWcTClP4L8qDAB3PIHdDksPI8iC=",
  sigB: "a/A9ZV03OND33NwOS/pR3ap~kXS/p3vG8QkQECciG4aLM3oBu6kR3J18rGtPiZz0AP0DHQGW59ISXnTYS1GZGGCIRQp~UyaEJxwPBDf81GK3K8wA2VQvd0o/g30t0YJHO3jlFzvqYyD1Sl6mF5b1bgJzuShLJwj0VI2AMOOU1PbagTclQ6kDSl18mUMtk6~9qsp52tZb/uzli9/ehEGkuILF3faGPtz1uqSLF1h492e6hW5Vyt1PFTjUAbYINf7/RyrL2~t/weAmHxR4MtSUB3Mblp9N2tFApci6VtrrRRYUtdbVqc8d6tRS113Ilu9PySGqdrWDG0S51eHxU7sM1td3S1NHqhA2GzdFYN3mhMTDqv4bk3E50IPxpB6kvtFvHIgV7gsix4axfh1WobBdSq6OPsxjTYgw5zJNXPdVBjetQ5wyekfLSvNwVmIRYYoK",
  sigC: "0u0smo2v8tCfMYEC9/zVuv6XnjDx820TaKwBhM2T5YpetOAVWfHBzih3~9r6PZy9Zpng6fCHkCQSvd1osCO5VQZHo0sB1GWobB/vLBzXb/RXAjlYFaUBJ6kJWbjV4DjsLVgulvSIlz8dfLHszZxwTVtYFFrP535kbkieiRj~3LsvpetToOuk7MC6OTCW~ZDdY9AOmacVW9eAyILGZHthh5yf6/CKMCIOhFRdzCmOSacqe~1gy38zDrs2QtQvBb40vV~0csjpgn61adOaA3qQsRMWpofnhhiIptr87hO4dvFujw9YZXXmOVkN3NgsigXL~OvNgWc6PftUJA8HyVL/SHde1q6q28FwDAuQz7TXPdLw/~sRqhfVYiBU90HzUJKvQlrm/Ho4yuP6HsjXpySdDIXJjKDmPpBYtIHeDPIKov67/G~kJEKm9WNwcU8uDeBUesBO0SBJN6iSPLI4iQO42FUaeJPYpoIUAhdy3EqkL1tlhvh6I0qFlt~fQj4WRiQsnQz8Ai4Tknn5pliORh4XG9FinB3Ip7b0KKw3F6IzD~e=",
  sigD: "5AF8CgjGMLnlQgt11r4Pp4JCP/SxgrjT0Gqpem1MB/thfRoYSnE1Y/26Ho1Uvn4PfYzTIBJmAQlEK~CzJLCpYaMxvSKa~L~6Q1NCJlTT2gSlaq7oQ1ArkwU9aMS05hb3EDK5QCrz990gyN~UgRK2pXv4dnH7NgW1DNq97IIEqXMHbAPbY1MUcAD1H9KkfvLy/UOsF0SWkXXWA~pwDf6lW1hlnHFK1Ue9e2Orz~vOi2sqfz7fWvJRKkFPck5HX6/nxXrQtrll54fji5PpcxcwjixxnYvwrs3Pr3sZHlB4yBDvIUnmpTC9HPVEgAvHqArvI/iD9dcEN18O/Bf5ct0xrRjoVRR0R9kAqGL3vyg7TT5cqkYkyHzzPHNGGGdQe71e4WntX63KN8t/ssqaQzzwBNN0hdwgQPv2",
  sigG: "6L/At2A2whx~zHPERTPDQaiYRUhIkYLZgh~KBqH/dQuVI9fatCrPTzisfGy3VxKuECknwHt6uL9Dhg67MHq~fKiMTIHMlhUikJLUeDbmo1ohBM1vyQRjhnXKHK9v4nQC08Aq8tVZUH/FzZjB~~psTNJqyA2S~0tllzsPcglYnS2fz/yANHIutti7Nf~m1pKrhyJAzeOYz7KpuoHle67J2JLenIHm9EsVC0glNfcfJwly2Wt9JAVRHotdpUnAJrM9EKDEYOzGKaW2xpSBhqIesTsZUKo1Bv61MNjySGoADT87RWBKJG6CZYBB/pBE9GtPnfCsKXaawMN/zj4St8ucA6esdv~zAN7d5SJsDaHI2GMO5eYnOMjL2/6aNFRKIvfoaY5N9uSNVusnbpiOUu5Zga==",
  sigF: "2bcrGLrksR8AdGNwoho~jHDyGmtsmAXi",
  sigE: "COmn9YvVf4uNL5kRvfmvEKUgZnXUOqbntv0w1bhnvAvkkFFKhSdYePLOrr3I9g+IQrXC+GcYhwBT5mgL1rm8rMNlsgdIa7z6EkHyctrJ3mY=",
  versionSig: "JZuFK8iZfzhZG+BaqcUjAgNuPh8lFrtHCX3Ev7uGAGTj9gLkI0nL5bb/QS7zhKew",
  identityHash: "QtNhHLDRNFlGszOP7Z3MtgbbXz+D0+Yo5nIwsS2BMtkc/oxuUahUw6zt6HLhJIA/t0boQ7ooLK9C5AhzhNRJagONhn3aFx16yPrTuH2gxzYslJxGh4Pwk/Rp/cwJf1lgyxJgKiDTVT211VOrBbUGMPPHMxLFjgz2NFZL60ZuGOI=",
  wrapperSig: "GPovRHiXimRME7mIvTpACYFqBYlegnTtiGh6a1MnOiw5BonUCnQXLPrY11S/I6reK63heVFuq0IGam/4MslcMF0EBqqM~jlk",
  checksum: "v9zcFcARcJm=",
  callbackId: "_1746682528400_6938",
  requestHash: "1c1b45ff1de7699d976e014172e7bac3"
};

暗号化ロジックの追跡とフック設定

送信直前のパラメータ結合箇所を特定するため、配列の結合処理をインターセプトする。実行時に特定のアプリケーション識別子が含まれる場合に自動ブレークポイントを配置し、スタックトレースの観察を容易にする処理を実装した。

(function interceptArrayJoin() {
  const nativeJoinMethod = Array.prototype.join;
  const targetIdentifier = "app_name=jxhk_web";
  let hookActive = true;

  Array.prototype.join = function(delimiter) {
    if (!hookActive) return nativeJoinMethod.call(this, delimiter);

    const arrayElements = Array.from(this).map(String);
    const matchesTarget = arrayElements.some(segment => segment.includes(targetIdentifier));

    if (matchesTarget) {
      console.group("🎯 検証対象リクエストの結合処理を検出");
      console.log("対象配列データ:", arrayElements);
      console.log("区切り文字:", delimiter);
      console.trace("呼び出し元のスタックトレース");
      debugger;
      console.groupEnd();
    }

    return nativeJoinMethod.call(this, delimiter);
  };

  console.log("✅ Array.prototype.join のフックインストール完了");
})();

送信パラメータと環境データのマッピング

フックを介して停止状態を作り、各暗号化フィールドが対応するブラウザ環境情報を解き明かす。パラメータは特定のアルゴリズムおよび符号化処理を経て送信され、元の文字列にはタイムスタンプなどの動的要素が付与される。

  • sigA: リゾルバ情報、オーディオフィンガープリント、システム言語、解像度(1920x1080)、タイムスタンプなどを結合した文字列を符号化。
  • sigB: OS (Win32)、ユーザーエージェント、ブラウザレンダリングエンジン、バージョン、タイムゾーンなどを統合。
  • sigC: スクリーン解像度、ドメインハッシュ、ページURL、ストレージ容量、ネイティブメソッド署名などを収集。
  • sigD: グラフィックスベンダー、WebGLパラメータ、IPアドレス、クライアント解像度情報を暗号化。
  • sigG: 入力デバイス数、WebRTC接続情報、メディアコーデック、タイムスタンプ関連データを処理。
  • sigF: 機能の有効/無効状態を示すバイナリ的なフラグ列。
  • sigE: `localStorage` に格納された特定キーの値を直接取得し符号化。
  • versionSig (v): 読み込まれた検証スクリプトのバージョンハッシュ。
  • identityHash (idf): カレントタイムスタンプをRSA公開鍵で暗号化し、Base64エンコード。
  • wrapperSig (w): `versionSig` の値をさらに特定のアルゴリズムで再暗号化。
  • checksum (ct): 計算された制御番号を符号化。
  • callbackId & requestHash: 動的に生成されるコールバック識別子と、全パラメータの整合性チェック用のハッシュ値。

各フィールドは元の文字列にタイムスタンプなどの動的要素を付与した後、独自の符号化関数を通って最終的なペイロードに組み込まれる。復元時は逆順の処理と環境変数の正確な再構築が必須となる。

環境差異の特定と調整方針

解析フェーズでは、実際に取得されたフィンガープリントとサーバー側で期待される値の差分を精査する。ネイティブメソッドの署名差異、GPUレポートの誤認識、またはタイムゾーン・ストレージ容量の不一致などが主な検証対象となる。得られた差分データを基準に、ヘッドレスブラウザまたは自動化テスト環境のパラメータを逐一補正し、完全な環境再現を目標とする。

タグ: ブラウザフィンガープリント リバースエンジニアリング JavaScriptフック Webセキュリティ 環境解析

5月26日 17:04 投稿