7.0 KiB
虎牙精英宝典 9.1 全流程分析(Python / 脱敏)
branch/field: HUYA_ELITE_FULL_FLOW_9_1
1. 样本与完整性
- 主样本:
/Users/yml/Desktop/抓包/hy/9.1/9.1 - SHA-256:
807fb951f9daa21e77f33618f1409a99b9b44da829966f328ec8b0614f599d55 - 格式:Charles 会话 ZIP 归档,不是普通 HAR。
- 归档成员 2327;
*-meta.json1472;请求体 552;响应体 303。 - 状态:COMPLETE 1443,EXCEPTION 16,RECEIVING_REQUEST_BODY 12,RECEIVING_RESPONSE_BODY 1。
- 结论:该包覆盖扫码登录后的 Web 会话、宝典初始化、游戏账号绑定、积分兑换、商城下单、支付宝二维码和支付后订单状态;比旧的 Reqable/Charles 样本完整。
9.1_all 适合静态资源检索,但没有统一 flow、headers、状态和时序索引。协议重建以 ZIP 为主,静态页面以 1197-res.html 等正文为辅。
2. 业务固定值与动态值
本次页面确认的业务值:sid=2203、宝典 actId=25135、绑定活动 bActId=9271、任务模块 moduleId=20051、外部联运活动 17096、游戏 cjm、组件 gid=3203、宝典商品 spu=hy-5879340、商品 SKU 5370360、供应商 87401。
运行时必须重新取得:UID、Cookie、WSS baseinfo、WUP requestId、wsLaunch guid、游戏账号信息、getLiveLinkParam 的 t/code/sig、支付宝 payOrderId/ctoken、订单号和二维码状态。样本中的这些动态值不能硬编码,也不能用旧 Cookie 重放。
3. 登录与宝典初始化
- 扫码登录链在登录样本中完成后,
POST /web/cookie/verify(entry 859)返回 HTTP 业务成功结构,随后浏览器访问宝典页面(entry 1197,HTTP 200)。 - 宝典主 WSS 为
d35bf373-ws.va.huya.com(entry 828),完成launch.wsLaunch、mobileui.getConfig、心跳/确认和业务 RPC。 - 主链首先调用
checkUserBindGameAccount、getActInfo、getActUserTaskDetail、getUserScore、getUserPrizeRecords、getEntityPrizeFieldMap、getModuleAddress、getLiveLinkParam。 getActInfo返回 status 200,活动名“活动+购买任务”,活动时间戳区间、模块 20051、外部活动 17096、游戏 cjm 和组件 3203。
WSS 帧为二进制 WebSocket payload,前 6 字节是 command/sequence,body 是 WUP/TAF。项目已有 WssMessage.decode() 和 _decode_wup_body(),同一连接的 requestId 运行时递增;不要把 frame sequence 或样本 requestId 当业务主键。
4. 积分兑换闭环
4.1 绑定和前置查询
- 首次绑定响应显示游戏“和平精英”;绑定状态会经历未绑定、已绑定和确认后状态,
confirmBindActAccount返回status=200,msg=请求成功。 getLiveLinkParam返回外部活动17096、gameIdList=cjm、livePlatId=huya和动态t/code/sig。签名算法证据不足,客户端只转发实时响应。getActPrizeDetail(sid=2203,pid=12861)返回奖品“幸运币礼包(小)”,兑换积分 20,库存/时间/限制字段来自服务端。
4.2 写入与回查
请求:webActUI.scoreExchangePrize,字段为 userId、sid=2203、pid=12861、ip、clientEnv、source、isRole=1。本样本的空 ip/source/clientEnv 是一次浏览器操作结果,不应成为固定规则。
响应:status=200,msg=请求成功,返回兑换订单标识和 exchangeInfo(pid=12861,exchangeScore=20,desc=兑换奖品:幸运币礼包(小))。敏感订单标识已省略。
写入后浏览器按顺序回查 getUserScore、getUserPrizeRecords、getEntityPrizeFieldMap、getModuleAddress。实测积分从可用 300 变为 280,兑换记录新增该奖品、20 分和当日日期;这证明兑换链在该包中闭合。UI 应以回查值为准,并对 isCanExchange、活动时间、库存、今日/用户限制和可用积分做二次校验。
5. 开通宝典与支付闭环
商城 WSS 为 wsapi.huya.com(entry 1431),初始化后业务顺序为:
getGoodsInfoV5(pid=直播间上下文, spuId=hy-5879340, skuId=5370360):商品名“精英宝典”,说明“得300积分丨解锁道具兑换权益”,标价 3000(分);响应关联活动绑定信息和bActId=9271。getSupplierInfoV5(supplierId=87401):返回“和平精英官方小店”。listPayChannelV5:可用渠道为Zfb、Weixin。checkHyProtocolV5:协议检查成功,状态 200。PlayMallUI.getMyPromotion、calcOrderPromotion:本单无返利,订单金额为 3000 分/人民币 30.00 的商城商品金额。checkUserBuyAuth:状态 200,允许创建订单。createOrderV5:状态 200,返回商城内部订单标识、支付前订单状态和应付金额;样本值已脱敏。payOrderSubmitV5(order, channel=Zfb, payType=QrCode):状态 200,返回支付宝网关跳转 URL、支付流水标识和回调地址。URL 中包含 RSA2 签名,客户端应把它当作服务端生成的短期跳转值,不能自行拼接或重签。orderDetailV5(orderId)多次轮询:前期订单状态为待支付,支付确认后变为完成状态(状态码 50),支付金额保持 3000;batchQueryBuyAfterConfig随后返回商城后置配置。- 支付 HTTP 链:支付宝网关 ->
unitradeprod.alipay.com/appAssign.htm->excashier.alipay.com/standard/auth.htm->queryQRStatus.json。首次查询返回qrStatus=normal,后续查询返回已登录/已确认状态(qrStatus=2),二维码状态由支付宝控制,不能由客户端伪造。
订单状态 50 是商城订单完成证据;宝典页面的购买任务积分/权益应再调用 getUserScore、getActUserTaskDetail 和相关宝典查询确认,不能仅凭支付宝页面成功推断权益到账。
6. Python 实现建议
仓库现有 core.huya.wss_client.HuyaWssClient、core.huya.http_client.HuyaHttpClient、activity_structs.py 和 shop_structs.py 已覆盖 WUP/TAF 结构及大部分查询。scripts/huya_elite_client.py 可作为查询入口:
client.snapshot() # 活动、任务、绑定、奖品、积分、记录
# 用户明确确认后:实时 getActPrizeDetail -> scoreExchangePrize -> 三项回查
# 开通:getGoodsInfoV5 -> checkUserBuyAuth -> createOrderV5
# -> payOrderSubmitV5 -> orderDetailV5 轮询 -> 宝典权益回查
建议将状态机拆为 login_session、elite_snapshot、exchange、purchase 四步;所有动态字段从前序响应传递,错误时保留服务端 status/msg,不猜测签名算法。写操作默认幂等保护:同一用户、同一 pid 在收到成功响应后不重复提交,只做回查。
7. 证据边界
- 归档已证明兑换成功和商城订单完成,但没有提供支付宝私钥、服务端签名算法或可脱离当前登录态的重放凭据。
getEntityPrizeFieldMap/getModuleAddress在本次兑换奖品上返回无地址,不代表所有实物奖品都无需地址;实际奖品类型必须按最新响应决定。- 订单完成到宝典积分到账可能存在异步延迟,工作台应轮询业务接口而非只看支付状态。