feat(huya): 一键全自动测试脚本(密码->cookie)
This commit is contained in:
Executable
+98
@@ -0,0 +1,98 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""一键全自动测试: 账号密码 -> 页面cookie(biztoken)。
|
||||||
|
|
||||||
|
用法:
|
||||||
|
python tools/full_auto_test.py <账号如hy_xxx或300023887> <密码>
|
||||||
|
|
||||||
|
前提: evidence/cert_keycap.json 内有较新鲜的 wupData 信封
|
||||||
|
(过期则先在设备上跑 scripts/hook_cert_keycap.py 刷新)。
|
||||||
|
"""
|
||||||
|
import sys, re, json, hashlib, base64, time, struct
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parent.parent
|
||||||
|
sys.path.insert(0, str(ROOT))
|
||||||
|
sys.path.insert(0, str(ROOT / "tools"))
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from huya_wup_encoder import build_password_login_wup
|
||||||
|
from cert_forge import build_p1, forge_cert
|
||||||
|
|
||||||
|
|
||||||
|
def password_login(account: str, password: str) -> bytes:
|
||||||
|
"""纯Python护照登录, 返回新鲜cred(114B)。"""
|
||||||
|
uid = account[3:] if account.startswith("hy_") else account
|
||||||
|
raw = (ROOT / "evidence/wup_passwordlogin_taf.bin").read_bytes()
|
||||||
|
mj = json.loads(re.search(rb'(\{"associationId.*?\})', raw).group(1))
|
||||||
|
ua = re.search(rb'(\{"curl".*?"user_action":\[.*?\]\})', raw).group().decode()
|
||||||
|
sd = re.search(rb'PQwemAN9[A-Za-z0-9+/=]+', raw).group().decode()
|
||||||
|
dev = {"app_version": "13.4.22", "sdk_version": "1.0.80138",
|
||||||
|
"vendor": "xiaomi", "model": "M2102J2SC", "os": "android",
|
||||||
|
"ip": "127.0.0.1",
|
||||||
|
"fingerprint": "02df398797432eadefcc12767119ad5e80999389",
|
||||||
|
"screen": "M2102J2SC,30,11", "width": "1080", "height": "2120",
|
||||||
|
"device_id": "7c5387e0539c023c31c4ff0e807e7256117385ee"}
|
||||||
|
pkt = build_password_login_wup(
|
||||||
|
uid, hashlib.sha1(password.encode()).hexdigest(), sd,
|
||||||
|
"ed0db8334cadd236c00cadf7e11ab5a5",
|
||||||
|
mj["session"], mj["traceId"], ua, dev)
|
||||||
|
r = requests.post(
|
||||||
|
"https://wup.huya.com", data=pkt,
|
||||||
|
headers={"Content-Type": "application/multipart-formdata; charset=UTF-8",
|
||||||
|
"User-Agent": "Dalvik/2.1.0 (Linux; U; Android 11)",
|
||||||
|
"Accept-Encoding": "gzip"}, timeout=15)
|
||||||
|
assert r.status_code == 200, f"登录HTTP {r.status_code}"
|
||||||
|
b = r.content
|
||||||
|
s = b.find(b"\x0a\x0a", 0x40)
|
||||||
|
e = b.find(b"_wup_header")
|
||||||
|
d = b[s:e - 6]
|
||||||
|
m = re.search(rb"\x3d\x00([\x00-\x03])(.)", d) # tag3 SIMPLE_LIST, INT8 len
|
||||||
|
assert m, "响应中未找到cred字段"
|
||||||
|
ln = m.group(2)[0]
|
||||||
|
st = m.start() + 4
|
||||||
|
cred = d[st:st + ln]
|
||||||
|
assert len(cred) == 114 and cred[:1] == b"\x0a", f"cred异常 {len(cred)}"
|
||||||
|
return cred
|
||||||
|
|
||||||
|
|
||||||
|
def forge(cred: bytes) -> str:
|
||||||
|
t = int(time.time() * 1000) & ((1 << 48) - 1)
|
||||||
|
rnd = (t.to_bytes(6, "big") + b"\x00\x00"
|
||||||
|
+ ((t << 16) & ((1 << 64) - 1)).to_bytes(8, "big")[2:] + bytes(8))[:20]
|
||||||
|
fp = b"02df398797432eadefcc12767119ad5e80999389"
|
||||||
|
P1 = build_p1(b"5008", fp, cred, rnd=rnd)
|
||||||
|
return forge_cert(P1, key_idx=0x20).hex()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
acct, pwd = sys.argv[1], sys.argv[2]
|
||||||
|
print("[1/3] 纯Python密码登录 ...")
|
||||||
|
cred = password_login(acct, pwd)
|
||||||
|
print(f" cred OK: {len(cred)}B {cred[:8].hex()}")
|
||||||
|
|
||||||
|
print("[2/3] 铸造证书 ...")
|
||||||
|
cert_hex = forge(cred)
|
||||||
|
out = ROOT / "evidence/auto_test_cred.json"
|
||||||
|
out.write_text(json.dumps({"p1": "", "cert_hex": cert_hex,
|
||||||
|
"cred_hex": cred.hex()}))
|
||||||
|
print(f" 证书 OK: {len(cert_hex)//2}B")
|
||||||
|
|
||||||
|
print("[3/3] 扫码绑定取cookie ...")
|
||||||
|
import subprocess
|
||||||
|
probe = ROOT / "scripts/probe_forge_cert_bind.py"
|
||||||
|
src = probe.read_text()
|
||||||
|
src = re.sub(r'open\("evidence/hycred_[a-z_]+\.json"\)',
|
||||||
|
f'open("{out.as_posix()}")', src)
|
||||||
|
tmp = ROOT / "scripts/_probe_auto.py"
|
||||||
|
tmp.write_text(src)
|
||||||
|
r = subprocess.run([sys.executable, str(tmp)], capture_output=True, text=True)
|
||||||
|
print(r.stdout[-800:])
|
||||||
|
if "ok\": true" in r.stdout:
|
||||||
|
print("\n🎉 全链路成功: 密码已换出页面cookie(biztoken)!")
|
||||||
|
return 0
|
||||||
|
print("\n❌ 绑定失败——若40020多为信封过期, 请刷新wupData后重试")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
Reference in New Issue
Block a user