type: 收窄虎牙验证与设备注册类型
This commit is contained in:
+43
-17
@@ -23,6 +23,7 @@
|
||||
- ``_random_triple`` 的 64hex 占位只是 cw JSON 模板形态 — 真实 dfpReport 指纹
|
||||
JSON (R36 解密 12 样本) 无 hdid 字段 (顶层 Athena/deviceinfo/terminal/version)。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import base64
|
||||
@@ -74,23 +75,33 @@ def _load_chain() -> dict[str, tuple[bytes, bytes]]:
|
||||
try:
|
||||
data = json.loads(CHAIN_FILE.read_text(encoding="utf-8"))
|
||||
return {
|
||||
name: (base64.b64decode(item["req_b64"]), base64.b64decode(item["resp_b64"]))
|
||||
name: (
|
||||
base64.b64decode(item["req_b64"]),
|
||||
base64.b64decode(item["resp_b64"]),
|
||||
)
|
||||
for name, item in data.items()
|
||||
}
|
||||
except (OSError, ValueError, KeyError) as exc:
|
||||
raise DfpRegistrationError(f"注册链模板读取失败: {exc}") from exc
|
||||
|
||||
|
||||
def _post(body: bytes, content_type: str = "application/octet-stream",
|
||||
timeout: float = 20, proxies: Mapping[str, str] | None = None) -> bytes:
|
||||
def _post(
|
||||
body: bytes,
|
||||
content_type: str = "application/octet-stream",
|
||||
timeout: float = 20,
|
||||
proxies: Mapping[str, str] | None = None,
|
||||
) -> bytes:
|
||||
try:
|
||||
response = requests.post(
|
||||
WSAPI,
|
||||
data=body,
|
||||
headers={"Content-Type": content_type, "User-Agent": UA,
|
||||
"Accept-Encoding": "gzip"},
|
||||
headers={
|
||||
"Content-Type": content_type,
|
||||
"User-Agent": UA,
|
||||
"Accept-Encoding": "gzip",
|
||||
},
|
||||
timeout=timeout,
|
||||
proxies=proxies,
|
||||
proxies=dict(proxies) if proxies else None,
|
||||
)
|
||||
response.raise_for_status()
|
||||
return response.content
|
||||
@@ -130,11 +141,16 @@ def _build_random_dfp_body() -> bytes:
|
||||
json_sec = os.urandom(CW_JSON_LEN)
|
||||
if len(seed) <= CW_JSON_LEN:
|
||||
mask = os.urandom(len(seed))
|
||||
json_sec = bytes(a ^ b for a, b in zip(seed, mask)) + json_sec[len(seed):]
|
||||
json_sec = bytes(a ^ b for a, b in zip(seed, mask)) + json_sec[len(seed) :]
|
||||
cw = os.urandom(2) + json_sec + os.urandom(CW_COLL_LEN) + CW_TAIL
|
||||
if len(cw) != CW_LEN:
|
||||
raise DfpRegistrationError(f"dfpReport cw 长度异常: {len(cw)}")
|
||||
body = struct.pack(">I", len(TAF_HEAD) + len(MAGIC) + len(cw) + 4) + TAF_HEAD + MAGIC + cw
|
||||
body = (
|
||||
struct.pack(">I", len(TAF_HEAD) + len(MAGIC) + len(cw) + 4)
|
||||
+ TAF_HEAD
|
||||
+ MAGIC
|
||||
+ cw
|
||||
)
|
||||
if len(body) != 4226:
|
||||
raise DfpRegistrationError(f"dfpReport body 长度异常: {len(body)}")
|
||||
return body
|
||||
@@ -145,23 +161,34 @@ def _select_operator_request(template: bytes, fingerprint: str | None) -> bytes:
|
||||
old = b"02df398797432eadefcc12767119ad5e80999389"
|
||||
index = template.find(old)
|
||||
if index >= 0:
|
||||
return template[:index] + fingerprint.encode("ascii") + template[index + len(old):]
|
||||
return (
|
||||
template[:index]
|
||||
+ fingerprint.encode("ascii")
|
||||
+ template[index + len(old) :]
|
||||
)
|
||||
return template
|
||||
|
||||
|
||||
def _parse_response(data: bytes) -> tuple[str, str, str]:
|
||||
try:
|
||||
t1 = re.search(rb"\x16\x20([0-9a-f]{32})", data).group(1).decode()
|
||||
t2 = re.search(rb"\x26\xb4([A-Za-z0-9+/=]{180})", data).group(1).decode("latin1")
|
||||
t5 = re.search(rb"\x56\x28([0-9a-f]{40})", data).group(1).decode()
|
||||
except AttributeError as exc:
|
||||
t1_match = re.search(rb"\x16\x20([0-9a-f]{32})", data)
|
||||
t2_match = re.search(rb"\x26\xb4([A-Za-z0-9+/=]{180})", data)
|
||||
t5_match = re.search(rb"\x56\x28([0-9a-f]{40})", data)
|
||||
if not t1_match or not t2_match or not t5_match:
|
||||
raise ValueError("missing response fields")
|
||||
t1 = t1_match.group(1).decode()
|
||||
t2 = t2_match.group(1).decode("latin1")
|
||||
t5 = t5_match.group(1).decode()
|
||||
except (AttributeError, ValueError) as exc:
|
||||
raise DfpRegistrationError("dfpReport 响应缺少 t1/t2/t5") from exc
|
||||
return t1, t2, t5
|
||||
|
||||
|
||||
def register_device(fingerprint: str | None = None,
|
||||
proxies: Mapping[str, str] | None = None,
|
||||
timeout: float = 20) -> tuple[str, str, str]:
|
||||
def register_device(
|
||||
fingerprint: str | None = None,
|
||||
proxies: Mapping[str, str] | None = None,
|
||||
timeout: float = 20,
|
||||
) -> tuple[str, str, str]:
|
||||
"""执行新注册链,返回 ``(t1, safedeviceid, device_id)``。"""
|
||||
chain = _load_chain()
|
||||
_post(chain["getDfpConfig"][0], timeout=timeout, proxies=proxies)
|
||||
@@ -169,4 +196,3 @@ def register_device(fingerprint: str | None = None,
|
||||
_post(select_request, "application/x-wup", timeout, proxies)
|
||||
response = _post(_build_random_dfp_body(), timeout=timeout, proxies=proxies)
|
||||
return _parse_response(response)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user