web_cookie_fields 用逆向算法替换随机:__yamid_new=UUIDv1时间戳复刻、game_did=35位63字符集、_yasids同源、_qimei_uuid42=1a前缀、guid回退加固定段
This commit is contained in:
@@ -17,8 +17,8 @@ status=200(和平精英已绑定)、getUserScore 返回 status=200(积分
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import random
|
||||||
import secrets
|
import secrets
|
||||||
import string
|
|
||||||
import time
|
import time
|
||||||
|
|
||||||
# 统计/会话字段生成规则;9.1 抓包值为样例,格式保持对齐
|
# 统计/会话字段生成规则;9.1 抓包值为样例,格式保持对齐
|
||||||
@@ -30,6 +30,71 @@ _FILL_MAP: tuple[tuple[str, str], ...] = (
|
|||||||
("udb_accdata", "undefined"),
|
("udb_accdata", "undefined"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 浏览器实测逆向(2026-09-01,见 docs/HUYA_WEB_FIELD_TRACE.md):
|
||||||
|
# - __yamid_new: room_normal.js generate32(UUID-v1 风格,1582-epoch 本地时区时间戳
|
||||||
|
# + v1 版本位 + 时钟序列 + 48 位随机 node)。浏览器 epoch = new Date(1582,10,15,
|
||||||
|
# 0,0,0,0).getTime() 实测 -12216643543000(GMT+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_did:35 位随机,字符集 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:
|
def _rand_float() -> str:
|
||||||
import random
|
import random
|
||||||
@@ -78,15 +143,17 @@ def fill_web_cookie_fields(
|
|||||||
else:
|
else:
|
||||||
add("guid", str(guid))
|
add("guid", str(guid))
|
||||||
elif "guid" not in pairs:
|
elif "guid" not in pairs:
|
||||||
add("guid", secrets.token_hex(16))
|
# guid 结构: '0a' + 10hex + '956a'/'966a' + 16hex(浏览器实测固定段,见 trace 文档)
|
||||||
add("_qimei_uuid42", secrets.token_hex(21)) # 42 hex
|
add("guid", "0a" + secrets.token_hex(5) + "966a" + secrets.token_hex(8))
|
||||||
add("__yamid_new", secrets.token_hex(16).upper()) # 32 hex 大写
|
# _qimei_uuid42: QIMEI SDK 产物,cookie 首字节 '1a' + UUID 布局 32hex + 8hex 附加
|
||||||
alnum = string.ascii_letters + string.digits
|
add("_qimei_uuid42", "1a" + secrets.token_hex(20))
|
||||||
import random
|
# __yamid_new: room_normal.js generate32 精确复刻(UUID-v1 时间戳,含 CBCC 前缀规律)
|
||||||
|
add("__yamid_new", _yamid_new_generate32())
|
||||||
add("game_did", "".join(random.choices(alnum, k=30))) # 30 位字母数字
|
add("game_did", _game_did_generate()) # 35 位随机(真实长度)
|
||||||
|
|
||||||
# qimei 皮肤字段
|
# qimei 皮肤字段
|
||||||
|
# _qimei_fingerprint: QIMEI SDK SpookyHashV2(canvas指纹,31) 32hex;设备稳定,
|
||||||
|
# 无真实 canvas 时可随机(格式 32hex 对齐),真实算法见 trace 文档
|
||||||
add("_qimei_fingerprint", secrets.token_hex(16))
|
add("_qimei_fingerprint", secrets.token_hex(16))
|
||||||
add("_qimei_h38", secrets.token_hex(19))
|
add("_qimei_h38", secrets.token_hex(19))
|
||||||
|
|
||||||
@@ -99,7 +166,8 @@ def fill_web_cookie_fields(
|
|||||||
add("h_unt", str(int(time.time())))
|
add("h_unt", str(int(time.time())))
|
||||||
if uid:
|
if uid:
|
||||||
add("__yaoldyyuid", str(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_lvt_51700b6c722f5bb4cf39906a596ea41f", str(int(time.time())))
|
||||||
add("Hm_lpvt_51700b6c722f5bb4cf39906a596ea41f", str(int(time.time())))
|
add("Hm_lpvt_51700b6c722f5bb4cf39906a596ea41f", str(int(time.time())))
|
||||||
add("HMACCOUNT", secrets.token_hex(8).upper())
|
add("HMACCOUNT", secrets.token_hex(8).upper())
|
||||||
|
|||||||
@@ -86,3 +86,47 @@ qimeisdk-web 0.6.3 源码已定位:
|
|||||||
2. `guid` 采样更多样本确认固定段后按 `0a` + 结构仿造
|
2. `guid` 采样更多样本确认固定段后按 `0a` + 结构仿造
|
||||||
3. `__yamid_new` 需找到生成它的具体脚本(非 document.cookie 写入,可能在
|
3. `__yamid_new` 需找到生成它的具体脚本(非 document.cookie 写入,可能在
|
||||||
ubtk/埋点脚本里)做种子同步
|
ubtk/埋点脚本里)做种子同步
|
||||||
|
## 六、核心字段生成算法逆向结果(2026-09-01 晚,浏览器实测 + 源码定位)
|
||||||
|
|
||||||
|
### ✅ __yamid_new = room_normal.js generate32(UUID-v1 风格,已 Python 复刻验证)
|
||||||
|
```js
|
||||||
|
// a.msstatic.com/huya/main3/app/room_normal_55c7cc4f.js
|
||||||
|
function u(e){var t="__yamid_new",n=getCookieVal(t);if(n)return n;n=e||d.generate32();...writeCookie(t,n,...)}
|
||||||
|
d.generate32(){
|
||||||
|
c = new Date().getTime() - new Date(1582,10,15,0,0,0,0).getTime(); // 本地时区 epoch
|
||||||
|
return generateBits(c,0,31) // time_low 8hex
|
||||||
|
+ generateBits(c,32,47) // time_mid 4hex
|
||||||
|
+ generateBits(c,48,59)+"1" // time_hi+版本位
|
||||||
|
+ generateBits(rand(4095),0,7) + generateBits(rand(4095),0,7)
|
||||||
|
+ generateBits(rand(8191),0,7)+... 48位随机node;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 浏览器实测 epoch(GMT+8): `-12216643543000`;Python 复刻 12hex 时间戳段与浏览器**逐位一致**
|
||||||
|
- **`CBCC` 前缀是时间戳自然结果**(1582-epoch 当前值的高位),非固定魔数;随生成时刻缓慢递增
|
||||||
|
- `_yasids`(rootsid)同源同刻生成(浏览器实测 yamid=`CBCC653E4B...` / rootsid=`CBCC647A8A...` 共享种子时钟)
|
||||||
|
|
||||||
|
### ✅ game_did = vplayerUI.js 35 位随机(已复刻)
|
||||||
|
```js
|
||||||
|
// a.msstatic.com/huya/h5player/room/2608311423/vplayerUI.js
|
||||||
|
B = (t=35) => { const e="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
|
||||||
|
for(i="";i.length<t;) i += e.charAt(parseInt(Math.random()*(e.length-1))); return i }
|
||||||
|
```
|
||||||
|
- **长度 35**(旧随机 30 位是错的);字符集 64 去掉末尾 `_`(63 选 1)
|
||||||
|
- cookie 名 `game_did`,无 cookie 时生成并写入
|
||||||
|
|
||||||
|
### ⚠️ _qimei_uuid42 结构已定,算法待深挖
|
||||||
|
- cookie 值:首字节 `1a` 固定 + 40hex(localStorage 是 44hex,cookie 为截断子串)
|
||||||
|
- 由 qimeisdk-web 0.6.3 内部 VM 生成(`_qimei_ssid`/`_qimei_last_get_id_time_<16hex>` 同源)
|
||||||
|
- 当前实现对齐结构(1a 前缀 + 42hex 随机化),精确算法待继续
|
||||||
|
|
||||||
|
### ⚠️ _qimei_fingerprint = SpookyHashV2(canvas指纹,31),待 canvas 复现
|
||||||
|
- SDK 0.6.3 内置 x64hash128 与 canvas 指纹逻辑(文本+三圆+环形)
|
||||||
|
- 设备稳定(同 profile 跨会话不变);当前实现随机 32hex 格式对齐
|
||||||
|
- 复现需在真实环境执行 canvas(headless 下 canvas 指纹固定,可抽取一次固化为常量)
|
||||||
|
|
||||||
|
### 已修正生成器(core/huya/web_cookie_fields.py, commit 待定)
|
||||||
|
- `__yamid_new` → `_yamid_new_generate32()`(UUID-v1 时间戳复刻)
|
||||||
|
- `game_did` → `_game_did_generate()`(35 位 63 字符集)
|
||||||
|
- `_yasids` → 与 `__yamid_new` 同源同刻生成
|
||||||
|
- `_qimei_uuid42` → `1a` 前缀 + 42hex
|
||||||
|
- `guid`(无会话值回退)→ `0a` + 10hex + `966a` + 16hex 结构
|
||||||
|
|||||||
Reference in New Issue
Block a user