Files
live-hub-py/scripts/analyze_pairs.py
T
yml2213 da2cf5a61d feat(huya): 整合 App 协议登录获取 Cookie 全链路并与 Web 登录解耦
- core/huya: 新增 app_login, wup_encoder, nonce_forge, cert_forge, envelope_forge, device_profile, udb_aes
- core/huya/__init__.py: 导出 login_huya_app_password 与 HuyaAppPasswordLogin
- web/backend: 新增 /accounts/app-password-login 与 /accounts/app-password-login/selected 路由及 Schema,与原 Web 密码登录独立分开
- web/frontend: 增加 App 登录 API 与前端界面“App 登录选中”操作,弹窗结果明确区分
- tests: 新增 test_huya_app_login.py 单元测试覆盖全链路
2026-08-26 15:51:30 +08:00

81 lines
3.1 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
dfpReport 同步 pair 分析器
- 从 evidence/dfp_pair_sync.json 提取每个 wire 的 tag2 密文 (去掉 10B 魔数 + 9B 尾部字段)
- 结合 plains 内存缓冲 (JSON 头 + 二进制尾) 计算 keystream
- 验证输入布局假设: input = [JSON 554B][binary L-554B]
"""
import json, binascii, sys
MAGIC = bytes.fromhex('571882cf664bb39401ee')
TRAILER = bytes.fromhex('00400c0b8c980ca80c')
EVID = 'evidence/dfp_pair_sync.json'
def load_pairs():
d = json.load(open(EVID))
pairs = []
for i in range(0, len(d), 2):
w, p = d[i], d[i+1]
raw = binascii.unhexlify(w['hex'])
idx = raw.find(b'\r\n\r\n')
body = raw[idx+4:]
mp = body.find(MAGIC)
assert body.endswith(TRAILER), f"pair{i//2} trailer mismatch"
tag2 = body[mp+10 : len(body)-len(TRAILER)]
plains = []
for pl in p['plains']:
if isinstance(pl, dict) and pl.get('hex'):
plains.append({'addr': pl['addr'], 'buf': binascii.unhexlify(pl['hex'])})
pairs.append({'t': w['t'], 'tag2': tag2, 'plains': plains})
return pairs
def find_json_end(buf):
"""locate the end of the 554B JSON string at buf head; return index after closing brace + boundaries of following non-zero region"""
# JSON starts with '{' at offset 0. Find the matching close at known length 554
if buf[:1] != b'{':
return None
# standard JSON serialized 554B for this device
json_bytes = buf[:554]
assert json_bytes.startswith(b'{"appId":"5008"'), json_bytes[:40]
return 554
def nonzero_ranges(buf, start):
"""return list of (start,end) runs of non-zero bytes in buf[start:]"""
runs = []
in_run = False
for i in range(start, len(buf)):
if buf[i] != 0 and not in_run:
s = i; in_run = True
elif buf[i] == 0 and in_run:
runs.append((s, i)); in_run = False
if in_run:
runs.append((s, len(buf)))
return runs
def main():
pairs = load_pairs()
print(f"{len(pairs)} pairs loaded")
for k, pr in enumerate(pairs):
t2 = pr['tag2']
print(f"\n===== pair{k} t={pr['t']} tag2_len={len(t2)} (data={len(t2)}) =====")
for pi, pl in enumerate(pr['plains']):
buf = pl['buf']
je = find_json_end(buf)
runs = nonzero_ranges(buf, 0) if je else []
# focus: runs after JSON end
post = [r for r in runs if r[0] >= 554]
print(f" plain{pi} addr={pl['addr']} buflen={len(buf)} json@0..{je if je else '?'}")
# show a compact view: for each 256B block 0..8192 whether zero or nonzero
blocks = []
for b in range(0, len(buf), 256):
chunk = buf[b:b+256]
nz = sum(1 for x in chunk if x != 0)
blocks.append(f"{b//256}:{nz}")
print(" nz/256B:", ' '.join(blocks))
# print runs summary first 6
for r in post[:6]:
print(f" nonzero {r[0]}..{r[1]} (len {r[1]-r[0]}) head={buf[r[0]:r[0]+32].hex()}")
if __name__ == '__main__':
main()