
توثيق والهندسة العكسية لـ reCAPTCHA
يحتوي هذا المستودع على تحليل تقني لنظام مكافحة الروبوتات من جوجل (reCAPTCHA) مع التركيز على:
@g_recaptcha@lyxlobyxيُعد reCAPTCHA أحد أنظمة مكافحة الروبوتات التي تمتلك أكثر تقنيات التعتيم تطورًا، حيث يستخدم سلسلة من التحويلات التي تجعل الكود أقل قابلية للقراءة وأكثر صعوبة في الهندسة العكسية. يمكن معالجة معظم عمليات التعتيم بسهولة باستخدام شجرة الصياغة المجردة (AST)، لكن بعضها يُنفَّذ في وقت التشغيل، مما يجعل AST عديم الفائدة في هذه الحالة. يتم أيضًا تطبيق تعدد الأشكال (Polymorphism) على الكود لتغيير بنيته في كل إصدار من البرنامج النصي. على سبيل المثال، لا ينفذ الكود الإجراء مباشرة، بل يستخدم كائنات أو دوال تغيّر شكلها
تعبيرات التسلسل (Sequence Expressions)
يتم تسطيح الكود عن طريق تحويل كل عبارة كتلة إلى تعبير مستمر مفصول بفواصل، ويمكن أن يظهر في عبارات if، ووسائط الدوال، وحتى داخل الكائنات

الحساب المختلط بين العمليات الحسابية والبتية (Mixed Boolean Arithmetic)
يدمج العمليات الحسابية (الجمع، الطرح، الضرب) مع العمليات البتية (AND، OR، XOR، NOT) لإخفاء المنطق الأصلي، على سبيل المثال -2 * ~(h & H) + -2 + (h ^ H)
جدول الدوال غير المباشر (Indirect Function Table)
يتم بناء كل دالة داخل جدول، ويتم استدعاؤها باستخدام فهرسها، مثل functions[index](https://github.com/elyelysiox/recaptcha/blob/HEAD/args)
مصفوفة الثوابت المضمنة (Inline Constant Array) يتم تعيين حرفية مصفوفة محلية بشكل مضمن، في منتصف التعبير، وتقوم المصفوفة بتجميع الثوابت (أرقام، نصوص) التي يُعاد استخدامها في جميع أنحاء جسم الدالة عبر الوصول بالفهرس
// b = [14, 1, "call"] assigned inline inside a sequence expression
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
}
إرسال الدوال المتعدد (Function Multiplexing) يتم دمج عدة دوال مختلفة منطقيًا في دالة واحدة، باستخدام معامل رقمي كمحدد للكتلة. يتم تحديد الكتلة النشطة من خلال تقييم المعامل مقابل شروط بتية. يمرر المتصلون قيمة رقمية حرفية كمحدد
function(N, y, U, Y, h, H, m, C, u) {
C = [26, 47, 6];
// block 1
if ((N - 2 ^ 14) < N && (N - C[2] | 28) >= N) {
// convert value to string logic
}
// block 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;
}
التفرع عبر المعاملات المنطقية (Logical Operator Branching) يستبدل عبارات if وكتل if/else بتقييم الاختصار للمعاملات المنطقية، محولًا تدفق التحكم إلى تعبيرات. وعند دمجه مع تعبيرات التسلسل، تظهر فروع متعددة كتعبير واحد مستمر مفصول بفواصل
// if (a) { block }
a && (block)
// if (!a) { block }
a || (block)
// if (a) { x } else { y }
a ? x : y
// combined with CFF and sequence expressions:
(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), ...)),
ربط ثوابت الدوال الأصلية (Bind Native Methods Constants) يربط الدوال الأصلية للمتصفح بمستقبلاتها الأصلية، ويخزنها كثوابت لمنع العبث بها
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)
الكود الميت (Dead Code) يتم حقن كتل برمجية يتعذر الوصول إليها أو غير مستخدمة في جميع أنحاء الملف، مما يزيد حجمه إلى أكثر من 60,000 سطر، وهذا يجعل التحليل الثابت والهندسة العكسية القائمة على نماذج اللغة الكبيرة (LLM) صعبة
تسطيح تدفق التحكم (Control Flow Flattening) يحول كل جزء من الكود (التعاريف والحلقات) إلى آلة حالة مسطحة. يخفي منطق التنفيذ الأصلي عن طريق تمرير جميع الكتل البرمجية عبر كتلة "موزع" مركزية
يمكن أن تتغير أشكال الموزعات؛ بعضها يحتوي على 2-3 متغيرات حالة، ويتغير نوع الحلقة/الشرط. تبدو كما يلي

هذا CFF بمتغيرَي حالة، أحدهما يتعامل مع كتلة catch والآخر مع كتلة try.
تجمع السلاسل المشفرة (Encrypted String Pool) جميع القيم النصية الحرفية (واجهات برمجة تطبيقات DOM، خصائص المتصفح، قيم CSS، رسائل الخطأ، إلخ) مشفرة في تجمع نصي ضخم واحد. تستخدم دالة فك التشفير بذرة وشيفرة XOR قائمة على LCG لاستخراج كل سلسلة في وقت التشغيل
يوجد أكثر من 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 with running key
b += String.fromCodePoint(J),
F += J; // accumulate key
return G = b;
}
// call sites pass a seed to locate and decrypt each string
Z[23](64, 4, 54961, 103)() // → "lang"
Z[23](66, 4, 54961, 103)() // → "addEventListener"
Z[23](32, 12, 20287, 852)() // → "inline-block"

مكرر القيم ذو الحالة (Stateful Value Iterator) يستخدم reCAPTCHA دالة ذات حالة تُرجع سلسلة من الكائنات والقيم في وقت التشغيل (مثل window، document.body، ثوابت رقمية) بترتيب ثابت، كل استدعاء يقدم مؤشرًا داخليًا، واستدعاؤها خارج التسلسل أو عدد مرات أكثر من اللازم يفسد جميع القراءات اللاحقة. تعمل آلية مهلة على إبطال الحالة بعد فترة زمنية ثابتة، وتُرجع null لأي قراءات متأخرة
// sequential calls return different values:
c() // → window
c() // → document.body
c() // → 123
c() // → null (timeout expired)
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
جدول الدوال المحسوب (Computed Function Table)
يشبه جدول الدوال غير المباشر، لكن هنا يتم حساب فهرس الدالة المطلوب استدعاؤها في وقت التشغيل باستخدام بذرة، عبر XOR ومعامل القسمة (Modulus)
c = ((Q ^ no | U[1]) >> 5) + no
A = mN[(c % U[2] + U[2]) % U[2]] // mN is the function table (50+ functions)
q[29](5, 6977) // seed=6977 → index resolves to function at mN[X]
q[29](53, 6187) // seed=6187 → different index, different function

تشفير القيم في وقت التشغيل (Runtime Value Encryption)
بعض القيم (معلمات إعدادات captcha، معلمات الإرساء، إلخ) لا تُخزن أبدًا كنص صريح؛ يتم تشفيرها فور جمعها ولا يتم فك تشفيرها إلا في وقت الاستخدام، ولها بادئة B في البداية

تعتيم تدفق التحكم غير المتزامن (Async Control Flow Obfuscation)
يتم تحويل المنطق المتزامن إلى آلات حالة قائمة على المولدات (generators) ملفوفة في سلاسل وعود (Promises) متكررة، أي تتبع قيمة عبر المُنقح (debugger) يجبرك على التنقل عبر معالجات غير متزامنة متعددة، مما يفقد سياق التنفيذ الأصلي عند كل حد .then()
مكونات تهيئة reCAPTCHA``` ar: <WidgetInit?> k: co: hl: v: size: sa: anchor-ms: execute-ms: cb:
### الاستجابة
تحتوي الاستجابة على:
- تصميم نافذة iframe الخاصة بـ CAPTCHA
- Anchor token المستخدم للتحقق من الحمولة (/reload)
- التكوين الرئيسي للتهيئة، الذي يتم تنفيذه في طريقة `recaptcha.anchor.Main.init` لاستلامه في recaptcha_en.js
### البنية:
ملاحظة: تمت إزالة 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]
هذا يمثل:
- ترتيب التنفيذ
- خط أنابيب الجمع
- تسلسل توليد الإشارات
### أكواد إشارات البصمة واشتقاق المفتاح
يحوّل إشارات البصمة إلى مفاتيح تشفير حتمية عبر خط أنابيب اشتقاق متعدد المراحل
كل قيمة بصمة تمر بما يلي:
- يتم تطبيعها
- يتم ترميزها في رمز إشارة مضغوط
- يتم تحويلها إلى مفتاح تشفير رقمي
- يتم تشفيرها باستخدام المفتاح المشتق
العملية حتمية، بمعنى أن نفس قيمة الإدخال تولّد دائمًا نفس رمز الإشارة ونفس مفتاح التشفير.```
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)
القيمة: 3ccb
التجزئة: true
الوصف: يُنشئ مفتاح HMAC من window.localStorage.getItem("rc::a ") + "6d" المحوَّل إلى بايتات، ويحسب HMAC-SHA256(siteKey) باستخدام هذا المفتاح، ويعيد أول 4 أحرف ست عشرية من النتيجة.
قيمة rc::a هي base64 مولّد عشوائيًا.
Idx 5 (integer)
window.localStorage.length * 2falsewindow.localStorage مضروبًا في 2Idx 16 (string)
القيمة: yM5Us/j/fn6EDgtmPlP4Pxj605nMJN9dRYHyy5Mn
قد تكون بعض إشارات reCAPTCHA غير متاحة أو يفشل جمعها (بسبب مهلات متعلقة بتصحيح الأخطاء). في هذه الحالات، يتم ملء الإشارة المفقودة بقيمة مشفرة بتنسيق base64 مولّدة عشوائيًا. على سبيل المثال:``` ["CMXZyamk3ZHNjdGsyaQ==", 3249, 591]
بمجرد اكتمال بناء البصمة، يتم تسلسلها إلى سلسلة نصية وتشفيرها باستخدام مفتاح التشفير المحمّل من حقل الإرساء (الفهرس 18). يتم بعد ذلك تخزين النتيجة المشفرة في حقل الفهرس `16` في حمولة `/reload`.
## إشارات VM
فيما يلي قيم المتصفح التي تم الحصول عليها بواسطة جهاز reCAPTCHA الافتراضي الداخلي، بالإضافة إلى مفتاح الإشارة. لا تظهر بعض القيم في البصمة النموذجية لأن الجهاز الافتراضي يستخرج قيمًا معينة فقط من البايت كود الخاص بالتهيئة. لذلك، سيتم عرض قيم أخرى. لمزيد من التفاصيل، انظر [هنا](https://github.com/elyelysiox/recaptcha-vm)
تنسيق الإشارة الأساسي:```
[
null,
collectorElapsed,
encryptElapsed,
value
]
حيث تعني collectorElapsed المدة (بالملي ثانية) التي استغرقها المجمِّع للحصول على القيمة
وتعني encryptElapsed المدة (بالملي ثانية) التي استغرقها تشفير القيمة.
تُقاس هذه الأوقات أثناء تنفيذ 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]" ]
- **المفتاح 417** (`string`)
- القيمة: `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36...`
- الوصف: User-Agent كامل للمتصفح
- **المفتاح 727** (`array`)
- القيمة: `[]`
- الوصف: كتل أسعار المنتجات، تحتوي على أسعار المنتجات التجارية في الموقع، وقد تظهر في مواقع الأسواق مثل Amazon وeBay وAliExpress وغيرها، [مثال](https://github.com/elyelysiox/recaptcha/blob/main/findProductPricesBlock.js)
- **المفتاح 150** (`array`)
- القيمة: `[\"Join And Get Free Trial!\",\"\",\"Captcha Solving Service\",\"Prod...`
- الوصف: روابط مستخرجة من عناصر `<a>` في الموقع، ونادرًا ما يستخرج VM هذه القيم
- **المفتاح 545** (`boolean`)
- القيمة: `false`
- الوصف: `navigator.webdriver`
- **المفتاح 370** (`integer`)
- القيمة: `0`
- الوصف: أقصى عدد لنقاط اللمس في الجهاز `navigator.maxTouchPoints`
- **المفتاح 779** (`array`)
- القيمة: `[null,null,null,null,"false"]`
- الوصف: يستخرج البيانات من حقول الشحن/الفوترة، [مثال](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 لكل عنصر
ثلاث مراحل: حقول إدخال نصية، عبارات SELECT، وخانات اختيار
- **المفتاح 659** (`array`)
- القيمة: `[[[0,921],[1,2053]],[[235054,1,1,1],[164277,3,4,1]],2,39]`
- الوصف: يحتوي على بيانات العناصر التي تم الضغط عليها في الصفحة بالتنسيق `[[[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 هي درجة سلوكية مضغوطة مشتقة من بيانات تفاعلات المستخدم المجمعة.
لكل تفاعل:
- تتم زيادة مؤشر التفاعل بمقدار واحد
- يُدمج الطابع الزمني مع مؤشر التفاعل المعدَّل
- يُختزل تجزئة العنصر باستخدام عملية modulo
- تُجمع النتيجة في درجة تراكمية
---
```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
```
- **المفتاح 959** (`array`)
- القيمة: `[[[0,0,979]],1,0]`
- الوصف: يحتوي على حركات التمرير المجمعة خلال جلسة الصفحة
### التنسيق الأساسي
```
[ [ [ scrollX, scrollY, timestamp ] ], count, behaviorChecksum ]
```
- **المفتاح 895** (`array`)
- القيمة: `[[[1,0]]]`
- الوصف: يتتبع ` VisibilityStateEntry` حالة رؤية الصفحة، موضحًا ما إذا كان المستخدم يشاهد الصفحة حاليًا أو انتقل بعيدًا عنها، بالتنسيق `[[[isVisible, startTime]]]`
- **المفتاح 1092** (`array`)
- القيمة: `[886,2300,262.2099999997952,392.7600000009595,2050.2399999993577]`
- الوصف: أداء reCAPTCHA، وPerformanceNavigationTiming وPerformanceEventTiming، بالتنسيق `[vmStart,vmEnd,domContentLoadedEventEnd,loadEventEnd,firstUserInteractionTime]`
- **المفتاح 41** (`array`)
- القيمة: `[[[1123,0,0]]]`
- الوصف: ClearTimeout
- **المفتاح 43** (`array`)
- القيمة: `[[[1123,0]]]`
- الوصف: ClearTimeout
- **المفتاح 549** (`array`)
- القيمة: `[0,null,null,null,null,null,null]`
- الوصف: KeyboardEvent، المفاتيح المحسوبة + الطوابع الزمنية
- **المفتاح 352** (`array`)
- القيمة: `1,[[2050,125,633,266,[609,266,105,44],3,1,50,1,1]],[3,3,318],...`
- الوصف:
يحتوي الهيكل على:
- توقيت حركة الماوس
- إحداثيات المؤشر
- مدد النقر
- أبعاد العنصر المضغوط
- معلومات نوع المؤشر
- مقاييس الضغط
- مسافة انتقال المؤشر
- إحصائيات التوقيت السلوكية
### التنسيق الأساسي:
```
[
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`
### خوارزمية المجموع الاختباري للسلوك
لكل حدث ماوس:
- تُضخَّم مدة النقر
- تُدمج النتيجة مع الطابع الزمني للحدث
- تُخلط إحداثيات المؤشر وأبعاد العنصر معًا
- تُحسب نسبة موزونة
- تُقرَّب النسبة وتُجمَع
بعد معالجة جميع الأحداث:
- تُدمج الدرجة المتراكمة مع إجمالي مسافة المؤشر
- تُطبَّع النتيجة باستخدام عدد النقاط المجمعة
- يُطبَّق تحويل لوغاريتمي
- تُدمج إحصائيات حركة إضافية
- تُختزل القيمة النهائية باستخدام عملية modulo
- تُقرَّب النتيجة إلى درجة عددية صغيرة
---
```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
```
- **المفتاح 360** (`string`)
- القيمة: `""`
- الوصف: تحليل الإجمالي المُجمَّع لأسعار الموقع بالدولار ($) باستخدام تعبير نمطي ``(?i)total[\S\s]{0,20}?(?:(?:(?:USD|\$)\s*)?[\d\.,]+\s*(?:USD|\$)|(?:USD|\$)\s*[\d\.,]+)``، [مثال](https://github.com/elyelysiox/recaptcha/blob/main/websitePricesTotal.js)
- **المفتاح 1278** (`integer`)
- القيمة: `229.6`
- الوصف: قسمة توقيت وقت التشغيل الحالي على 10 `Math.trunc(performance.now()) / 10`
- **المفتاح 1422** (`boolean`)
- القيمة: `false`
- الوصف: تحليل ما إذا كانت هناك حقول OTP/2FA في الموقع، [مثال](https://github.com/elyelysiox/recaptcha/blob/main/parseOTPFields.js)
- **المفتاح 614** (`array`)
- القيمة: `[1,0,0,Infinity]`
- الوصف: معلومات بطارية الجهاز، بالتنسيق `[level,isCharging,chargingTime,dischargingTime]`
- **المفتاح 2033** (`array`)
- القيمة: `["0",-1,-1,999]`
- الوصف: بعض القيم الثابتة لـ VM وتوقيت وقت تشغيل VM
- **المفتاح 1313** (`array`)
- القيمة: `["undefined",3]`
- الوصف: فحوصات Android وChrome، `[typeof window.android, Object.keys(window.chrome).length]`
- **المفتاح 1994** (`array`)
- القيمة: `[2,4,53324367238]`
- الوصف: `[navigator.hardwareConcurrency, navigator.deviceMemory, navigator.storage.estimate().qouta]`
- **المفتاح 1310** (`array`)
- القيمة: `["Google Inc. (Intel Inc.)","ANGLE (Intel Inc.,...`
- الوصف: مُعرض WebGL والمورّد وإجمالي الامتدادات، [مثال](https://github.com/elyelysiox/recaptcha/blob/main/webglSignals.js)
- **المفتاح 291** (`array`)
- القيمة: `[1542343452,0,105002991,3556653,96784904,-731949068,-902263026,...`
- الوصف: تجزئة مفتاح النماذج الأولية (Prototypes) المحددة لكائنات المتصفح، مثل `SpeechSynthesisEvent` و`NetworkInformation` و`HTMLElement` وغيرها، [مثال](https://github.com/elyelysiox/recaptcha/blob/main/hashBrowserProtos.js)
## حمولة طلب إعادة التحميل
تُسلسَل هذه البيانات باستخدام protobuf (Protocol Buffers)، وهي طريقة فعّالة ومحايدة لتسلسل البيانات المنظمة، طورتها Google.```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/Invisible |
a | تحدي صوتي |
Idx 20)للفك:```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
]
| الموارد |
|---|
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` | الرمز المستخدم لاسترجاع حمولة صورة CAPTCHA من نقطة نهاية `/payload` |
| `12` | `humanVerificationToken` | رمز تعريف بشري مرتبط بحالة Google reCAPTCHA وملفات تعريف الارتباط في المتصفح |
| `14` | `captchaSessionToken` | رمز جلسة داخلي |
| `15` | `bftToken` | ... |
---
### بنية `pmeta`
مثال:```js
[
"pmeta",
[
"/m/013xlm",
null,
3,
3,
3,
null,
"Tractor"
],
null,
[1]
]
pmeta[1]تُستخدم القيمة عند Idx 9 (challengeImageToken) لاسترجاع صورة الكابتشا:```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 مثل:
- `Verify`
- `Next`
- `Skip`
### البنية الداخلية لـ`e`
بعد فك التشفير، يبدو الهيكل كما يلي:```txt
[[["9ffd9672"]]]
كل قيمة تمثل معرّف تجزئة لفئة/إجراء الزر rc-button-default
التجزئة هي:
قد تبدو تسلسلات التفاعل الأطول كما يلي:```txt [ [ ["9ffd9672"], ["9ffd9672"], ["9ffd9672"], ["9ffd9672"] ] ]
### `oc` — إشارات VM المشفرة
يستخدم نفس خوارزمية التشفير المستخدمة في حقل `idx 16` من حمولة طلب `/reload`، مع مفتاح التشفير المُحمَّل في المرساة (الفهرس 31) `1777752103288`
### `pm` — حمولة القياس عن بُعد
يحتوي حقل `pm` على بنية تليمترية مشفرة بـ Base64 مماثلة لحمولة القياس عن بُعد المستخدمة في `/reload`.
## مكافحة التصحيح/العبث
- ***وسم التكامل القائم على Symbol***
تُضيف reCAPTCHA مفتاح Symbol باسم `Symbol(jas)` إلى كل مصفوفة وكائن بقيمة رقمية تُستخدم كفحص تكامل. ولأن الرموز (Symbols) غير قابلة للتعداد وغير مرئية لعمليات الاستنساخ القياسية (مثل JSON.stringify)، فإن أي محاولة لاستبدال هذه البنيات أو استنساخها تُفقد الوسم، وهو ما تكتشفه reCAPTCHA كعبث

- ***التقاط متغيرات الإغلاق (Closure)***
بعض القيم تكون مخزّنة عمدًا في نطاق دالة خارجية ولا يُستهلك إلا داخل عمليات استدعاء متداخلة أو إغلاقات، وبالتالي لا يوجد المتغير أبدًا في نفس النطاق الذي يُستخدم فيه
- ***فحوصات التوقيت***
تتضمن 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
لذلك، من المرجح أن أحد هذه الأخطاء يُفعَّل عند حدوث انتهاء المهلة، لأنه على الأرجح ليس شيئًا قد يحدث في تدفق مستخدم حقيقي
## Botguard الخاص بـ reCAPTCHA
على الرغم من أن Google أزالت BotGuard، سأشرح قليلاً عن كيفية عمله داخليًا لمن يهتمون بمعرفة كيف يبدو، ومدى اختلافه عن الأنواع الأخرى من botguard
أولًا، عملية توليد التوكن: تولّد VM رموزًا (tokens) للأخطاء المستمرة أثناء التنفيذ. يمكن أن تكون هذه الأخطاء ناتجة عن انحرافات في إزاحة البايت كود (bytecode offset)، أو سجلات VM مفقودة، أو حالة VM غير صحيحة، أو ضعف سلامة تدفق التحكم. تلتقط وحدة التوزيع (dispatcher) هذه الأخطاء، وتستدعي دالةً تكتب بايتات التوكن.
تستخدم VM خوارزمية ARX Cipher، وهي خوارزمية أنشأتها وكالة الأمن القومي (NSA) في عام 2013، تشبه 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];
}
دالة التشفير الرئيسية لها وضعان: تشفير وعدم تشفير. وضع التشفير يستخدم ARX Cipher و Bitwise + XOR لتشفير البيانات ووضعها في مخزن مؤقت. هناك 4 أنواع من المخازن المؤقتة:
180353304243 (غير مستخدم في هذا النوع من botguard).وضع عدم التشفير فقط يقوم بتعيين البايتات المشفرة بالفعل إلى المخزن المؤقت.```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;
}
}
}
في نهاية التنفيذ، تستدعي الـ VM الدالة الرئيسية التي تُحضّر الحمولة باستخدام هذه المخازن المؤقتة وتولّد التوكن، وهو توقيع. على عكس BotGuard VM الأخرى، لا يحتوي هذا الـ VM على نظام بصمة، ولا Google Botguard، ولا يقوم بعمليات إصدار الأخطاء + كتابة البايتات، وهو أبسط بكثير وأسهل في الهندسة العكسية.
هذا المستودع مخصص حصريًا للأغراض التعليمية والبحثية. الكود والتقنيات والمفاهيم المعروضة هنا مخصصة للدراسة الأكاديمية وفهم الموضوعات التي يغطيها.
التجزئة: true
الوصف: بصمة Bloom filter من نوع base64 بطول 40 حرفًا لجميع عُقد <HEAD>. يتنقل عبر كل عنصر فرعي لجمع أسماء الوسوم والسمات ومحتوى النص، ثم يُسلسِل النتيجة ويُمررها عبر تجزئة djb2.
يتم إدخال كل ملخص في BitHash(240 bits, 7 rounds, max 25 nodes) يضبط البتات عبر شبكة 40×6، ثم يرمّز كل مقطع من 6 بتات كحرف base64. تُستبعد وسوم سكربتات reCAPTCHA الخاصة عبر regex ديناميكي على 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، نموذجIdx 30 (integer)
0falsehttps://www.gstatic.com/recaptcha/releases/<version>/، نموذجIdx 31 (string)
AAgkAQI0SBtruedocument.cookie المجزوءة، نموذجIdx 32 (string)
""falsedocument.referrer.Idx 33 (integer)
القيمة: 2
التجزئة: false
الوصف: عنصر صندوق reCAPTCHA الذي يتم فيه العرض.
// like grecaptcha.execute('.grecaptcha') -> this div
// Basically, it returns a number or the depth or level of that div in the document.
// Example: html > body > main > form > fieldset > div.recaptcha.form-field
// 5 4 3 2 1 0
// out = 5
nM = document.getElementsByClassName('grecaptcha-badge')[0] // or 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 يتحقق إذا كان عنصر شراء باستخدام regex /buy|pay|place|order|donate|purchase/i مع textContent و classNames و id، نموذجIdx 36 (string)
h3, h2 or 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)
القيمة: [1,0,null,1,1,["805b1z63wq"],"MWc2MzZwMnR0ZHNkMw==",0,null,[[1]]]
التجزئة: 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)
القيمة: 4
التجزئة: false
الوصف: يأخذ رابط الموقع الحالي، ويحوله إلى مصفوفة أحرف، ويقصّه إلى 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، تعيد "-1,-1" إذا كانت القيمة null، نموذجIdx 57 (string)
القيمة: www.gstatic.com,_,static.kogstatic.com,www.google.com,www.googletagmanager.,...
التجزئة: false
الوصف: يجمع المضيفين من src لجميع عناصر <SCRIPT> الموجودة في document.scripts، نموذج
لكل <SCRIPT>
إذا كان العنصر يحتوي على سمة src (hasAttribute("src"))، يتم أخذ قيمة src وتحليلها باستخدام regex من نوع URI (nd)، مع استخراج مكوّن المضيف فقط (مجموعة الالتقاط 3 من regex).
إذا لم يكن لدى <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)
القيمة: []
التجزئة: false
الوصف: استخراج الطوابع الزمنية (أرقام من 12 إلى 13 رقمًا تبدأ بـ 1[2-9]، وهي نموذجية لمللي ثانية epoch ~2008-2099) من قيم ملفات تعريف الارتباط، نموذج
جمّع القيم التالية عبر جميع المعرفات التي تم العثور عليها: العدد، الحد الأدنى، الحد الأقصى، والمتوسط.
النتيجة النهائية هي مصفوفة [count, min, max, avg]
Idx 64 (integer)
55557falseIdx 65 (string)
sha384-3qctruehttps://www.google.com/recaptcha/api.js?render= (مقتطع إلى 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)
القيمة: [null,null,"","",null,"1l0fl"]
التجزئة: 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)) → هذه هي الكتلة الرئيسية التي تلتقط المال وتنقسم إلى خيارين منفصلين
Idx 71 (array)
[jsHeapSizeLimit,usedJSHeapSize,totalJSHeapSize]falseIdx 72 (array)
القيمة: [[["Google Chrome","147"],["Not.A/Brand",...
التجزئة: 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... | تشفير لحمولة بصمة الإصبع المتسلسلة بالكامل باستخدام مفتاح التشفير من anchor (الفهرس 18) 1777669303203 |
20 | tbMywxNTQsOD... | بنية تيليمتري مشفرة بـ Base64 تحتوي على فروقات توقيت VM، أوقات الموارد، إحصائيات كائنات المتصفح المجمعة وعناوين URL الخاصة بسكربتات الموقع |
21 | 0aAPQrAobqME... | رمز مرتبط بحل CAPTCHA سابق. يُستخدم لاستمرارية الجلسة وربط الثقة |
22 | BDAAYAIAGEcA... | تجزئة لجميع مفاتيح كائنات المتصفح |
25 | W1tbNTAwNiw... | عدادات مشفرة بـ Base64 لأحداث تفاعل المستخدم مثل حركة الماوس والنقرات ولوحة المفاتيح وتغييرات التركيز |
qr| استجابة سريعة (جديد) |
| النوع |
|---|
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 | كابتشا اختيار الصورة القياسية |
tileselect | تحدي صورة ديناميكي قائم على المربعات |
dynamic | تحدي ديناميكي حيث تُعاد تحميل المربعات بعد الاختيار |
multicaptcha | تحدي كابتشا متعدد الخطوات |
audio | تحدي إتاحة قائم على الصوت |
nocaptcha | تدفق تحقق يعتمد على مربع الاختيار فقط |
doscaptcha | رفض كابتشا في حال وجود إساءة استخدام |
| الحقل | الاسم | الوصف |
|---|
v | recaptchaVersion | إصدار reCAPTCHA |
c | challengeToken | رمز حالة التحدي المُعاد من /replaceimage أو من طلب /userverify سابق |
response | حمولة مشفّرة تحتوي على مؤشرات المربعات المحددة وبيانات وصفية إضافية للتفاعل | |
t | challengeElapsed | الوقت المنقضي منذ تحميل التحدي في البداية |
ct | completionTime | إجمالي الوقت الذي استغرقه المستخدم لحل CAPTCHA وإرساله |
ch | ocHash | تجزئة الحمولة oc المتسلسلة بالكامل، مثال |
oc | encryptedVmSignals | إشارات مشفّرة تم جمعها من reCAPTCHA VM، انظر هنا |
pm | telemetryPayload | بنية بيانات قياس عن بُعد مشفّرة بـ Base64 تحتوي على فروقات توقيت VM، وتوقيتات الموارد، وإحصاءات كائنات المتصفح المجمّعة، وبيانات وصفية لسكربتات الموقع |