
reCAPTCHAのドキュメントとリバースエンジニアリング
このリポジトリは、Googleのアンチボット(reCAPTCHA)の技術的分析を含んでおり、以下に焦点を当てています。
@g_recaptcha@lyxlobyxreCAPTCHAは、最も高度な難読化技術を備えたアンチボットシステムの1つであり、コードを読みづらくし、リバースエンジニアリングを困難にする一連の変換を適用しています。ほとんどの難読化は抽象構文木(AST)を使って容易に操作できますが、一部は実行時に処理されるため、ASTはこの場合無効になります。また、コードにはポリモーフィズムが適用され、スクリプトのバージョンごとに構造が変更されます。例えば、コードは直接アクションを実行せず、代わりに形を変えるオブジェクトや関数を使用します。
シーケンス式
コードは、各ブロック文を連続したカンマ区切りの式に変換することでフラット化されます。これはif文、関数引数、さらにはオブジェクト内にも現れます。

混合ブール算術
算術演算(加算、減算、乗算)とビット演算(AND、OR、XOR、NOT)を織り交ぜて元のロジックを隠します。例:-2 * ~(h & H) + -2 + (h ^ H)
間接関数テーブル
各関数はテーブル内に構築され、そのインデックスを使って呼び出されます。例:functions[index](https://github.com/elyelysiox/recaptcha/blob/HEAD/args)
インライン定数配列 ローカル配列リテラルが式の途中でインラインに代入されます。この配列は関数本体全体でインデックスアクセスを通じて再利用される定数(数値、文字列)をグループ化します。
// b = [14, 1, "call"] はシーケンス式内でインライン代入される
function(Y, Q, c, l, G, X, W, J, b, P) {
(Y & 94) == Y && (b = [14, 1, "call"], ...)
W[b[2]](J, G) // W.call(J, G)
Y >> b[1] & b[0] // Y >> 1 & 14
}
関数多重化 複数の論理的に異なる関数が1つに統合され、数値パラメータをブロックセレクタとして使用します。アクティブなブロックは、パラメータをビット単位の条件に対して評価することで決定されます。呼び出し元は数値リテラルをセレクタとして渡します。
function(N, y, U, Y, h, H, m, C, u) {
C = [26, 47, 6];
// ブロック1
if ((N - 2 ^ 14) < N && (N - C[2] | 28) >= N) {
// 値を文字列に変換するロジック
}
// ブロック2
if ((N + 4 & 40) >= N && (N + 5 & C[0]) < N) {
Y = bB();
throw Error(Y === void 0 ? "unexpected value " + U + y : Y);
}
return u;
}
論理演算子による分岐 if文やif/elseブロックを論理演算子の短絡評価で置き換え、制御フローを式に変換します。シーケンス式と組み合わせることで、複数の分岐が単一の連続したカンマ区切りの式として現れます。
// if (a) { block }
a && (block)
// if (!a) { block }
a || (block)
// if (a) { x } else { y }
a ? x : y
// CFFとシーケンス式の組み合わせ:
(Y | 1) & 14 || (c = Q.O, J = c.O.length + c.g.length),
(Y ^ 59) >> 3 == 3 && (Q.classList
? Q.classList.add(c)
: Z[31](31, Q, c) || (l = f[0](84, "string", "", Q), ...)),
ネイティブメソッド定数のバインド ネイティブブラウザメソッドを元のレシーバにバインドし、改ざんを防ぐために定数として保存します。
LO = (Tw = self) == null ? void 0 :
(K9 = Tw.Math) == null ? void 0 :
(v4 = K9.floor) == null ? void 0 :
(mF = v4.bind) == null ? void 0 :
mF.call(v4, Math) // Math.floor.bind(Math)
LO(x) // Math.floor(x)
U4() // Math.random()
Ge(obj, prop) // Object.defineProperty(obj, prop)
デッドコード アクセス不能または未使用のコードブロックがファイル全体に注入され、サイズが60,000行以上になります。これにより、静的解析やLLMベースのリバースエンジニアリングが困難になります。
制御フローの平坦化 コードの各部分(宣言やループ)をフラットな状態機械に変換します。すべてのコードブロックを中央の「ディスパッチャ」ブロック経由でルーティングすることで、元の実行ロジックを隠します。
ディスパッチャは形を変えることができます。2〜3個の状態変数を持つものもあり、ループ/条件のタイプが変わります。次のようになります。

これは2つの状態変数を持つCFFで、1つはcatchブロック、もう1つはtryブロックを処理します。
暗号化文字列プール すべての文字列リテラル(DOM API、ブラウザプロパティ、CSS値、エラーメッセージなど)は、単一の巨大な文字列プールに暗号化されます。復号関数はシードとLCGベースのXOR暗号を使用して、実行時に各文字列を抽出します。
コード全体に1990以上の呼び出し箇所があり、復号関数はデコードされたコードポイントを累積するランニングキーを使用するため、各文字は以前のすべての文字に依存します。
X = function(J, b, P, F, U) {
U = ["codePointAt", 127, "char encrypted pool"];
for (F = (P = 0, b = "", l); P < Q; P++)
J = (U[2][U[0]](c + P) ^ F) & U[1], // ランニングキーとのXOR
b += String.fromCodePoint(J),
F += J; // キーを累積
return G = b;
}
// 呼び出し箇所は各文字列を特定して復号するためにシードを渡す
Z[23](64, 4, 54961, 103)() // → "lang"
Z[23](66, 4, 54961, 103)() // → "addEventListener"
Z[23](32, 12, 20287, 852)() // → "inline-block"

状態を持つ値イテレータ reCAPTCHAは状態を持つ関数を使用し、固定された順序で一連のランタイムオブジェクトや値(window、document.body、数値定数など)を返します。呼び出しごとに内部カーソルが進み、順序を無視して呼び出したり、何度も呼び出すと後続の読み取りがすべて破損します。タイムアウト機構により、一定時間後に状態が無効になり、遅延読み取りではnullが返されます。
// 順次呼び出しで異なる値が返る:
c() // → window
c() // → document.body
c() // → 123
c() // → null (タイムアウト切れ)
l(c(), G[2], G[W[1]], G[1]) + l(c(), G[2], G[W[1]], 12)
// ↑ window ↑ window
10 * l(c(), G[2], G[W[1]], G[1]) + l(c(), G[2], G[W[1]], 12))
c().querySelectorAll(a[X[2]](98, X[1], X[1]))
// ↑ document.body
計算関数テーブル
これは間接関数テーブルと似ていますが、ここでは取得する関数のインデックスが実行時にシードを使ってXORとModulusで計算されます。
c = ((Q ^ no | U[1]) >> 5) + no
A = mN[(c % U[2] + U[2]) % U[2]] // mNは関数テーブル(50以上の関数)
q[29](5, 6977) // seed=6977 → インデックスはmN[X]の関数に解決
q[29](53, 6187) // seed=6187 → 異なるインデックス、異なる関数

実行時値暗号化
一部の値(captcha設定パラメータ、アンカーパラメータなど)はプレーンテキストで保存されることはなく、収集直後に暗号化され、使用時のみ復号されます。先頭に接頭辞Bが付きます。

非同期制御フロー難読化 同期ロジックは、再帰的なPromiseチェーンでラップされたジェネレータベースの状態機械に変換されます。デバッガで値をトレースすると、複数の非同期ハンドラをステップ実行することになり、各.then()の境界で元の実行コンテキストが失われます。
reCAPTCHAを初期化するためのコンポーネント``` ar: <WidgetInit?> k: co: hl: v: size: sa: anchor-ms: execute-ms: cb:
### Response
応答には以下が含まれます:
- CAPTCHA iframe ウィンドウデザイン
- ペイロード検証に使用されるアンカートークン (/reload)
- 初期化のためのメイン設定で、`recaptcha.anchor.Main.init` メソッド内で実行され、recaptcha_en.js で受信します。
### Structure:
注:Recaptcha BotGuard は `04/01/2026` に削除されました。サンプルは [こちら](https://github.com/elyelysiox/recaptcha-payload/tree/main/botguard_scripts) でご確認いただけます。```javascript
[
"ainput",
[
"bgdata",
"",
"LyogQW50aS1zcGFtLiBXYW50IHRvIHNheSBoZWxsbz8gQ29ud...", // BotGuard Script Base64-Encoded
"YWVtZ0h5MGNCWXJDQ2lidGh0RW13RmhWdlc3aU5yeVpzSmx6U...", // BotGuard VM Bytecode Double Base64-Encoded
"wrB8fsOVU8K0YAzDsyQpw7ZHw6jDnMK1AMO6SRcvw53CsGlQw6/DuMO0wqr" // VM Config Bytecode Base64-Encoded
],
null,
[
"conf",
null,
"6LfTV4gkAAAAACDVrUvp9_DalxUPvFSU7M2HJDO-", // Website Key
0,
null,
null,
null,
1,
// Indexes for fingerprinting or something else
[16, 21, 125, 63, 73, 95, 87, 41, 43, 42, 83, 102, 105, 109, 121],
[-7614991, 137],
0,
null,
null,
null,
null,
0,
null,
0,
null,
700, // Time Start for Time Variances of Fingerprint Values
1,
null,
0,
// Encoded metadata for the VM's main bytecode constructs
"CvsCEg8I8ajhFRgAOgZUOU5CNWISDwjmjuIVGAA6BlFCb29IYxIPCMfm1DgYADoGZHhkTmlkEg8Is4qgOBgBOgZMV0o1a2ISDwiB7OgVGAA6Bkh1dlBqZhIPCK6e6zcYADoGR2JpT1FkEg8I94jmNxgAOgZvaWxlRGQSDwjwzeMVGAE6BmZJVkloYhIPCOLKoDcYAToGZ0xOQ0hjEg8I3r+3NxgBOgZlYXp1NmQSDwjY0oEyGAA6BkFxNzd2ZhIOCLjllDIYAToFUUJPRDASDwio7784GAA6BkdGVU5jZhIPCLWzqzgYAToGb3JZVjZkEg8I0tuVNxgAOgZmZmFXQWUSDwiV2JQyGAE6BlBxNjBuZBIPCKuRyjgYADoGQVo0TmJiEg8IxfOINxgAOgZhWG9pYWMSDwiNyoYyGAE6Bk93TjR0ZhIOCIr9iDcYADoFTWZJSTQaJwgDEiMdJv3NgTUZp4oJGYQKGZzijAIZzPMRGa+VQBnqsCYZ5a8MGQ==",
0,
1,
null,
null,
1,
null,
null,
0,
null,
null,
0,
0,
"cf5e3c3a6ab6c494c829a7932d9577c1e6de862dd4912e55dc7fe2e40a1f7604"
],
"https://who.clickbait.team:443", // Website URL:Port
null,
[
3,
1,
1
],
null,
null,
null,
1,
3600,
[
"https://www.google.com/intl/es/policies/privacy/",
"https://www.google.com/intl/es/policies/terms/"
],
"vQWNjTpMwdevQPWmE8akDzp8jsOZfa1VqTzVHaPiQ/c=",
1,
0,
null,
1,
1777669303203, // Fingerprint Data Encryption Key
0,
0,
[203], // Config Bytecode Key
null,
[185], // Config Bytecode Key
"RC--rg1OSRnOD0ayA",
null,
null,
null,
null,
null,
// Bft Token, Used in reCAPTCHA V2
"0dAFcWeA4RepD9zDjeMQE73pAT27pXZ7Nz_419U2K36QNqzHaKtLIDkwZQLi-Ud8OvSZHbDEcxQxusBQnsF5QQErMRpJMcUplaFg",
1777752103288 // "oc" Data Encryption Key
]
値は最初のサンプルフィンガープリントの復号化された値に基づいています。こちらを参照してください。
フィンガープリント値の各サブフィールドには基本フォーマットがあります:
[value, key, elapsed]
ここで key は暗号化キーであり、elapsed はコレクターが値を取得して暗号化するのにかかった時間です。これにより、reCAPTCHAは以下を検出できます:
システムは内部スケジューラを使用します:``` [42, 45, 53, 30, 28, 54, 29, 31, 32, 33, 34, 35, 37, 36, 38, 39, 43, 40, 41, 46, 48, 57, 58, 60, 61, 62, 63, 64, 66, 68, 69, 71, 72, 79, 55]
This represents:
- 実行順序
- コレクタパイプライン
- 信号生成シーケンス
### フィンガープリント信号コードと鍵導出
フィンガープリント信号を多段階導出パイプラインを通じて決定論的な暗号鍵に変換します
各フィンガープリント値は:
- 正規化され
- コンパクトな信号コードにエンコードされ
- 数値の暗号鍵に変換され
- 導出された鍵を使用して暗号化されます
このプロセスは決定論的であり、同じ入力値は常に同じ信号コードと暗号鍵を生成します```
Raw Value
↓
Signal Code Derivation
↓
Compact Signal Code
↓
Numeric Key Derivation
↓
Encryption Key
↓
Value Encryption
入力信号``` "BUTTON,195a81c9"
***ステップ1 - 信号コードの導出***```javascript
deriveSignalCode("BUTTON,195a81c9")
// → "wg"
生成されたシグナルコードは、元の値に対するコンパクトな決定論的識別子です。
ステップ2 - 数値キーの導出```javascript deriveKey("wg") // → 3792
信号コードは数値の暗号鍵に変換されます。
***ステップ3 — 値の暗号化***```javascript
encryptValueWithKey(3792, "wgia1z9pwq")
// → "bYVbh6BUsE_5pLA"
次の値は、コレクターの順序に従って、派生キーで暗号化されます。
すべての生成されたシグナルコードは、コンパクトなシリアライズ構造に集約されます。
プロセス``` value -> "BUTTON,195a81c9" seed code -> wg key -> 3792 value -> "wgia1z9pwq" seed code -> 21 key -> 1599 value -> 1 seed code -> p1 key -> 3521 value -> "8cc68d83" seed code -> ld key -> 3448 value -> "https://nextcaptcha.com/demo..." seed code -> 9p key -> 1879 value -> 4 seed code -> op key -> 3553 value -> false seed code -> 1r key -> 1633 value -> 7 seed code -> qf key -> 3605 value -> "jYAQSHAEAI" seed code -> 1z key -> 1641 value -> "" seed code -> 80 key -> 1784 value -> 2 seed code -> jk key -> 3393 value -> "AAAAAAAAAA" seed code -> 1z key -> 1641 value -> "h3" seed code -> 9p key -> 1879 value -> "0,BUTTON,195a81c9" seed code -> ia key -> 3352 value -> -1 seed code -> 1u key -> 1636 value -> 0 seed code -> wq key -> 3802 value -> "74,fbfbc5b3" seed code -> 6z key -> 1796 value -> 0 seed code -> wq key -> 3802 value -> 0 seed code -> wq key -> 3802 value -> 2 seed code -> jk key -> 3393 value -> 0 seed code -> wq key -> 3802 value -> "-1,-1" seed code -> 1m key -> 1628 value -> "static.cloudflareinsights.co,..." seed code -> 1g key -> 1622 value -> "" seed code -> 80 key -> 1784 value -> "https://nextcaptcha.com,https...." seed code -> pd key -> 3572 value -> "[4,"CABIBQAggA","BAgAAgAAgA"]" seed code -> 1n key -> 1629 value -> "Demostración empresarial de reCAPTCHA v3..." seed code -> 1k key -> 1626 value -> "[2,76852,77850,77351]" seed code -> 9b key -> 1865 value -> "sha384-TNm" seed code -> 23 key -> 1601 value -> "[1680,1050,876,1166,844,876]" seed code -> 13 key -> 1570 value -> "[300,null,1778502450481]" seed code -> ex key -> 3251 value -> "[null,null,"",""]" seed code -> rx key -> 3654 value -> "[2147483648,70806416,65303240]" seed code -> 2r key -> 1664 value -> "GA1.1.354395113.1778502448" seed code -> 1g key -> 1622 value -> false seed code -> 1r key -> 1633 value -> "[[[1,"wg"],..." seed code -> 85 key -> 1789
**最終**```json
[
[
[1, "wg"], [1, "21"], [1, "p1"],
[1, "ld"], [1, "9p"], [1, "op"],
[1, "1r"], [1, "qf"], [1, "1z"],
[1, "80"], [1, "jk"], [1, "1z"],
[1, "9p"], [1, "ia"], [1, "1u"],
[1, "wq"], [1, "6z"], [1, "wq"],
[1, "wq"], [1, "jk"], [1, "wq"],
[1, "1m"], [1, "1g"], [1, "80"],
[1, "pd"], [1, "1n"], [1, "1k"],
[1, "9b"], [1, "23"], [1, "13"],
[1, "ex"], [1, "rx"], [1, "2r"],
[1, "1g"], [1, "1r"]
],
"54"
]
Idx 4 (string)
Value: 3ccb
Hashed: true
説明: window.localStorage.getItem("rc::a") + "6d" をバイト列に変換したものから HMAC 鍵を生成し、その鍵で HMAC-SHA256(siteKey) を計算し、結果の先頭 4 文字の 16 進数文字列を返します。
rc::a の値はランダム生成された base64 です。
Idx 5 (integer)
window.localStorage.length * 2falsewindow.localStorage の長さを 2 倍した値Idx 16 (string)
Value: yM5Us/j/fn6EDgtmPlP4Pxj605nMJN9dRYHyy5Mn
特定の reCAPTCHA シグナルは利用不可であるか、収集に失敗する場合があります (デバッグ関連のタイムアウトによる)。その場合、欠落したシグナルはランダムに生成された base64 エンコード値で埋められます。例:``` ["CMXZyamk3ZHNjdGsyaQ==", 3249, 591]
指紋構築が完了すると、それは文字列にシリアライズされ、アンカーフィールド(インデックス18)から読み込まれた暗号化キーを使用して暗号化されます。暗号化された結果は、`/reload` ペイロードのインデックス`16`フィールドに保存されます。
## VM シグナル
以下は、内部 reCAPTCHA VM によって取得されたブラウザの値と、シグナルキーです。一部の値はサンプルフィンガープリントに表示されていません。これは、VM が構成バイトコードから特定の値のみを抽出するためです。そのため、他の値が表示されます。詳細については、[こちら](https://github.com/elyelysiox/recaptcha-vm) を参照してください。
基本シグナル形式:```
[
null,
collectorElapsed,
encryptElapsed,
value
]
ここで、collectorElapsed はコレクターが値を取得するのにかかった時間(ms)を意味します
そして、encryptElapsed は値の暗号化にかかった時間(ms)を意味します。
これらの時間はVMの実行中に測定されます。
[ null, 7, 0, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36" ], null, null, [ null, 0, 0, "[]" ], null, null, [ null, 4, 0, "["Join And Get Free Trial!","","Captcha Solving Service","Products","Docs"]" ], [ null, 0, 0, "false" ], null, [ null, 0, 0, "0" ], [ null, 1, 0, "[null,null,null,null,"false"]" ], [ null, 3, 4, "[[[0,921],[1,2053]],[[235054,1,1,1],[164277,3,4,1]],2,39]" ], [ null, 1, 4, "[[[0,0,979]],1,0]" ], [ null, 1, 1, "[[[1,0]]]" ], [ null, 4, 1, "[886,2300,262.2099999997952,392.7600000009595,2050.2399999993577]" ], [ null, 1, 1, "[[[1123,0,0]]]" ], [ null, 1, 2, "[[[1123,0]]]" ], [ null, 1, 3, "[0,null,null,null,null,null,null]" ], [ null, 5, 9, "[1,[[2050,125,633,266,[609,266,105,44],3,1,50,1,1]],[3,3,318],[28,777,858,28],0,0,25]" ], [ null, 0, 0, "" ], [ null, 0, 0, "229.6" ], [ null, 0, 0, "false" ], [ null, 1, 0, "[1,0,0,Infinity]" ], [ null, 1, 1, "["0",-1,-1,999]" ], [ null, 1, 0, "["undefined",3]" ], [ null, 1, 6, "[2,4,53324367238]" ], [ null, 12, 0, "["Google Inc. (Intel Inc.)","ANGLE (Intel Inc., Intel(R) UHD Graphics 630, OpenGL 4.1)",30]" ], [ null, 28, 2, "[1542343452,0,105002991,3556653,96784904,-731949068,-902263026,-1914850612,571474391,-1588406278,3443508,1967713171,-1249474914,-1588406278,0,918504841,-807058197]" ]
- **Key 417** (`string`)
- Value: `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36...`
- Description: 完全なブラウザのユーザーエージェント
- **Key 727** (`array`)
- Value: `[]`
- Description: 製品価格ブロック。ウェブサイト上の商業製品の価格を含みます。これらはAmazon、eBay、AliExpressなどのマーケットプレイスウェブサイトに表示される可能性があります。[サンプル](https://github.com/elyelysiox/recaptcha/blob/main/findProductPricesBlock.js)
- **Key 150** (`array`)
- Value: `[\"Join And Get Free Trial!\",\"\",\"Captcha Solving Service\",\"Prod...`
- Description: ウェブサイトの`<a>`要素から抽出されたリンク。VMがこれらの値を抽出することは稀です
- **Key 545** (`boolean`)
- Value: `false`
- Description: `navigator.webdriver`
- **Key 370** (`integer`)
- Value: `0`
- Description: 最大デバイスタッチポイント `navigator.maxTouchPoints`
- **Key 779** (`array`)
- Value: `[null,null,null,null,"false"]`
- Description: 配送/請求フィールドからデータを抽出します。[サンプル](https://github.com/elyelysiox/recaptcha/blob/main/formFieldScrape.js)
`postal|postalcode|postalcode|postal_code|zip` → 郵便番号フィールドを検索
`ship|deliver` → 配送セクション
`billing|payment|credit` → 請求セクション
`country` → 国セレクター
`addr.*(match|equal)|(match|equal).*address` → 「住所が同じ」チェックボックス
各要素のname、id、autocomplete、classNameを読み取ります
3つのフェーズ: テキスト入力、SELECT要素、チェックボックス
- **Key 659** (`array`)
- Value: `[[[0,921],[1,2053]],[[235054,1,1,1],[164277,3,4,1]],2,39]`
- Description: ページ上で押された要素のデータを以下の形式で含みます: `[[[count,timestamp]],[[hashedElem,tagType,type,autoComplete]],pressedCount,behaviorChecksum]`
### 要素タイプ
| 要素タイプ | ID |
|-------------|----|
| `""` | 1 |
| `text` | 2 |
| `button` | 3 |
| `submit` | 4 |
| `checkbox` | 5 |
| `email` | 6 |
| `password` | 7 |
| `select-one` | 8 |
| `select-multiple` | 9 |
| `radio` | 10 |
| `textarea` | 11 |
| `file` | 12 |
| `tel` | 13 |
| `number` | 14 |
| `date` | 15 |
| `reset` | 16 |
| `range` | 17 |
### 動作チェックサムアルゴリズム
behaviorChecksumは、収集されたユーザーインタラクションデータから導出されるコンパクトな動作スコアです。
各インタラクションについて:
- インタラクションインデックスは1ずつ増加
- タイムスタンプは調整されたインタラクションインデックスと結合
- 要素ハッシュはモジュロ演算で縮小
- 結果は実行中のスコアに累積
---
```javascript
function computePressedElementsChecksum(pressedElementsArray) {
let accumulator = 0;
for (const [countTimestampPair, elementInfo] of zip(
pressedElementsArray[0],
pressedElementsArray[1],
)) {
const shiftedTimestamp = countTimestampPair[0] + 1;
const baseValue = countTimestampPair[1] + shiftedTimestamp;
const remainder = elementInfo[0] % baseValue;
accumulator = remainder + accumulator;
}
const logTerm = Math.log(accumulator + 1) * 4;
const modTerm = accumulator % 10;
const behaviorChecksum = Math.floor(logTerm + modTerm);
return JSON.stringify(pressedElementsArray);
}
function zip(a, b) {
const length = Math.min(a.length, b.length);
const result = [];
for (let i = 0; i < length; i++) {
result.push([a[i], b[i]]);
}
return result;
}
```
### 例
```javascript
const checksum = computePressedElementsChecksum([[[0,921],[1,2053]],[[235054,1,1,1],[164277,3,4,1]],2,39]);
console.log(checksum); // → 39
```
- **Key 959** (`array`)
- Value: `[[[0,0,979]],1,0]`
- Description: ページセッション中に収集されたスクロール動作を含みます
### 基本形式
```
[ [ [ scrollX, scrollY, timestamp ] ], count, behaviorChecksum ]
```
- **Key 895** (`array`)
- Value: `[[[1,0]]]`
- Description: `VisibilityStateEntry`はページの可視性ステータスを追跡し、ユーザーが現在ページを閲覧中か、または別のページに移動したかを示します。形式: `[[[isVisible, startTime]]]`
- **Key 1092** (`array`)
- Value: `[886,2300,262.2099999997952,392.7600000009595,2050.2399999993577]`
- Description: reCAPTCHAのパフォーマンス、PerformanceNavigationTimingおよびPerformanceEventTiming。形式: `[vmStart,vmEnd,domContentLoadedEventEnd,loadEventEnd,firstUserInteractionTime]`
- **Key 41** (`array`)
- Value: `[[[1123,0,0]]]`
- Description: タイムアウトクリア
- **Key 43** (`array`)
- Value: `[[[1123,0]]]`
- Description: タイムアウトクリア
- **Key 549** (`array`)
- Value: `[0,null,null,null,null,null,null]`
- Description: KeyboardEvent、計算されたキー+タイムスタンプ
- **Key 352** (`array`)
- Value: `1,[[2050,125,633,266,[609,266,105,44],3,1,50,1,1]],[3,3,318],...`
- Description:
構造は以下を含みます:
- マウス移動のタイミング
- カーソル座標
- クリック時間
- 押された要素の寸法
- ポインタタイプ情報
- 圧力メトリクス
- カーソル移動距離
- 動作タイミング統計
### 基本形式:
```
[
eventsCount,
mouseEvents,
[
coalescedEventsCount,
averageInterEventDelay,
timingVarianceScore
],
[
totalPoints,
clickSequenceScore,
totalCursorDistance,
totalPoints
],
0,
0,
behaviorChecksum
]
```
### マウスイベント構造:
mouseEvents内の各エントリは以下の構造に従います:
```
[
timestamp,
clickDuration,
clientX,
clientY,
[
elementLeft,
elementTop,
elementWidth,
elementHeight
],
elementTagType,
trackedElementIndex,
pressure,
pointerTravelDistance,
pointerArea
]
```
| 名前 | 説明 |
|---|---|
| `timestamp` | イベント開始からの相対タイムスタンプ |
| `clickDuration` | `pointerdown`から`pointerup`までの時間 |
| `clientX` | ... |
| `clientY` | ... |
| `elementBounds` | インタラクトされた要素のバウンディング矩形 |
| `elementTagType` | インタラクトされた要素のエンコードされたDOMタグ識別子 |
| `trackedElementIndex` | ランタイムインタラクションマップからのインタラクトされたDOM要素の内部識別子 |
| `pressure` | 正規化されたポインタ圧力値に`100`を乗算 |
| `pointerTravelDistance` | `pointerdown`から`pointerup`までの移動距離 |
| `pointerArea` | `width * height`で計算された接触面積 |
### 要素タグタイプ
これはreCAPTCHA VMの実行中に初期化されます
| タイプ | ID |
|-----------|----|
| `BODY` | 1 |
| `INPUT` | 2 |
| `BUTTON` | 3 |
| `SELECT` | 4 |
| `TEXTAREA`| 5 |
| `FORM` | 6 |
| `A` | 7 |
| `AREA` | 8 |
| `AUDIO` | 9 |
| `VIDEO` | 10 |
| `IFRAME` | 11 |
| `DIV` | 12 |
| `SPAN` | 13 |
| `LABEL` | 14 |
### 例
```
[
18342,
91,
742,
381,
[700, 320, 120, 38],
3,
1,
50,
1.4,
16
]
```
表す内容:
- `18.342s`のイベント
- `91ms`のクリック時間
- `(742, 381)`でのクリック
- `BUTTON`とのインタラクション
- ポインタ圧力 `0.5` (50)
- クリック中のわずかなカーソル移動
- ポインタ接触面積 `16`
### 動作チェックサムアルゴリズム
各マウスイベントについて:
- クリック時間を増幅
- その結果をイベントタイムスタンプと結合
- カーソル座標と要素寸法を混合
- 加重比率を計算
- 比率を丸めて累積
すべてのイベントが処理された後:
- 累積スコアを総カーソル移動距離と結合
- 結果を収集ポイント数で正規化
- 対数変換を適用
- 追加の移動統計を組み込む
- 最終値をモジュロ演算で縮小
- 結果を小さな整数スコアに丸める
---
```javascript
function computeMouseBehaviorChecksum(mouseDataArray) {
let totalSum = 0;
for (let i = 0; i < mouseDataArray[1].length; i++) {
const event = mouseDataArray[1][i];
const scaledClickDuration = event[1] * 4;
const xPlusScaledDuration = event[0] + scaledClickDuration;
const combinedElementDims = event[2] + event[4][2] + event[4][1]; // clientY + elementWidth + elementTop
const product = xPlusScaledDuration * combinedElementDims;
const divisor = event[3] + event[4][3] + event[4][0] + 1; // elementTagType + elementHeight + elementLeft + 1
const roundedValue = Math.round(product / divisor);
console.log(roundedValue);
totalSum += roundedValue;
}
const summaryArray = mouseDataArray[3]; // [totalPoints, clickSequenceScore, totalCursorDistance, totalPoints]
const sumPlusCursorDistance = totalSum + summaryArray[2];
const totalPointsPlusOne = summaryArray[0] + 1;
const ratio = sumPlusCursorDistance / totalPointsPlusOne;
const ratioPlusOne = ratio + 1;
const logRatio = Math.log(ratioPlusOne);
const scaledLog = logRatio * 4;
const ratioPlusTotalPoints = ratio + summaryArray[0];
const ratioPlusTotalPointsPlusScore = ratioPlusTotalPoints + summaryArray[1];
const modResult = ratioPlusTotalPointsPlusScore % 11;
const behaviorChecksum = Math.round(scaledLog + modResult);
return JSON.stringify(mouseDataArray);
}
```
### 例
```javascript
const checksum = computeMouseChecksum([1,[[2050,125,633,266,[609,266,105,44],3,1,50,1,1]],[3,3,318],[28,777,858,28],0,0,25]);
console.log(checksum); // → 25
```
- **Key 360** (`string`)
- Value: `""`
- Description: 収集されたウェブサイト価格合計$の解析、正規表現 `(?i)total[\S\s]{0,20}?(?:(?:(?:USD|\$)\s*)?[\d\.,]+\s*(?:USD|\$)|(?:USD|\$)\s*[\d\.,]+)` を使用。[サンプル](https://github.com/elyelysiox/recaptcha/blob/main/websitePricesTotal.js)
- **Key 1278** (`integer`)
- Value: `229.6`
- Description: 現在のランタイムタイミングを10で割った値 `Math.trunc(performance.now()) / 10`
- **Key 1422** (`boolean`)
- Value: `false`
- Description: ウェブサイトにOTP/2FAフィールドがあるかどうかを解析します。[サンプル](https://github.com/elyelysiox/recaptcha/blob/main/parseOTPFields.js)
- **Key 614** (`array`)
- Value: `[1,0,0,Infinity]`
- Description: デバイスのバッテリー情報。形式: `[level,isCharging,chargingTime,dischargingTime]`
- **Key 2033** (`array`)
- Value: `["0",-1,-1,999]`
- Description: 一部のVM定数値とVMランタイムタイミング
- **Key 1313** (`array`)
- Value: `["undefined",3]`
- Description: Android、Chromeのチェック。`[typeof window.android, Object.keys(window.chrome).length]`
- **Key 1994** (`array`)
- Value: `[2,4,53324367238]`
- Description: `[navigator.hardwareConcurrency, navigator.deviceMemory, navigator.storage.estimate().qouta]`
- **Key 1310** (`array`)
- Value: `["Google Inc. (Intel Inc.)","ANGLE (Intel Inc.,...`
- Description: WebGLレンダラー、ベンダー、総拡張数。[サンプル](https://github.com/elyelysiox/recaptcha/blob/main/webglSignals.js)
- **Key 291** (`array`)
- Value: `[1542343452,0,105002991,3556653,96784904,-731949068,-902263026,...`
- Description: ブラウザオブジェクトの特定のプロトタイプキーのハッシュ値。例: `SpeechSynthesisEvent`、`NetworkInformation`、`HTMLElement`など。[サンプル](https://github.com/elyelysiox/recaptcha/blob/main/hashBrowserProtos.js)
## リロードリクエストペイロード
このデータは、Googleが開発した構造化データを効率的かつ中立的にシリアル化する方法であるprotobuf(Protocol Buffers)を使用してシリアル化されています。```javascript
[
"rreq",
"U5VsmTDhJM1iOJUyw4DEUTYv",
"03AFcWeA5Els3SIQviW2OYCHYD4uDhKlFPG6A48z2nk74BC2vrXSRvtpP9uVkWW96kUKm7sHIr...",
null,
null,
"-383788762",
"q",
"05APQrAobTCFGtbKVY3NwExv-K_G7oqmzGyUcTXi532CBKvSJUiT49tkRSgGD__OdfVRZtrI3i...",
"submit",
null,
null,
null,
null,
null,
"6LcAbwIqAAAAAJvVAhSSJ8qzYsujc7kn1knmSgQX",
null,
"0XA4cHhALxgMF9_Kt6uze2ZTR08XAe2x8o3BrU1hbTouNf3o1cnRmYRxZW01IA0BCNC_qJykb...",
null,
null,
null,
"tbMywxNTQsODQ0XSxbMSwyOTksMTA4Nl1dLFtbMiw2MSwxMzIuNzM5OTk5OTk5ODQ2MzNdLF...",
"0aAPQrAobqMEazjp9PGLYWTgxWGGcq9k5MJNI6LFBWfTh0UkDaVobdH-InwAYsTXtxs3rH_fI",
"BDAAYAIAGEcAAUoYI4lDCKAsCJlcgB6AAJtgggoIEEOALSoQRZxSZyAJBHANCkAJQYhFJES...",
null,
null,
"W1tbNTAwNiw0M10sWzY0NjA3LDFdLFs0NTQ2NCwxXSxbMzU4MzcsMV1dXQ==",
null,
null,
]
| 値 | 説明 |
|---|---|
q | reCAPTCHA V3 チャレンジ |
fi | reCAPTCHA V2/不可視チャレンジ |
a | 音声チャレンジ |
qr |
デコード方法:```javascript atob("W1tbMywwLDgyOV0sWzEs...") // → [[[3,0,829],[1,42,863]],[[2,727,1341.300000011921]...
ペイロードには以下が含まれます:
- リソースタイミング情報
- 長時間タスクのパフォーマンスタイミング
- reCAPTCHA VM実行デルタ
- ウェブサイトのスクリプトURL
- ブラウザオブジェクト収集統計
### 基本構造```js
[
[recaptchaResources],
[tasksTiming],
[
null,
null,
null,
idleTimeoutDelta,
deltaTiming,
0,
0,
0,
],
websiteScriptsUrls,
[collectionElapsed, browserObjectsLength]
]
[ PerformanceLongTaskTiming.name == "self" ? 2 : 4, PerformanceLongTaskTiming.duration, PerformanceLongTaskTiming.startTime ]
### reCAPTCHA リソースタイミングフォーマット```js
[
resourceType,
duration,
startTime
]
| Resource |
|---|
Idx 25)このフィールドには、実行中に収集されたブラウザインタラクションイベントのBase64エンコードされたカウンターが含まれています
デコード例:```js [ [ [5006, 43], [64607, 1], [45464, 1], [35837, 1] ] ]
### イベントカウンター構造```js
[
[
[eventType, count]
]
]
[ "rresp", "", null, 120, [ "pmeta", [ "/m/013xlm", null, 3, 3, 3, null, "Tractor" ], null, [1] ], "", null, null, "", "", null, null, "", null, "", "", 0 ]
## フィールド説明
| インデックス | 名前 | 説明 |
|---|---|---|
| `0` | `rresp` | リロードエンドポイントから返される応答タイプ識別子 |
| `1` | `responseToken` | reCAPTCHA応答トークン |
| `3` | `tokenExpiration` | トークンの有効期限までの秒数 |
| `4` | `pmeta` | CAPTCHAの種類、カテゴリ、グリッドレイアウトに関する情報を含むチャレンジメタデータブロック |
| `5` | `challengeType` | CAPTCHAチャレンジの種類 |
| `8` | `usagePatternToken` | 使用パターン。`window.sessionStorage`に保存され、将来の`/reload`リクエストで再利用される |
| `9` | `challengeImageToken` | `/payload`エンドポイントからCAPTCHA画像ペイロードを取得するためのトークン |
| `12` | `humanVerificationToken` | Google reCAPTCHAの状態とブラウザのCookieに関連付けられた人間識別トークン |
| `14` | `captchaSessionToken` | 内部セッショントークン |
| `15` | `bftToken` | ... |
---
### `pmeta`構造
例:```js
[
"pmeta",
[
"/m/013xlm",
null,
3,
3,
3,
null,
"Tractor"
],
null,
[1]
]
pmeta[1] 値Idx 9(challengeImageToken)の値は、CAPTCHA画像を取得するために使用されます:```txt
https://www.google.com/recaptcha//payload
?p=
&k=
### カテゴリ識別子
| ID | カテゴリ |
|---|---|
| `/m/0pg52` | タクシー |
| `/m/01bjv` | バス |
| `/m/02yvhj` | スクールバス |
| `/m/04_sv` | オートバイ |
| `/m/013xlm` | トラクター |
| `/m/01jk_4` | 煙突 |
| `/m/014xcs` | 横断歩道 |
| `/m/015qff` | 信号機 |
| `/m/0199g` | 自転車 |
| `/m/015qbp` | 駐車メーター |
| `/m/0k4j` | 自動車 |
| `/m/015kr` | 橋 |
| `/m/019jd` | ボート |
| `/m/0cdl1` | ヤシの木 |
| `/m/09d_r` | 山 / 丘 |
| `/m/01pns0` | 消火栓 |
| `/m/01lynh` | 階段 |
## UserVerify リクエストペイロード
`/userverify` ペイロードは、ユーザーが reCAPTCHA v2 画像チャレンジを完了した後に送信されます
# ペイロード構造```
v: hsFBb1u5wWWWkWP4in1ua2cQ
c: 03AFcWeA5RIHz5mI2COQqTcLjdrC7FiPpdfkX-hB-B2iFenI...
response: eyJyZXNwb25zZSI6WzMsMSw0LDksMCwxMSwxMCwxMywxNF0....
t: 24521
ct: 24521
ch: -4007845
oc: 0ZpqzzPgYKEEaN0xpfo3v_voeVUySZK3Ktf_fLVRdhnu3yeTy4BhO...
pm: 51bGwsbnVsbCxbbnVsbCxudWxsLG51bGwsWzEwLDQuMjcwMDAwMD....
response ペイロードグリッド内でユーザーが選択した正方形のインデックス/位置を表します。
ペイロードは送信前に JWT としてエンコードされます。
```txt
0 1 2
3 4 5
6 7 8
ペイロード例:```json
{
"response": [2, 3, 6]
}
```txt
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
ペイロードの例:```json
{
"response": [2, 3, 6, 14]
}
e フィールドresponse ペイロードには e フィールドも含まれる場合があります:```json
{
"response": [2, 3, 6, 14],
"e": "bxCoiXVt49I7CTS_tNlVbGg"
}
このフィールドには、CAPTCHAボタン操作に関連する暗号化されたインタラクションメタデータが含まれています。例:
- `確認`
- `次へ`
- `スキップ`
### `e`の内部構造
復号後、構造は次のようになります:
``````txt
[[["9ffd9672"]]]
各値は、rc-button-default ボタンのクラス/アクションに対するハッシュ化された識別子を表します。
ハッシュは次の通りです:
より長いインタラクションシーケンスは次のようになります:```txt [ [ ["9ffd9672"], ["9ffd9672"], ["9ffd9672"], ["9ffd9672"] ] ]
### `oc` — 暗号化されたVMシグナル
`/reload`リクエストペイロードの`idx 16`フィールドと同じ暗号化アルゴリズムを使用し、暗号化キーはアンカー(インデックス31)`1777752103288`にロードされています。
### `pm` — テレメトリペイロード
`pm`フィールドには、`/reload`で使用されるテレメトリペイロードと同様のBase64エンコードされたテレメトリ構造が含まれています。
## アンチデバッグ/改ざん対策
- ***シンボルベースの整合性タグ***
reCAPTCHAは、整合性チェックに使用される数値を持つすべての配列とオブジェクトにSymbolキー`Symbol(jas)`を設定します。Symbolは列挙不可であり、標準的なクローン操作(JSON.stringifyなど)では不可視であるため、これらの構造を置き換えたりクローンしようとするとタグが失われ、reCAPTCHAはそれを改ざんとして検出します

- ***クロージャ変数のキャプチャ***
一部の値は意図的に外部関数でスコープされ、ネストされたコールバックやクロージャ内でのみ消費されるため、変数は使用されるスコープには決して存在しません
- ***タイミングチェック***
reCAPTCHAは実行時デバッグ検出メカニズムを組み込んでいます。コードがデバッガによって分析されていることを検出すると、デバッグセッションを再起動し、実行状態とコンテキストが失われます
- ***クラッシュソースタブ***
https://github.com/user-attachments/assets/4ae3bf68-5ae7-4adc-a0b9-36cc11b64998
このバグはChromiumを使用するブラウザで発生します。ここに示すように、ブラウザや開発者ツールが予期せず閉じる原因となるバグがいくつかあります:
https://blog.castle.io/detect-and-crash-chromium-bots-with-one-weird-trick-bots-hate-it/
https://issues.chromium.org/issues/340836884?ref=blog.castle.io
したがって、タイムアウトが発生するとこれらのバグのいずれかがトリガーされる可能性が高く、実際のユーザーフローでは起こりそうにありません
## reCAPTCHA Botguard
BotGuardはGoogleによって削除されましたが、内部でどのように動作し、他のタイプのBotGuardとどのように異なるのかに興味がある方のために少し説明します。
まず、トークン生成プロセス:VMは実行中の永続的なエラーに対してトークンを生成します。これらのエラーは、バイトコードオフセットのずれ、VMレジスタの欠落、VM状態の誤り、制御フロー整合性の低下などが原因で発生します。これらのエラーはディスパッチャによってキャプチャされ、トークンのバイトを書き込む関数を呼び出します。
VMはARX暗号を使用します。これは2013年にNSAによって作成されたアルゴリズムで、データの暗号化にSpeckに似ています。また、すべてのGoogle BotGuardで使用されています。アルゴリズムはバージョンごとに変更され、定数(3990)、演算順序、ラウンド数も変わります。次のようになります:```javascript
/*
D -> cipher state array
P -> seed
E -> byte index
*/
Vl = function(D, P, E, F, v) {
F = D[3] | 0;
D = D[2] | 0;
for (v = 0; v < 14; v++) {
E = E >>> 8 | E << 24;
E += P | 0;
E ^= D + 3990;
P = P << 3 | P >>> 29;
P ^= E;
F = F >>> 8 | F << 24;
F += D | 0;
F ^= v + 3990;
D = D << 3 | D >>> 29;
D ^= F;
}
return [P >>> 24 & 255, P >>> 16 & 255, P >>> 8 & 255, P >>> 0 & 255, E >>> 24 & 255, E >>> 16 & 255, E >>> 8 & 255, E >>> 0 & 255];
}
メインの暗号化機能には、暗号化モードと非暗号化モードの2つがあります。 暗号化モードでは、ARX Cipher、Bitwise + XORを使用してデータを暗号化し、バッファに設定します。 バッファには4つのタイプがあります:
180353304243(このタイプのボットガードでは使用されません)非暗号化モードでは、既に暗号化されたバイトをバッファに設定するだけです。```javascript // (The sequence flatten messed up the statements a bit) /* Q -> cipher state array FQ(v, c) -> derive a seed c = (z << 3) - 4 -> index FQ(v, (c | 0) + 4) -> position */ t = function(D, P, E, F, v, Q) { if (E.O == E) { P = function(h, A, c, x, z) { A = v.length; // buffer length z = (A | 0) - 4 >> 3; if (v.Jw != z) { // vm.block_index != index v.Jw = z; // set new block index c = (z << 3) - 4; x = [0, 0, Q[1], Q[2]]; try { v.zB = Vl(x, FQ(v, c), FQ(v, (c | 0) + 4)); // call ARX Cipher to generate keyStream } catch (V) { throw V; } } v.push(v.zB[A & 7] ^ h); // sets A to bits 0-7, and obtains a byte from the keystream and applies xor with a byte of the data to be encrypted }; v = Z(P, E); // get buffer if (P == 180 || P == 243 || P == 353) { Q = Z(189, E); } else { // set encripted bytes to buffer P = function(h) { v.push(h); }; } F && P(F & 255); E = D.length; for (F = 0; F < E; F++) { P(D[F]); } } }
そして、これはエラーを処理してバイトライターを呼び出す関数です。```javascript
// (The sequence flatten messed up the statements a bit)
p = function(D, P, E, F, v, Q, h, A) {
D = E[1];
A = E[2];
Q = Z(465, P) >> 3;
h.push(D, Q >> 8 & 255, Q & 255); // error code/header bytes
E.message && (D += E.message);
A = void 0;
E && E[0] === U && (E = void 0);
h = Z(244, P);
h.length == 0 && (A != void 0 && h.push(A & 255));
D = "";
E && (E.stack && (D += ":" + E.stack));
E = Z(0, P); // buffer size limit (2048)
if (!P.TB && E[0] > 3) {
D = D.slice(0, (E[0] | 0) - 3);
E[0] -= (D.length | 0) + 3; // reduce size limit
D = Pv(D);
E = P.O;
P.O = P;
try {
v = (v = Z(304, P)) && v[v.length - 1] || 95;
if (P.n3) {
// this path is never executed
(F = Z(123, P)) && F[F.length - 1] == v || t([v & 255], 123, P);
} else {
t([95], 304, P); // set byte to error buffer
}
t(O(2, D.length).concat(D), 180, P, 9); // set bytes to main buffer
} finally {
P.O = E;
}
}
}
At the end of the execution, the VM calls the main function that prepares the payload with these buffers and generates the token, which is a signature. Unlike other BotGuard VM, this VM does not have a fingerprinting system, Google Botguard nor does it perform these error-emitting + writing bytes, and is much simpler and easier to reverse engineer.
This repository is exclusively for educational and research purposes. The code, techniques, and concepts presented here are intended for the academic study and understanding of the topics covered.
Hashed: true
説明: すべての <HEAD> ノードの 40 文字 base64 ブルームフィルタフィンガープリント。各子要素を走査してタグ名、属性、テキストコンテンツを収集し、シリアライズして djb2 ハッシュを実行します。
各ダイジェストは BitHash(240 ビット, 7 ラウンド, 最大 25 ノード) に投入され、40×6 のグリッドにビットを設定し、各 6 ビットセグメントを base64 文字にエンコードします。reCAPTCHA 自身のスクリプトタグは src に対する動的正規表現により除外されます。
Idx 17 (integer)
2falseIdx 18 (string)
a2hyNTFuNDI4NnA3falseIdx 27 (string)
location.originfalseIdx 28 (boolean)
falsefalsewindow.parent != window ? true : window.frameElement != null ? true : falseIdx 29 (string)
e2a3cd70truegrecaptcha.execute 関数の本体を SHA-256 でハッシュ化したもの。サンプルIdx 30 (integer)
0falsehttps://www.gstatic.com/recaptcha/releases/<version>/ を含むスクリプトのインデックス。サンプルIdx 31 (string)
AAgkAQI0SBtruedocument.cookie のキーをハッシュ化したもの。サンプルIdx 32 (string)
""falsedocument.referrer。Idx 33 (integer)
Value: 2
Hashed: false
説明: reCAPTCHA ボックスがレンダリングされる要素。
// 例: grecaptcha.execute('.grecaptcha') -> この div
// 基本的に、その div の文書内での番号または深さを返します。
// 例: html > body > main > form > fieldset > div.recaptcha.form-field
// 5 4 3 2 1 0
// out = 5
nM = document.getElementsByClassName('grecaptcha-badge')[0] // または document.getElementsByClassName('g-recaptcha')[0] v2
let count = 0;
for (; nM = nM.parentElement || null;) {
count++;
}
const result = count;
Idx 34 (string)
AAAAAAAAAAtrue<INPUT> 属性名をハッシュ化したもの。サンプルIdx 35 (string)
0,DIV,f0c7414etruedocument.activeElement を解析し、正規表現 /buy|pay|place|order|donate|purchase/i を使って textContent, classNames, id から購入要素かどうかを判定。サンプルIdx 36 (string)
h3, h2 または http/1.1falsenextHopProtocol 値 performance.getEntriesByType("navigation")[0].nextHopProtocolIdx 37 (integer)
-1falseperformance.timing.unloadEventStartIdx 38 (integer)
96falseperformance.timing.domainLookupStart - performance.timing.domainLookupEndIdx 39 (integer)
0falseperformance.navigation.typeIdx 40 (integer)
0falsewindow.scrollY または document.defaultView.pageYOffsetIdx 41 (string)
DIV,a08cd360true:hover 要素。最後の要素を取得し、tagName, classNames, id をハッシュ化。サンプルIdx 42 (string)
9,e3b0c442trueIdx 44 (string)
2v591z63wqtrue:hover 要素、document.activeElement、すべての <INPUT> 要素のハッシュ、location.url、window.scrollY。例:const element = document.querySelectorAll(":hover");
const current = element[element.length - 1];
const result = [
deriveSignalCode(hash(current)),
deriveSignalCode(hash(document.activeElement)),
deriveSignalCode(hash(document.querySelectorAll('input'))),
deriveSignalCode(location.url),
deriveSignalCode(String(window.scrollY))
].join('')
Idx 45 (integer)
4falsewindow.history の長さ。Idx 46 (string)
https://static.kogstatic.com/0000/34c...falseline:column の情報。Idx 47 (integer)
0falsewindow.getSelection().toString().length || 0Idx 49 (string)
h2-0falsenextHopProtocol を取得し、duration がゼロかどうかを判定します。結果を protocol-isZero の形式で返します。サンプルIdx 50 (array)
Value: [1,0,null,1,1,["805b1z63wq"],"MWc2MzZwMnR0ZHNkMw==",0,null,[[1]]]
Hashed: true
説明: ユーザーの動作を含みます。ハッシュ化された :hover 要素と、別の :hover 要素が収集されるたびに増加するタイムアウト。ユーザーのアクティベーションを分析し、(10 * IsActive + IsBeenActive) を計算して、ユーザーがページとインタラクションした回数や現在もページ上に存在するかを累積します。
基本フォーマット:
[
count,
timeout,
null,
timeoutMultiplier,
transitionCount,
[ elementsHoverHashed ],
sessionId,
userActivationScore,
null,
[ [ flags ] ]
]
Idx 51 (array)
[0]falsedocument.body.innerText から "try again", "incorrect", "invalid", "declined" の単語と一致するものを検索し、見つかった一致の総数を返します。それ以外の場合は 0 を返します。サンプルIdx 52 (integer)
11false10 * navigator.userActivation.isActive + navigator.userActivation.hasBeenActiveIdx 53 (integer)
Value: 4
Hashed: false
説明: 現在のウェブサイト URL を取得し、文字配列に変換して 100 文字に切り詰め、その後文字列に戻します。サンプル
その切り詰めた文字列の長さが偶数の場合は 5、奇数の場合は 4 になります。
Idx 54 (boolean)
falsefalsewindow.document.hiddenIdx 55 (array)
[[[1,"2v"],[1,"9z"],[1,"z8"],[1,"us"],[1,..falseIdx 56 (string)
-1,-1falsewindow.opener のチェック。null の場合は "-1,-1" を返します。サンプルIdx 57 (string)
Value: www.gstatic.com,_,static.kogstatic.com,www.google.com,www.googletagmanager.,...
Hashed: false
説明: document.scripts に存在するすべての <SCRIPT> 要素の src からホストを収集します。サンプル
各 <SCRIPT> について:
要素に src 属性がある場合 (hasAttribute("src"))、src の値を取得し、URI タイプの正規表現 (nd) でパースし、ホスト部分のみを抽出します (正規表現のキャプチャグループ 3)。
<SCRIPT> に src 属性がない場合 (インラインスクリプト)、プレースホルダー "_" が使用されます。
Idx 58 (string)
mapslitepromosdismissed1falsewindow.localStorage のキー。Idx 59 (string)
""falsewindow.nameIdx 60 (string)
https://www.kogama.com,https://www.google.com,https://js.stripe.comfalseIdx 61 (array)
[0,"AAAAAAAAAA","AAAAAAAAAA"]trueMutationObserver によって記録された属性名とターゲット要素タイプのハッシュ。サンプルIdx 62 (string)
document.titlefalseIdx 63 (array)
Value: []
Hashed: false
説明: Cookie の値からタイムスタンプ (1[2-9] で始まる 12-13 桁の数字、典型的には ~2008-2099 年のエポックミリ秒) を抽出します。サンプル
見つかったすべての ID に対して次の値を累積します: カウント、最小値、最大値、平均値。
最終的な値の結果は配列 [count, min, max, avg] です。
Idx 64 (integer)
55557falseIdx 65 (string)
sha384-3qctruehttps://www.google.com/recaptcha/api.js?render= に設定された reCAPTCHA スクリプトのインテグリティ (10 文字に切り詰め)。Idx 67 (array)
[screen.width, screen.height, screen.availHeight, window.innerWidth, window.innerHeight, window.outerHeight]falseIdx 68 (array)
[300,null,1777685870223]false[new Date().getTimezoneOffset(), null, Date.now()]Idx 69 (string)
09AKhCRwjrDFiHsrRA--o23-HB-eWqOtk_XQ-rLE1...falseIdx 70 (array)
Value: [null,null,"","",null,"1l0fl"]
Hashed: false
説明: 合計金額 (例: Total: $50.00 や Total 150.00 EUR) を抽出します。サンプル
document.innerText から、正規表現を使用して通貨記号またはコードと数値額を検索します:
total[\S\s]{0,20}?(((R\$|\$|€|£|USD|EUR)\s*[\d\.,]+)|[\d\.,]+\s*(€|USD|EUR))`
total → 正確な単語 "total" を検索
[\S\s]{0,20}? → 0 から 20 文字の介在文字 (スペース、コロン、改行など) を検索してから数値を見つける
(((R\$|\$|€|£|USD|EUR)\s*[\d\.,]+)|[\d\.,]+\s*(€|USD|EUR)) → 金額をキャプチャするメインブロックで、2 つの別々のオプションに分かれています
Idx 71 (array)
[jsHeapSizeLimit,usedJSHeapSize,totalJSHeapSize]falseIdx 72 (array)
Value: [[["Google Chrome","147"],["Not.A/Brand",...
Hashed: false
説明: userAgent データの配列 navigator.userAgentData。モバイルかどうかのフラグとプラットフォーム。サンプル:
[
navigator.userAgentData.brands.map(b => [b.brand, b.version]),
navigator.userAgentData.mobile ? 1 : 0,
navigator.userAgentData.platform
]
Idx 73 (array)
[[null,2,0,"Mozilla/5.0 (Windows NT 10.0;...falseIdx 77 (integer)
nullfalseIdx 78 (string)
""false| インデックス | 値 | 説明 |
|---|
0 | rreq | リクエストタイプ識別子 |
1 | U5VsmTDhJM1iO... | reCAPTCHA バージョン |
2 | 03AFcWeA5Els3... | /anchor エンドポイントから取得した検証トークン |
5 | -383788762 | シリアル化されたフィンガープリントペイロード全体をハッシュ化したもの、サンプル |
6 | q | 実行中のチャレンジまたはリクエストモードを示す |
7 | 05APQrAobTCFG... | 使用パターン。使用履歴と以前に解決されたチャレンジパターンを含む。有効な場合、スコアを大幅に向上させることができる |
8 | submit | 検証時にユーザーがページ上で実行している特定のサイトアクション(例: signin、register) |
14 | 6LcAbwIqAAAA... | ウェブサイトキー |
16 | 0XA4cHhALxgM... | アンカー(インデックス 18)からの暗号化キー 1777669303203 を使用して、シリアル化されたフィンガープリントペイロード全体を暗号化したもの |
20 | tbMywxNTQsOD... | VM タイミングデルタ、リソースタイミング、収集されたブラウザオブジェクト統計、ウェブサイトスクリプト URL を含むテレメトリ構造の Base64 エンコード |
21 | 0aAPQrAobqME... | 以前に解決された CAPTCHA に関連付けられたトークン。セッション継続性と信頼相関に使用 |
22 | BDAAYAIAGEcA... | すべてのブラウザオブジェクトキーをハッシュ化したもの |
25 | W1tbNTAwNiw... | マウスの動き、クリック、キーボード、フォーカス変更などのユーザーインタラクションイベントのカウンターを Base64 エンコードしたもの |
| クイックレスポンス(新規) |
| Type |
|---|
recaptcha/api.js | 3 |
recaptcha/releases/<version> | 1 |
https://www.google.com/recaptcha/api2/anchor | 2 |
https://www.google.com/recaptcha/api2/bframe | 4 |
| ハッシュ | イベントタイプ |
|---|
5006 | pointermove |
64607 | pointerdown |
45464 | pointerup |
31617 | keydown |
37178 | keyup |
35837 | focusin |
| 位置 | 値 | 説明 |
|---|
0 | /m/013xlm | 対象オブジェクトクラスの内部カテゴリ識別子 |
2 | 3 | グリッド列数 |
3 | 3 | グリッド行数 |
5 | null | 予約済みまたはオプションのメタデータフィールド |
6 | "Tractor" | テキストラベル |
| タイプ | 説明 |
|---|
imageselect | 標準画像選択CAPTCHA |
tileselect | タイルベースの動的画像チャレンジ |
dynamic | 選択後にタイルが再読み込みされる動的チャレンジ |
multicaptcha | 複数ステップのCAPTCHAチャレンジ |
audio | 音声ベースのアクセシビリティチャレンジ |
nocaptcha | チェックボックスのみの検証フロー |
doscaptcha | 不正使用がある場合CAPTCHAを拒否 |
| フィールド | 名前 | 説明 |
|---|
v | recaptchaVersion | reCAPTCHA バージョン |
c | challengeToken | /replaceimage または以前の /userverify リクエストから返されるチャレンジ状態トークン |
response | 選択されたタイルのインデックスと追加の操作メタデータを含むエンコードされたペイロード | |
t | challengeElapsed | チャレンジが最初に読み込まれてからの経過時間 |
ct | completionTime | ユーザーが CAPTCHA を解いて送信するのにかかった合計時間 |
ch | ocHash | シリアライズされた oc ペイロード全体のハッシュ、サンプル |
oc | encryptedVmSignals | reCAPTCHA VM から収集された暗号化されたシグナル。こちらを参照。 |
pm | telemetryPayload | Base64 エンコードされたテレメトリ構造。VM タイミングデルタ、リソースタイミング、収集されたブラウザオブジェクト統計、およびウェブサイトスクリプトメタデータを含む。 |