web_cookie_fields 用逆向算法替换随机:__yamid_new=UUIDv1时间戳复刻、game_did=35位63字符集、_yasids同源、_qimei_uuid42=1a前缀、guid回退加固定段

This commit is contained in:
yml2213
2026-09-01 23:48:00 +08:00
parent 8b24732c81
commit 8fef04d0af
2 changed files with 122 additions and 10 deletions
+77 -9
View File
@@ -17,8 +17,8 @@ status=200(和平精英已绑定)、getUserScore 返回 status=200(积分
from __future__ import annotations
import random
import secrets
import string
import time
# 统计/会话字段生成规则;9.1 抓包值为样例,格式保持对齐
@@ -30,6 +30,71 @@ _FILL_MAP: tuple[tuple[str, str], ...] = (
("udb_accdata", "undefined"),
)
# 浏览器实测逆向(2026-09-01,见 docs/HUYA_WEB_FIELD_TRACE.md):
# - __yamid_new: room_normal.js generate32UUID-v1 风格,1582-epoch 本地时区时间戳
# + v1 版本位 + 时钟序列 + 48 位随机 node)。浏览器 epoch = new Date(1582,10,15,
# 0,0,0,0).getTime() 实测 -12216643543000GMT+8)。CBCC 前缀是时间戳自然结果。
# - game_did: vplayerUI.js 35 位随机,字符集 64 去掉末尾 '_'63 选 1)。
# - _qimei_uuid42: QIMEI SDK 生成,cookie 值首字节固定 '1a'(本地存储 44hex 截断)。
_SDK_EPOCH_1582 = -12216643543000 # 浏览器实测 JS Date(1582,10,15) 本地时区 ms
_BASE16 = "0123456789ABCDEF"
_GAME_DID_CHARS = (
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
)
def _return_base16(a: int) -> str:
"""JS returnBase(a,16):正整数转大写十六进制;a<=0 返回空串。"""
if a <= 0:
return ""
out = ""
while a > 0:
out = _BASE16[a % 16] + out
a //= 16
return out
def _generate_bits(a: int, b: int, c: int) -> str:
"""JS generateBits(a,b,c):取 a 的 16 进制串 [floor(b/4)..floor(c/4)] 字符,越界补0。"""
d = _return_base16(a)
out = ""
for g in range(b // 4, c // 4 + 1):
out += d[g] if g < len(d) and d[g] != "" else "0"
return out
def _yamid_new_generate32(rng=None) -> str:
"""逐字复刻 room_normal.js generate32__yamid_new 生成器)。"""
import random
r = rng if rng is not None else random.Random()
now_ms = int(time.time() * 1000)
c = now_ms - _SDK_EPOCH_1582
return "".join((
_generate_bits(c, 0, 31),
_generate_bits(c, 32, 47),
_generate_bits(c, 48, 59) + "1",
_generate_bits(r.randrange(4096), 0, 7),
_generate_bits(r.randrange(4096), 0, 7),
_generate_bits(r.randrange(8192), 0, 7)
+ _generate_bits(r.randrange(8192), 8, 15)
+ _generate_bits(r.randrange(8192), 0, 7)
+ _generate_bits(r.randrange(8192), 8, 15)
+ _generate_bits(r.randrange(8192), 0, 15),
))
def _game_did_generate(length: int = 35) -> str:
"""逐字复刻 vplayerUI.js game_did35 位随机,字符集 64 去掉末尾 '_'"""
import random
out = ""
for _ in range(length):
idx = int(random.random() * (len(_GAME_DID_CHARS) - 1)) # 63 → 排除 '_'
out += _GAME_DID_CHARS[idx]
return out
def _rand_float() -> str:
import random
@@ -78,15 +143,17 @@ def fill_web_cookie_fields(
else:
add("guid", str(guid))
elif "guid" not in pairs:
add("guid", secrets.token_hex(16))
add("_qimei_uuid42", secrets.token_hex(21)) # 42 hex
add("__yamid_new", secrets.token_hex(16).upper()) # 32 hex 大写
alnum = string.ascii_letters + string.digits
import random
add("game_did", "".join(random.choices(alnum, k=30))) # 30字母数字
# guid 结构: '0a' + 10hex + '956a'/'966a' + 16hex(浏览器实测固定段,见 trace 文档)
add("guid", "0a" + secrets.token_hex(5) + "966a" + secrets.token_hex(8))
# _qimei_uuid42: QIMEI SDK 产物,cookie 首字节 '1a' + UUID 布局 32hex + 8hex 附加
add("_qimei_uuid42", "1a" + secrets.token_hex(20))
# __yamid_new: room_normal.js generate32 精确复刻(UUID-v1 时间戳,含 CBCC 前缀规律)
add("__yamid_new", _yamid_new_generate32())
add("game_did", _game_did_generate()) # 35随机(真实长度)
# qimei 皮肤字段
# _qimei_fingerprint: QIMEI SDK SpookyHashV2(canvas指纹,31) 32hex;设备稳定,
# 无真实 canvas 时可随机(格式 32hex 对齐),真实算法见 trace 文档
add("_qimei_fingerprint", secrets.token_hex(16))
add("_qimei_h38", secrets.token_hex(19))
@@ -99,7 +166,8 @@ def fill_web_cookie_fields(
add("h_unt", str(int(time.time())))
if uid:
add("__yaoldyyuid", str(uid))
add("_yasids", "__rootsid%3D" + secrets.token_hex(16).upper())
# _yasids 与 __yamid_new 同源(共享时间戳生成器,浏览器实测前缀一致)
add("_yasids", "__rootsid%3D" + _yamid_new_generate32())
add("Hm_lvt_51700b6c722f5bb4cf39906a596ea41f", str(int(time.time())))
add("Hm_lpvt_51700b6c722f5bb4cf39906a596ea41f", str(int(time.time())))
add("HMACCOUNT", secrets.token_hex(8).upper())