diff --git a/tools/huya_passport_client.py b/tools/huya_passport_client.py new file mode 100644 index 0000000..a00d3c7 --- /dev/null +++ b/tools/huya_passport_client.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 +"""纯 Python 护照登录客户端(进行中)。 + +路线: wsapi.huya.com / servant=huyaudbwebui / func=wupudbrequest_v0 + 内层 MsgRequestLoginPassport(id=0x1001) JSON 载荷 +目标: 响应 JSON 含 cred -> cert_forge -> bind -> 页面 cookie。 + +状态: 信封构建完成; 内层帧格式待盲发试错(step2)。 +""" +from __future__ import annotations + +import hashlib +import json +import random +import struct +import sys +import time +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) + +import requests + +WSAPI = "https://wsapi.huya.com" +SERVANT = "huyaudbwebui" +FUNC = "wupudbrequest_v0" +MSG_ID = 0x1001 # MsgRequestLoginPassport + + +def _wup_packet(servant: str, func: str, body: bytes) -> bytes: + """按抓包样本复刻 WUP 包头: [u32be len][10 03][',LV'][servant][func][body]。""" + core = (bytes([len(servant)]) + servant.encode() + + bytes([len(func)]) + func.encode() + body) + return struct.pack(">I", len(core) + 6) + b"\x10\x03, LV".replace(b" ", b"")[:4] + core[3 - 3:] if False else \ + struct.pack(">I", len(core) + 6) + b"\x10\x03" + b",LV" + core + + +def build_request(name: str, password_sha1: str, user_action: dict | None = None, + biz_appids: list | None = None) -> dict: + ua = user_action or {"curl": "登录页", "furl": "我的", "latitude": "-1.0", + "longitude": "-1.0", "ssid": "", "user_action": []} + return { + "name": name, + "password": password_sha1, + "userAction": json.dumps(ua, ensure_ascii=False), + "isAuthLogin": False, + "lgnExtParam": {}, + "bizAppids": biz_appids or [], + } + + +def probe_inner_formats(payload: dict): + """step2: 对内层帧做多种候选包装, 盲发读响应定位格式。""" + js = json.dumps(payload, separators=(",", ":")) + cands = { + "raw_json": js.encode(), + "u16id_json": struct.pack("I", MSG_ID) + js.encode(), + "json_id_field": json.dumps({"msgId": MSG_ID, "data": payload}, + separators=(",", ":")).encode(), + } + s = requests.Session() + s.trust_env = False + for name, body in cands.items(): + pkt = _wup_packet(SERVANT, FUNC, body) + try: + r = s.post(WSAPI, data=pkt, headers={ + "Content-Type": "application/octet-stream", + "User-Agent": "okhttp/3.14.9"}, timeout=15) + head = r.content[:64] + print(f"[{name}] HTTP {r.status_code} {len(r.content)}B {head!r}") + except Exception as e: + print(f"[{name}] EXC {e}") + + +if __name__ == "__main__": + acct = sys.argv[1] if len(sys.argv) > 1 else "hy_300023887" + pwd = sys.argv[2] if len(sys.argv) > 2 else "" + sha1 = hashlib.sha1(pwd.encode()).hexdigest() if pwd else "0" * 40 + probe_inner_formats(build_request(acct, sha1))