اسم مقترح للمستودع على GitHub: tiktok-android-signing-toolkit — راجع دليل النشر للوصف، التاقات، والريليز.
اللغات: English (افتراضي المستودع) | العربية (هذا الملف)
مجموعة للأغراض التعليمية والبحث العكسي (reverse engineering) مبنية على تحليل تطبيق TikTok الرسمي على Android وملفات اعتراض (MITM) حقيقية.
الهدف: فهم كيف تُبنى طلبات الـ API (التوقيعات، الهيدرز، تسجيل الجهاز، تدفق اللوجن) — وليس تجاوز الخدمة أو إساءة الاستخدام.
تنبيه: استخدام هذه الأدوات ضد خوادم TikTok أو حسابات الغير قد ينتهك شروط الخدمة والقوانين المحلية. أنت المسؤول عن الاستخدام.
مصدر البيانات المرجعية (مثال من المشروع): مجلد التقاط Raw_03-17-2026-03-58-36.folder
تطبيق: com.zhiliaoapp.musically — إصدارات مطابقة لـ v44.3.x (مثل 440301 / 440315) · Android
- متطلبات التشغيل
- التثبيت
- هيكل المشروع
- من أين تشغّل الأوامر؟
- البدء السريع
- أدوات سطر الأوامر (تفصيلي)
- متغيرات البيئة
- استخدام المكتبة من بايثون
- ترميز كلمة المرور في جسم الطلب
- هيدرز التوقيع
- طريقة التوقيع — مسار
sign()(يشمل الشرح الموسّع خطوة بخطوة) - معرّفات الجهاز
- تدفق اللوجن (مبسّط)
- رموز الأخطاء الشائعة
- الاختبارات
- مجلد
tools/ - الوثائق في
docs/ - الملفات الحساسة و
.gitignore - مشروع مرتبط: TikTokDeviceGenerator
- مراجع تقنية
- المطوّر والشركة والتواصل
- دعم المشروع
- Python 3.10+ (يُنصح بآخر إصدار مستقر)
- مكتبة
pycryptodome(لـ X-Argus — AES-CBC داخل المحرك)
cd tiktok_final
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txtمحتوى requirements.txt الحالي:
pycryptodome>=3.20.0
بعض الميزات الاختيارية (مثل تحقيقات إضافية في الاختبارات) قد تحتاج حزمًا أخرى؛ راجع رسائل الاستيراد في tests/test_all.py إن وُجدت.
| المسار | الوصف |
|---|---|
ttk/ |
حزمة بايثون الرئيسية: التوقيع، اللوجن، تسجيل الجهاز، تدفق MITM، إلخ. |
ttk/paths.py |
يحدد PROJECT_ROOT، FIXTURES_DIR، WORKSPACE_ROOT، ودالة resolve_data_path() لحل المسارات النسبية (جذر المشروع ثم fixtures/). |
fixtures/ |
ملفات JSON جاهزة للجهاز: device_v44_3_1.json، أمثلة (*.example.json)، devices_001.json، إلخ. |
tests/ |
test_all.py — مجموعة اختبارات شاملة. |
.github/workflows/ |
Python CI (مصفوفة 3.10–3.13، pip ثم tests/test_all.py) وCodeQL لتحليل أمني — نفس أنماط الـ workflows التي يقترحها GitHub لمكدس بايثون. |
docs/ |
توثيق تدفق اللوجن، تحليلات، خطط تنفيذ. |
tools/ |
سكربتات مساعدة: Frida، JADX، Ghidra، APK/sig، مقارنة dumps. |
| جذر المشروع | ملفات رفيعة login_client.py, device_register.py, flow.py, mitm_raw.py, feed_api_client.py, fake_login_probe.py — كلها تستدعي الوحدة الحقيقية عبر python3 -m ttk.<اسم>. |
| الوحدة | الدور |
|---|---|
signing_engine.py |
توليد X-Gorgon, X-Khronos, X-Argus, X-Ladon, X-SS-STUB محليًا. |
login_client.py |
عميل لوجن كامل (خطوات متعددة، كابتشا/تحقق حيث ينطبق). |
device_register.py |
تسجيل جهاز جديد عبر واجهة TikTok (device_register). |
flow.py |
تسجيل جهاز ثم لوجن في مسار واحد. |
mitm_raw.py |
قراءة مجلدات اعتراض Raw واستخراج/مقارنة الطلبات. |
fake_login_probe.py |
اختبار «جاف» بدون إرسال كلمة مرور حقيقية (فحص هيدرز/استجابة). |
feed_api_client.py |
مثال طلب فيد (Feed) مع التوقيع. |
device_guard.py |
بيانات حماية التذاكر (guard) عند توفر المفاتيح. |
virtual_devices.py |
توليد بروفايلات أجهزة افتراضية ديناميكية + تخزين JSON اختياري في fixtures/virtual_devices.json. |
rapidapi_signer.py |
توقيع عبر واجهة RapidAPI (بديل عن المحرك المحلي). |
tiktok_apk_sig.py |
استخراج/دمج sig_hash من APK مع قالب الجهاز. |
شغّل كل الأوامر من مجلد tiktok_final/ (جذر المشروع الذي يحتوي على مجلد ttk/) حتى يعمل import ttk بشكل صحيح.
يمكنك استخدام إما:
python3 login_client.py ...(الملف في الجذر = غلاف)، أوpython3 -m ttk.login_client ...(مباشرة على الحزمة).
python3 login_client.py --username USER --password "YourPassword"الافتراضي: fixtures/device_v44_3_1.json (ما لم تمرّر --device).
python3 login_client.py --username USER --step1python3 device_register.py --out my_device.json --verbose
python3 login_client.py --device my_device.json --username USER --password "PASS"لو أردت واجهة رسومية وتسجيل دفعات من الأجهزة عبر Java + unidbg (حمولة ثنائية ثم device_register)، راجع المستودع المرتبط TikTokDeviceGenerator — يكمّل أداة device_register.py البحتة بايثون في هذا المشروع.
python3 flow.py --username USER --password "PASS"python3 -m ttk.signing_engine --url 'https://...?' --method POST --body 'a=b' --cookie '...'| الخيار | الوصف |
|---|---|
--username |
مطلوب. اسم المستخدم. |
--password |
كلمة المرور نصية (تُرمَّز تلقائيًا). |
--password-hex |
كلمة مرور مرمّزة مسبقًا (hex). |
--device |
مسار JSON للجهاز (افتراضيًا: قالب fixtures). |
--proxy |
بروكسي HTTP/HTTPS، مثل http://user:pass@host:port. |
--proxy-file |
أول سطر صالح host:port:user:pass يُستخدم كبروكسي. |
--no-proxy |
تجاهل الملفات ومتغيرات البيئة للبروكسي. |
--step1 |
فقط check_login_name / التحقق من التسجيل. |
--step2 |
فقط pre_check. |
--skip-check |
تخطي الخطوة 1. |
--region-email |
بريد لحساب hashed_id في مسارات المنطقة (بدل الاعتماد على device_id فقط حيث ينطبق). |
--devices-batch |
ملف JSON بأسلوب devices_001.json (قائمة .devices[] مع .record) لدمج كل صف مع قاعدة --device. |
--batch-offset / --batch-limit |
تقطيع الدفعة. |
--proxy-rotate-file |
مع الدفعة: بروكسي مختلف لكل صف من ملف أسطر. |
--batch-summary-out |
كتابة ملخص JSON بعد الدفعة. |
--verbose |
طباعة الطلبات/الاستجابات بالتفصيل. |
--sign-backend local|rapidapi |
محلي (افتراضي) أو RapidAPI. |
--rapidapi-key |
مفتاح RapidAPI (أو عبر RAPIDAPI_KEY). |
مثال دفعة:
python3 login_client.py --username U --step1 --devices-batch fixtures/devices_001.json| الخيار | الوصف |
|---|---|
--base |
قالب جهاز (افتراضيًا يُحلّ إلى fixtures/device_v44_3_1.json عبر resolve_data_path). |
--apk |
مسار APK لاستخراج sig_hash ودمجه في القالب قبل الطلب. |
--extract-sig-only |
مع --apk و --out: تحديث JSON بالتوقيع فقط دون استدعاء الخادم. |
--virtual REGION |
بناء القاعدة من virtual_devices.generate_device_profile (يتجاوز --base). |
--out |
ملف الإخراج (افتراضيًا device_<timestamp>.json في جذر المشروع). |
--proxy / --proxy-file |
بروكسي. |
--verbose |
تفاصيل الطلبات. |
--allow-local-fallback |
عند فشل/صفر من الخادم: الاستمرار بمعرّفات محلية عشوائية (ليس تسجيلًا حقيقيًا على الخادم). |
--dump-golden DIR |
حفظ لقطات طلب/استجابة لكل محاولة (مقارنة مع MITM). |
--golden-only DIR |
تشغيل محاولة واحدة وتسجيل «golden» ثم الخروج. |
| الخيار | الوصف |
|---|---|
--username / --password / --password-hex |
بيانات الدخول. |
--device |
استخدام جهاز موجود (تخطّي التسجيل). |
--skip-register |
استخدام القالب الافتراضي من fixtures بدون تسجيل جديد. |
--save-device |
مسار حفظ الجهاز بعد تسجيل ناجح. |
--proxy / --proxy-file |
بروكسي للتسجيل واللوجن. |
--verbose |
تفاصيل. |
--region-email |
كما في login_client. |
--allow-local-fallback |
كما في device_register. |
بعد التسجيل يستدعي التدفيق get_domains لتسخين الجلسة (cookies) حيث ينطبق المنطق في الكود.
الوسيط الأول: مسار مجلد Raw_MM-DD-YYYY....folder.
| الخيار | الوصف |
|---|---|
--list |
قائمة ملفات متعلقة بـ passport/login. |
--dump FILE |
تحليل ملف طلب واحد → JSON. |
--suggest FILE |
اقتراح patch لملف الجهاز من طلب. |
--flow-diff |
مقارنة ترتيب الطلبات مع مرجع login_client. |
--export-device OUT.json |
دمج بصمة MITM في قالب JSON. |
--template BASE.json |
قالب الجهاز (مثلاً fixtures/device_v44_3_1.json أو مسار يُحلّ تلقائيًا). |
--from-file FILE |
ملف طلب محدد بدل الاكتشاف التلقائي. |
| الخيار | الوصف |
|---|---|
--device |
ملف جهاز (افتراضي محلي في الجذر إن وُجد). |
--username |
اسم ثابت؛ وإلا اسم عشوائي probe_*. |
--proxy / --proxy-file / --no-proxy |
بروكسي. |
--mitm-folder / --mitm-only / --mitm-list-repo |
استكشاف مجلدات Raw في المستودع المجاور. |
--verbose |
تفاصيل. |
--skip-region |
تخطي سلسلة nonce/region. |
--only-sign |
طباعة التوقيعات محليًا فقط. |
--step1-only |
التوقف بعد أول خطوة تحقق. |
سكربت يجلب الفيد عند توفر ملف جهاز مسجّل محليًا (افتراضيًا يبحث عن device_emulator_registered.json في جذر المشروع). راجع الكود لمتطلبات البروفايل.
| الخيار | الوصف |
|---|---|
--url |
عنوان كامل مع query. |
--method |
GET/POST/… |
--body |
جسم الطلب (نص). |
--cookie |
قيمة رأس Cookie. |
--ts |
طابع زمني Unix (افتراضي: الآن). |
| المتغير | الاستخدام |
|---|---|
RAPIDAPI_KEY / X_RAPIDAPI_KEY |
مفتاح RapidAPI عند --sign-backend rapidapi. |
TIKTOK_SIGN_BACKEND |
local أو rapidapi. |
TIKTOK_PROXY_FILE |
مسار ملف بروكسي (سطر تنسيق host:port:user:pass). |
TIKTOK_PROXY / HTTP_PROXY / HTTPS_PROXY |
بروكسي للطلبات (حسب منطق login_client). |
TIKTOK_MITM_FOLDER |
مجلد اعتراض افتراضي لبعض مسارات الاستكشاف في fake_login_probe. |
from ttk.signing_engine import sign, compute_stub
sig = sign(
url="https://api16-normal-c-alisg.tiktokv.com/passport/user/login/?aid=1233&ts=1234567890",
method="POST",
body=b"username=test&password=test",
cookie="store-idc=useast5; ...",
)
# sig → X-Gorgon, X-Khronos, X-Argus, X-Ladon, X-SS-STUB (حسب الطلب)from ttk.login_client import TikTokLoginClient, encode_password
from ttk.paths import FIXTURES_DIR, PROJECT_ROOT, resolve_data_path
client = TikTokLoginClient(device_path=None, verbose=True)
# encode_password("secret") # XOR افتراضي 0x05 (إصدارات حديثة)from ttk.device_register import TikTokDeviceRegister
dr = TikTokDeviceRegister(verbose=True)
reg = dr.register()from ttk.rapidapi_signer import sign_via_rapidapi # يتطلب RAPIDAPI_KEY في البيئةالتطبيق يرسل حقول مثل اسم المستخدم وكلمة المرور في الـ body بعد XOR ثم تمثيل hex لكل بايت.
- الإصدارات الحديثة (مطابقة v44.3.15 في الكود): XOR بمفتاح
0x05(الثابتLOGIN_BODY_XOR_KEYفيlogin_client). - إصدارات أقدم (ملاحظات 44.3.1): قد تحتاج
xor_key=0x17:
from ttk.login_client import encode_password
encode_password("MyPassword123") # افتراضي 0x05
encode_password("MyPassword123", xor_key=0x17) # أسلوب أقدم| الهيدر | فكرة الخوارزمية | مدخلات رئيسية |
|---|---|---|
X-SS-STUB |
MD5 للجسم (أحرف كبيرة) | بايتات الجسم الخام |
X-Khronos |
وقت Unix | ts |
X-Gorgon |
طبقة RC4-like + تبديل nibbles | معاملات URL، STUB، cookie، الزمن |
X-Ladon |
SIMON-128/ECB + padding | {ts}-{license_id}-{aid} |
X-Argus |
Protobuf + تشفير متعدد الطبقات | معاملات الجهاز والزمن |
التفاصيل الرياضية والثوابت مضمنة في ttk/signing_engine.py (وباقي الوثائق في docs/).
كل التوقيع المحلي يمر عبر ttk.signing_engine.sign(). فهم المدخلات والترتيب ضروري لأن أي اختلاف في نفس الـ URL (query) أو نفس بايتات الجسم أو نفس الـ Cookie أو نفس الطابع الزمني ts يغيّر الهيدرز.
| المعامل | الدور |
|---|---|
url |
الرابط كاملًا بما فيه query string (?aid=…&device_id=…) — يُستخرج منه الجزء بعد ? فقط للتوقيع. |
method |
"GET" أو "POST" (أو أخرى بحروف كبيرة). يؤثر على X-SS-STUB. |
body |
bytes أو str — يُحوَّل داخليًا إلى بايتات UTF-8 إن كان نصًا. يجب أن تطابق بالضبط ما يُرسل على السلك لحساب الـ STUB (انظر ملاحظة الـ gzip أدناه). |
cookie |
قيمة هيدر Cookie كسلسة واحدة (كما في الطلب الفعلي). |
ts |
وقت Unix (int). الافتراضي: int(time.time()). يُستخدم في Gorgon وLadon وArgus. |
ts← الوقت الحالي إن لم يُمرَّر.query_string←urlparse(url).query.body_bytes← ترميز الجسم إلى بايتات.X-SS-STUB← إن وُجد جسم و الطريقة ليستGET:MD5(body_bytes).hexdigest().upper()؛ وإلا يُترك الهيدر غير مُضاف في القاموس.compute_gorgon(query_string, stub, cookie, ts)← يُرجعX-GorgonوX-Khronos(الخronos هنا نص الرقمstr(ts)كما في المخرجات).compute_argus(query_string, stub, ts)← يعتمد على pycryptodome؛ بدون المكتبة يعيد سلسلة فارغة.compute_ladon(ts)← يولّدX-Ladon(عشوائية 4 بايتات داخل المخرج في كل استدعاء ما لم تُثبَّت).- دمج القاموس النهائي:
X-Khronos,X-Gorgon,X-Ladon,X-Argus، وX-SS-STUBعند وجود STUB.
flowchart LR
subgraph inputs [مدخلات]
U[url]
M[method]
B[body]
C[cookie]
T[ts]
end
subgraph sign_fn [sign]
ST[compute_stub]
GO[compute_gorgon]
AR[compute_argus]
LA[compute_ladon]
OUT[dict الهيدرز]
end
U --> GO
U --> AR
B --> ST
M --> ST
ST --> GO
ST --> AR
C --> GO
T --> GO
T --> AR
T --> LA
GO --> OUT
AR --> OUT
LA --> OUT
ST --> OUT
url_md5= MD5 لسلسلة query فقط (UTF-8)، أخذ أول 4 بايتات كأرقام.stub= 4 بايتات من الـ hex الـ 32 حرفًا لـX-SS-STUB، أو أصفار إن لم يكن هناك STUB.cookie_md5= MD5 لسلسلة الـ Cookie كاملة، أول 4 بايتات؛ أو أصفار بدون Cookie.- 4 بايتات صفر ثم 4 بايتات من تمثيل hex لـ
ts(8 hex أرقام). - الناتج 20 بايتًا يُمرَّر عبر جدول تبديل يشبه RC4 (KSA + PRGA) ثم دالة
_gorgon_handle: تبديل نصف بايتات (nibbles)، عكس بتات، XOR ثابت، إلخ. - البادئة: إصدار مثل
8404+ ثوابت مأخوذة من جدول الإصدار + 40 حرف hex من الـ 20 بايت النهائية → طول شائع 52 حرفًا لـ8404….
ملاحظة: مطابقة بايت-ببايت مع التطبيق قد تعتمد على مفاتيح/ثوابت داخل الثنائي؛ المحرك يحقق الشكل والتبعيات (query / stub / cookie / ts) كما في التحليل المرجعي.
- نص واضح:
{ts}-{license_id}-{aid}(افتراضيًاlicense_idوaidكما فيcompute_ladon). rand= 4 بايتات عشوائية (os.urandom).- من
rand + str(aid)يُشتق جدول مفاتيح عبر MD5 ثم تشفير كتلي يعتمد على SIMON-128 مع PKCS7 على النص أعلاه. - المخرج:
base64(rand ‖ ciphertext).
- تفكيك query إلى حقول (
device_id,version_name,channel,os_version, …). body_hash= أول 6 بايت من SM3 على بايتات الـ STUB (16 بايت من hex الـ STUB)، و**query_hash** من SM3 على سلسلة الـ query.- تجميع حقول في هيكل Protobuf مخصص (رقم الحقول كما في الكود) يشمل
channelالمطابق للـ query. - ترميز Protobuf → حشو PKCS7 → تشفير SIMON → طبقة XOR + عكس ثم بادئات ثابتة.
- AES-CBC بمفتاح و IV مشتقّان من
MD5على أجزاء من_ARGUS_SIGN_KEY. - المخرج: Base64 مع بادئة بايتية داخل الترميز (
\xf2\x81+ نص مشفّر) كما في التطبيق.
- في
sign()الافتراضي: الـ STUB = MD5 لبايتات الجسم كما تمرّرها (عادة JSON أو form غير مضغوط). - في مسارات
device_registerالواقعية، قد يُرسل الجسم مضغوطًا gzip على السلك؛ فرعjava_gzip_sigفي الكود يوضح أن الـ STUB قد يُحسب من MD5 بايتات الـ gzip وليس النص الظاهر فقط. عند محاكاة ذلك يجب تمريرbodyإلىsign()بنفس البايتات التي تُحسب عليها الـ MD5 في الخادم/التطبيق.
إن اخترت --sign-backend rapidapi في login_client، فإن X-Gorgon / X-Ladon / X-Argus / X-Khronos تُجلب من خدمة خارجية، بينما X-SS-STUB يُحسب محليًا (compute_stub) عند وجود جسم. راجع ttk/rapidapi_signer.py ومتغير RAPIDAPI_KEY.
- الواجهة الموحدة:
sign()≈ السطور 559–603 فيttk/signing_engine.py. - دوال منفصلة للاختبار:
compute_stub,compute_gorgon,compute_ladon,compute_argus.
ما يلي يطابق تنفيذ ttk/signing_engine.py: مكتبة قياسية فقط، مع pycryptodome لـ AES-CBC داخل Argus فقط.
| البنية | الدور |
|---|---|
| MD5 | سلاسل query/cookie (UTF-8)؛ بايتات جسم الـ STUB؛ مادة مفتاح/IV لـ Argus (MD5 على أجزاء _ARGUS_SIGN_KEY). |
| SM3 (معيار صيني GB/T 32905-2016) | تنفيذ بايثون _SM3؛ body_hash / query_hash في Argus (أول 6 بايتات لكلٍ منهما)؛ _ARGUS_SM3_OUTPUT لتغذية مفاتيح SIMON في Argus. |
| SIMON-128/128 | 72 جولة (simon_enc)؛ تشفير كتل protobuf في Argus؛ مسار Ladon يستخدم جدول جولات مخصصًا لكل كتلة 16 بايت. |
| AES-128-CBC | غلاف Argus النهائي (Crypto.Cipher.AES). |
| Protobuf مبسّط | _ProtoBuf: int → varint، str/bytes → حقل بطول، dict → رسالة فرعية. |
| PKCS#7 | حشو لمضاعفات 16 بايت قبل SIMON/AES. |
- داخل
sign(): إذاmethod.upper() == "GET"أو الجسم فارغ → لا تُضاف مفتاحX-SS-STUBفي القاموس المُرجَع. - تطبيع
body:str→ ترميزutf-8؛bytesكما هي. stub_lower = MD5(body_bytes).hexdigest()(32 حرف hex بأحرف صغيرة من hashlib).- الهيدر:
X-SS-STUB = stub_lower.upper()(32 حرف hex كبير). - الاستخدام اللاحق:
compute_gorgonيأخذ ذلك السلسلة الكبيرة ويقرأ أول 8 أزواج hex كبايتات 4–7 من حالة Gorgon.compute_argusيحوّل الـ stub بـbytes.fromhex(stub)إن وُجد؛ وإلا 16 بايت صفر لمدخل SM3.
X-Khronos = str(ts)— نفس الطابعtsالمُضمَّن في بايتات 16–19 لحالة Gorgon.- عند إعادة التقاط، ثبّت
tsفيsign(..., ts=)ليتطابق معX-Khronosفي اللقطة.
- اختر إصدار Gorgon (افتراضي
8404). جدول_GORGON_HEX_STRيعطي 8 أعدادًا تُخلط في KSA؛8404→ أصفار؛0404→ ثوابت قديمة غير صفرية. khronos_hex = hex(ts)[2:].zfill(8)— 8 أرقام hex بالضبط.MD5(query_string UTF-8).hexdigest()— خذ أول 8 أحرف hex → 4 بايتات → مواضع 0–3.- 4–7: من
X-SS-STUB(أول 8 أحرف hex من الـ stub الكبير) أو أصفار. - 8–11: أول 4 بايت من
MD5(cookie UTF-8)أو أصفار. - 12–15: أربعة أصفار ثابتة.
- 16–19: من 8 أرقام hex لـ
khronos_hex(زوجان hex لكل بايت). _gorgon_ksa(hex_str)→ جدول تبديل 256 بايت (KSA يشبه RC4؛ حالة خاصة عند القيمة 85)._gorgon_prga: 20 تكرارًا، كل واحد يحدّثinp[i]بـ XOR مستمد من الجدول._gorgon_handle: لكلi: تبديل نصفيّة البايت (nibbles)؛ XOR مع البايت التالي (دوري 20)؛ عكس بتات الناتج؛ XOR 20؛~ثم قناع0xFF.sig: الـ 20 بايت النهائية كـ 40 حرف hex صغير.- السلسلة النهائية:
version+ أربعة أوكتات hex من فهارس ثابتة فيhex_str([7],[3],[1],[6]كـ02x) +sig. مع8404والجدول صفري غالبًا840400000000+ 40 حرفًا ≈ 52 حرفًا.
ts,license_id(افتراضي 1611921764),aid(افتراضي 1233).- نص UTF-8:
"{ts}-{license_id}-{aid}". rand = os.urandom(4)ما لم تُمرَّرrand=إلىcompute_ladon(استدعاءsign()العادي لا يثبّتها → كل مرة مختلفة).keygen = rand ‖ str(aid)(بايتات).md5hex = MD5(keygen).hexdigest()كسلسلة ASCII (32 حرفًا).- PKCS7 على النص حتى مضاعف 16.
_ladon_keyschedule: يوسّعmd5hexإلى جدول مفاتيح (حلقة خارجية0x22).- لكل كتلة 16 بايت:
0x22جولة Feistel على نصفي 64 بت ( endian صغير) كما في_ladon_encrypt_data. base64(rand ‖ ciphertext)→X-Ladon.
بدون pycryptodome → سلسلة فارغة.
parse_qsعلى query؛_qpيأخذ أول قيمة لكل مفتاح.channelمن الاستعلام أو افتراضيgoogleplay— يجب أن يطابق التطبيق.stub_bytes:fromhex(stub)أو 16 بايت صفر.body_hash = SM3(stub_bytes)[:6].query_hash = SM3(query_string.encode() if query_string else bytes(16))[:6].- املأ
bean: الحقول 1,2,3,4,5,6,7,8,9,10,11,12,13,14,20,23 واختياري 16 — منها 12:ts << 1، 13/14: 6 بايتات، 23: فرعي فيهdevice_type,os_version,channel,_argus_calculate_constant(os_version)(جمع مرجّح لأرقام منos_version). _ProtoBuf(bean).to_bytes()→ PKCS7 → تشفير SIMON لكل 16 بايت بمفتاح من_ARGUS_SM3_OUTPUT[:32]._argus_xor_reverse: بادئة 8 بايت\xf2\xf7…، XOR للبايتات من الموضع 8، عكس المصفوفة كلها.- إحاطة:
b"\xa6n\xad\x9fw\x01\xd0\x0c\x18" + … + b"ao". - PKCS7 مرة أخرى، ثم AES-CBC:
MD5(_ARGUS_SIGN_KEY[:16])وMD5(_ARGUS_SIGN_KEY[16:])كمفتاح و IV. Base64(b"\xf2\x81" + ciphertext).
| الهيدر | query | جسم/STUB | cookie | ts |
عشوائية |
|---|---|---|---|---|---|
X-SS-STUB |
— | نعم | — | — | — |
X-Khronos |
— | — | — | نعم | — |
X-Gorgon |
نعم | نعم | نعم | نعم | — |
X-Ladon |
— | — | — | نعم | نعم (4 بايت) |
X-Argus |
نعم | نعم | — | نعم | نعم (حقل 3) |
- نفس query حرفًا بحرف (ترميز،
channel,version_name,device_id, …). - نفس سلسلة
Cookieكاملة لـ Gorgon. - نفس بايتات الجسم التي يحسب عليها التطبيق الـ STUB (انتبه لـ gzip).
tsمطابق لـX-Khronosفي اللقطة عند المقارنة الصارمة.- حقول Argus الافتراضية (
sdk_version,sdk_version_int, …) مطابقة لبروفايل الجهاز. - Ladon يتغيّر بين التشغيلات ما لم تُثبَّت
randفي الكود.
python3 -m ttk.signing_engine --url '...' --body '...' --cookie '...' --ts …python3 tests/test_all.py— اختبارات STUB/Khronos وشكل Gorgon/Argus.
في compute_argus، bean[23] قاموس متداخل. المُرمّز _ProtoBuf في signing_engine.py يعامل أي قيمة dict كـ رسالة فرعية بطول (نفس فكرة protobuf wire type 2 في هذا المُرمّز): الحقل 23 في الأب، وحقله هو _ProtoBuf(الداخل).to_bytes().
الحقول الداخلية (منطقيًا):
| رقم الحقل الداخلي | مصدر القيمة في بايثون | نوع السلك في _ProtoBuf |
|---|---|---|
| 1 | _qp("device_type") |
string → وسوم `(1<<3) |
| 2 | _qp("os_version") |
string → `(2<<3) |
| 3 | channel (من الاستعلام أو "googleplay") |
string → `(3<<3) |
| 4 | _argus_calculate_constant(os_version) int |
varint → `(4<<3) |
مخطط تداخل مفاهيمي:
[حقول الرسالة الجذر 1،2،…،22،23،…]
│
└── الحقل 23 (بطول محدد) ──► بايتات متداخلة:
├── الحقل 1 (بطول) device_type مثال: sdk_gphone64_arm64
├── الحقل 2 (بطول) os_version مثال: "16"
├── الحقل 3 (بطول) channel مثال: samsung_store
└── الحقل 4 (varint) f(os_version) مثال: 32768 لـ "16" مع الأوزان الافتراضية
_argus_calculate_constant: يأخذ سلسلة os_version، يبقي الأرقام فقط، يصفّ إلى 6 أرقام، يضرب كل رقم في [20480, 2048, 20971520, 2097152, 1342177280, 134217728] ويجمع — يُستخدم فقط داخل 23.4.
استعلام فارغ: query_hash = SM3(bytes(16))[:6] — أي SM3 على 16 بايت صفر وليس مدخلًا فارغًا. أول 6 بايتات من الملخص (hex): 106E34A2B8C7.
الثوابت في بداية tests/test_all.py. تُستخدم لإعادة إنتاج STUB وKhronos وشرائح SM3 لـ Argus.
CAP_2913 — POST /passport/user/login/ (التقاط [2913])
| العنصر | القيمة (مختصرة أو كاملة) |
|---|---|
X-SS-STUB |
2334A127910BFD04C800293D423DEFA7 |
X-Khronos (مع ts=1773712689) |
1773712689 |
ts الممرَّر إلى sign() |
1773712689 |
X-Gorgon الملتقط (مرجع فقط) |
8404c01c000098c0cd010cdc36e96ebb4a7782bd8189fcda33c8 — الاختبارات تذكر أن المطابقة الكاملة غير متوقعة مع المحرك المفتوح (مادة مفتاح داخل التطبيق)؛ الشكل 52 حرفًا، بادئة 8404. |
أول 6 بايت من SM3(stub_bytes) (stub_bytes = 16 بايت من hex الـ STUB) |
0AD0A7F0A1F7 |
أول 6 بايت من SM3(query_utf8) لسلسلة استعلام CAP_2913 |
414D4CED13BA |
CAP_2820 — جسم POST pre_check (التقاط [2820])
| العنصر | القيمة |
|---|---|
| بداية الجسم | account_sdk_source=app&multi_login=1&mix_mode=1&username=76716a7760627637 |
X-SS-STUB |
AFAB3892DC07AA8D95D49D68B9FF63CA |
CAP_2817 — GET check_login_name_registered: لا جسم → لا X-SS-STUB في مخرجات sign()؛ خانة STUB في Gorgon أصفار.
مثال — إعادة التحقق من STUB و Khronos
from ttk.signing_engine import sign, compute_stub
from tests.test_all import CAP_2913
assert compute_stub(CAP_2913["body"].encode()) == CAP_2913["X-SS-STUB"]
sig = sign(
url=CAP_2913["url"],
method="POST",
body=CAP_2913["body"],
cookie=CAP_2913["cookie"],
ts=CAP_2913["ts"],
)
assert sig["X-Khronos"] == CAP_2913["X-Khronos"]
assert sig["X-SS-STUB"] == CAP_2913["X-SS-STUB"]| الحقل | شكل تقريبي | توليد مرجعي في المشروع |
|---|---|---|
device_id |
رقم طويل (~19 رقمًا) | عشوائي آمن عند التسجيل |
iid (install_id) |
مماثل | عشوائي آمن |
openudid |
hex 16 حرفًا | عشوائي |
cdid |
UUID | عشوائي |
المرجع في الكود مستمد من JADX مثل DeviceRegisterManager وملفات مشابهة (انظر تعليقات device_register.py).
Client خوادم TikTok
│ │
│──[1] GET check_login_name ───────────▶ aggr16-normal.tiktokv.us
│◀──────── is_registered / … ───────────│
│ │
│──[2] POST login/pre_check ───────────▶ api16-normal-c-alisg.tiktokv.com
│◀──────── error_code: 0 … ───────────│
│ │
│──[3] POST login ─────────────────────▶ api16-normal-c-alisg.tiktokv.com
│◀──────── session_key, uid, … ───────│
التدفق الكامل في التطبيق أطول (منطقة، كابتشا، تحقق، …) — راجع docs/LOGIN_FLOW.md و docs/LOGIN_FLOW_V44_3_15.md.
error_code |
المعنى تقريبًا | ماذا تفعل |
|---|---|---|
0 |
نجاح | — |
7 |
حد معدل / تقييد | جهاز/بروكسي/توقيت آخر |
1105 |
كابتشا | حل الكابتشا أو اتباع مسار التطبيق |
2046 |
كلمة مرور خاطئة | تحقق من الترميز والحساب |
2048 |
حساب غير موجود | تحقق من اسم المستخدم |
من جذر tiktok_final/:
python3 tests/test_all.py- تغطي التوقيع، اللوجن، تسجيل الجهاز، المخطط JSON، وغيرها.
- إن وُجد
login_sessions.jsonفي الجذر، تُشغَّل اختبارات إضافية؛ وإلا تُتخطى تلقائيًا (مناسب للمستودع العام).
التكامل المستمر (CI): عند كل دفع أو PR إلى main، يشغّل Python CI نفس الأمر على Ubuntu مع إصدارات بايثون 3.10–3.13. يعمل CodeQL تحليلًا ثابتًا على نفس المحفّزات بالإضافة إلى جدول أسبوعي.
| أداة | وظيفة |
|---|---|
frida_controller.py + frida_hook_tiktok.js |
اعتراض/تسجيل من الجهاز عبر Frida. |
jadx_analyzer.py |
مسح مخرجات JADX ومقارنة ثوابت مع ttk/signing_engine.py. |
ghidra_analyze.py |
تحليل ثنائي (يتطلب بيئة Ghidra/pyghidra). |
apk_sig_hash.py |
تجزئة توقيع APK. |
android_sig_bruteforce.py / prepare_bruteforce.py |
أدوات بحث/تحضير متعلقة بالتوقيع. |
compare_device_register_dump.py |
مقارنة ملفات golden / dumps. |
تشغيل معظمها من داخل tools/ أو بمسارات صريحة كما في docstring كل ملف.
| الملف | المحتوى |
|---|---|
| LOGIN_FLOW.md | معاملات وتفاصيل تدفق اللوجن. |
| LOGIN_FLOW_V44_3_15.md | ملاحظات إصدار 44.3.15 وMITM. |
| ANALYSIS_REPORT.md | تقرير تحليل. |
| implementation_plan.md | خطة تنفيذ (سياق تاريخي). |
| plan_tiktok_signer.md | خطة موحّد التوقيع (سياق تاريخي). |
لا ترفع إلى Git:
- جلسات حقيقية، بروكسيات، مفاتيح، مخرجات اعتراض كاملة.
- ملفات مثل
login_sessions.json,proxsy.txt,golden_out/(حسب إعدادات المشروع)، أجهزة MITM/محلية، إلخ.
راجع .gitignore للقائمة الحالية.
github.com/code-root/TikTokDeviceGenerator — أداة تركّز على إنشاء وتسجيل أجهزة (واحد أو دفعات):
| ما هي | تطبيق سطح مكتب Tkinter؛ يبني حمولات التسجيل عبر Java وunidbg (محاكاة أصلية)، يرسل POST إلى نقطة device_register لدى TikTok (log-va.tiktokv.com/service/2/device_register/)، ويحفظ device_id / IID وبيانات وصفية بصيغة JSON. |
| ميزات | وضع دفعة (batch) مع threads، بروكسي HTTP/SOCKS اختياري، مخرجات مجزأة تحت Device/ وملخصات تحت generated_devices/. |
| التوثيق | README.md (إنجليزي) و README.ar.md (عربي). |
| الترخيص | MIT (راجع المستودع الأصلي). |
مشروع tiktok_final هنا مرتكز على التوقيع بايثون (ttk/signing_engine) و**login_client** ومسار device_register الموثّق. TikTokDeviceGenerator خيار عملي عندما تريد GUI + unidbg لتوليد أجهزة بالجملة؛ يمكن دمج مخرجات JSON مع login_client --device … هنا إذا تطابقت الحقول (راجع التوافق قبل الاستخدام الجاد).
استخدم أي أداة خارجية وفق القوانين وشروط خدمة TikTok.
- Hex-Rays FLIRT user guide — توقيعات مكتبات في IDA/Ghidra البيئات.
| المطوّر | مصطفى الباجوري (Mostafa Al-Bagouri) |
| الشركة | Storage TE |
| واتساب | +20 100 199 5914 |
إذا كانت هذه الأدوات مفيدة لك، يمكنك دعم الصيانة والتطوير اختياريًا. اختر الطريقة الأنسب لك.
| القناة | كيفية الدعم |
|---|---|
| PayPal | paypal.me/sofaapi |
| Binance Pay / المعرف | 1138751298 — الإرسال من تطبيق Binance (Pay / تحويل داخلي عند توفره). |
| إيداع عبر الويب (Binance) | إيداع عملات (Binance) — سجّل الدخول، اختر الأصل، ثم BSC (BEP20). |
| عنوان BSC (للنسخ) | 0x94c5005229784d9b7df4e7a7a0c3b25a08fd57bc |
الشبكة: استخدم BSC (BEP-20) فقط. هذا العنوان لـ USDT (BEP-20) وBTC على BSC (Binance-Peg / «BTC» على BSC في التطبيق). لا ترسل بتكوين أصلي على السلسلة، أو ERC-20، أو NFTs إلى هذا العنوان.
| USDT · BSC | BTC · BSC |
|---|---|
![]() |
![]() |
النسخة الإنجليزية (الافتراضية على GitHub): README.md
إخلاء مسؤولية: للتعليم والبحث؛ احترم شروط خدمة TikTok والقوانين المعمول بها.

