修正QIMEI UUID42随机段生成
This commit is contained in:
@@ -276,8 +276,9 @@ def _qimei_uuid42_generate(
|
||||
``now_ns`` 保留旧回退函数的纳秒参数约定;SDK 实际只读取本地时间的
|
||||
年/月/日/时/分/秒,因此毫秒和纳秒不会进入结果。时间前缀的年份和月份
|
||||
使用 SDK 的十六进制编码,最后三位来自 ``navigator.cookieEnabled``。
|
||||
``random_value`` 仅用于固定测试;生产调用沿用 ``Math.random()`` 等价的
|
||||
Python ``random.random()``,并将理论上的 1.0 夹到合法半字节上界 15。
|
||||
``random_value`` 仅用于固定测试;生产调用会像 SDK 一样独立调用 20 次
|
||||
``Math.random()`` 等价的 Python ``random.random()``,并将理论上的 1.0
|
||||
夹到合法半字节上界 15。
|
||||
"""
|
||||
now_ms = time.time_ns() // 1_000_000 if now_ns is None else now_ns // 1_000_000
|
||||
current = datetime.fromtimestamp(now_ms / 1000, tz=UTC).astimezone()
|
||||
@@ -292,12 +293,14 @@ def _qimei_uuid42_generate(
|
||||
)
|
||||
prefix = year_hex + month_hex + date_parts + ("100" if cookie_enabled else "000")
|
||||
|
||||
value = random.random() if random_value is None else float(random_value)
|
||||
nibble = min(15, max(0, int(value * 16)))
|
||||
repeated = f"{nibble:x}" * 20
|
||||
template = prefix + "----" + repeated + "----"
|
||||
random_source = random.random if random_value is None else lambda: random_value
|
||||
random_segment = "".join(
|
||||
f"{min(15, max(0, int(float(random_source()) * 16))):x}"
|
||||
for _ in range(20)
|
||||
)
|
||||
template = prefix + "----" + random_segment + "----"
|
||||
replacement = f"{zlib.crc32(template.encode('ascii')) & 0xFFFFFFFF:08x}"
|
||||
return prefix + replacement[:4] + repeated + replacement[4:]
|
||||
return prefix + replacement[:4] + random_segment + replacement[4:]
|
||||
|
||||
|
||||
def fill_web_cookie_fields(
|
||||
|
||||
@@ -68,6 +68,7 @@ random=0.25 17b0f060d14100037f4444444444444444444437df
|
||||
random=0.5 17b0f060d1410053db888888888888888888883ff6
|
||||
random=0.75 17b0f060d14100966bcccccccccccccccccccc1cf3
|
||||
random=.999 17b0f060d141003174ffffffffffffffffffffd85d
|
||||
sequence=0..f,0..3 17b0f060d14100b2230123456789abcdef012396a9
|
||||
```
|
||||
|
||||
每个值都可以拆成 `14 + 4 + 20 + 4 = 42` 位。时间前缀由本地时间组成:年份末两位转十六进制并补两位、月份转十六进制、日/时/分/秒转十六进制并各补两位,最后追加 `cookieEnabled ? 100 : 000`。中间 20 位是 `floor(Math.random() * 16)` 对应的十六进制半字节重复。两个 `----` 占位组成模板后,SDK 对模板 ASCII 字节计算标准 CRC32(多项式 `0xEDB88320`),将 8 位小写结果的前后四位分别替换占位,最后调用 `toLocaleLowerCase()`。Python 实现位于 `core/huya/web_cookie_fields.py`,并用上述固定向量回归;随机上界按 15 处理,避免理论输入 `1.0` 产生两位半字节。VM 追踪在 `/tmp/qvmtrace17.out`,生成器入口为 `e=6064`,模板拼接和替换发生在 `m≈5015..5137`。该实现只用于查询链路的设备态生成,不触发兑换、下单或支付。
|
||||
每个值都可以拆成 `14 + 4 + 20 + 4 = 42` 位。时间前缀由本地时间组成:年份末两位转十六进制并补两位、月份转十六进制、日/时/分/秒转十六进制并各补两位,最后追加 `cookieEnabled ? 100 : 000`。中间 20 位由 20 次独立的 `floor(Math.random() * 16)` 依次拼接;上面的单值向量因为探针固定了每次随机返回值,所以表现为相同半字节重复。两个 `----` 占位组成模板后,SDK 对模板 ASCII 字节计算标准 CRC32(多项式 `0xEDB88320`),将 8 位小写结果的前后四位分别替换占位,最后调用 `toLocaleLowerCase()`。Python 实现位于 `core/huya/web_cookie_fields.py`,并用上述固定与递增序列向量回归;随机上界按 15 处理,避免理论输入 `1.0` 产生两位半字节。VM 追踪在 `/tmp/qvmtrace17.out`,生成器入口为 `e=6064`,模板拼接和替换发生在 `m≈5015..5137`。该实现只用于查询链路的设备态生成,不触发兑换、下单或支付。
|
||||
|
||||
@@ -64,7 +64,7 @@ CBCC 06ECB5 0000 0001 B63016D6162BC990 ← reqable 8.31
|
||||
17b0f060d1410053db888888888888888888883ff6 ← 固定时间/随机 .5
|
||||
17b0f060d141003174ffffffffffffffffffffd85d ← 固定时间/随机 .999
|
||||
```
|
||||
时间前缀的编码为:年份末两位十六进制(补两位)+ 月份十六进制 + 日/时/分/秒各两位十六进制 + `cookieEnabled` 标志(`100`/`000`)。模板 `prefix + "----" + nibble * 20 + "----"` 的标准 CRC32 小写结果会拆成前后四位填回两个占位;`nibble = floor(Math.random() * 16)`,因此合法范围为 `0` 到 `f`。
|
||||
时间前缀的编码为:年份末两位十六进制(补两位)+ 月份十六进制 + 日/时/分/秒各两位十六进制 + `cookieEnabled` 标志(`100`/`000`)。模板 `prefix + "----" + random_nibbles + "----"` 的标准 CRC32 小写结果会拆成前后四位填回两个占位;`random_nibbles` 由 20 次独立的 `floor(Math.random() * 16)` 依次拼接,因此每位合法范围为 `0` 到 `f`。
|
||||
|
||||
### _qimei_fingerprint = x64hash128(feature_string, 31) 32hex
|
||||
qimeisdk-web 0.6.3 源码已定位:
|
||||
@@ -121,10 +121,10 @@ B = (t=35) => { const e="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012
|
||||
清理 localStorage/cookie 后对 QIMEI SDK 0.6.3 做固定时间、固定随机值追踪,定位到 VM 生成器 `e=6064`。它先拼出:
|
||||
|
||||
```text
|
||||
14 位时间前缀 + "----" + 20 位随机半字节重复串 + "----"
|
||||
14 位时间前缀 + "----" + 20 次独立抽样组成的随机半字节串 + "----"
|
||||
```
|
||||
|
||||
随后计算模板 ASCII 字节的标准 CRC32,将 8 位小写结果的前 4 位和后 4 位分别填入占位,最后调用 `toLocaleLowerCase()`。例如 `random=0.25` 的模板是 `17b0f060d14100----44444444444444444444----`,替换值是 `037f37df`,结果为 `17b0f060d14100037f4444444444444444444437df`。`navigator.cookieEnabled` 只影响时间前缀末三位(`100`/`000`)。
|
||||
随后计算模板 ASCII 字节的标准 CRC32,将 8 位小写结果的前 4 位和后 4 位分别填入占位,最后调用 `toLocaleLowerCase()`。例如固定每次 `random=0.25` 时,模板是 `17b0f060d14100----44444444444444444444----`,替换值是 `037f37df`,结果为 `17b0f060d14100037f4444444444444444444437df`;递增序列探针则得到随机段 `0123456789abcdef0123`,证明 SDK 会独立抽样 20 次。`navigator.cookieEnabled` 只影响时间前缀末三位(`100`/`000`)。
|
||||
- 由 qimeisdk-web 0.6.3 内部 VM 生成(`_qimei_ssid`/`_qimei_last_get_id_time_<16hex>` 同源);字段本身为 42 位小写十六进制。
|
||||
- Python 实现按 SDK 时间、CRC32 和随机上界复刻,固定向量覆盖 `0`、`.25`、`.5`、`.75`、`.999`。
|
||||
|
||||
|
||||
@@ -61,6 +61,22 @@ def test_qimei_uuid42_matches_sdk_vectors_and_random_upper_bound():
|
||||
assert all(ch in "0123456789abcdef" for ch in upper)
|
||||
|
||||
|
||||
def test_qimei_uuid42_uses_twenty_independent_random_draws(monkeypatch):
|
||||
values = iter(value / 16 for value in (*range(16), *range(4)))
|
||||
calls = 0
|
||||
|
||||
def next_random():
|
||||
nonlocal calls
|
||||
calls += 1
|
||||
return next(values)
|
||||
|
||||
monkeypatch.setattr("core.huya.web_cookie_fields.random.random", next_random)
|
||||
assert _qimei_uuid42_generate(1700000000000000000) == (
|
||||
"17b0f060d14100b2230123456789abcdef012396a9"
|
||||
)
|
||||
assert calls == 20
|
||||
|
||||
|
||||
def test_qimei_uuid42_encodes_local_date_and_cookie_flag():
|
||||
base = 1700000000000000000
|
||||
assert _qimei_uuid42_generate(base, random_value=0, cookie_enabled=False) == (
|
||||
@@ -75,7 +91,7 @@ def test_qimei_uuid42_handles_year_zero_padding():
|
||||
|
||||
|
||||
def test_sdk_uuid42_trace_vectors_have_confirmed_outer_layout():
|
||||
"""锁定 SDK 追踪确认的 14+4+20+4 外层布局,不约束未闭合的替换算法。"""
|
||||
"""锁定 SDK 追踪确认的 14+4+20+4 外层布局和固定随机向量。"""
|
||||
vectors = {
|
||||
0.0: "17b0f060d1410085cc000000000000000000003207",
|
||||
0.25: "17b0f060d14100037f4444444444444444444437df",
|
||||
|
||||
Reference in New Issue
Block a user