
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/main/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: