- docs/HUYA_APP_OVERVIEW.md: 整体流程/三形态hdid区分/登录入口盘点/随机化矩阵/风险清单/真机Frida现状 - core/huya 各模块 docstring 加风险标记与 hdid 名称混淆提示, 指向总览 - tools/app_login_flow 标注已过时(未接注册链), tools/huya_device_profile 标注与 core 策略关系 - scripts/phone_stable_capture.py + diag_phone_lifecycle.py: 真机 spawn+art_callsite 稳定抓帧/四组诊断 - evidence/diag_phone/: 真机基线/attach/稳定抓帧实验证据 (90s 存活无 EGL 崩)
106 lines
3.6 KiB
Python
106 lines
3.6 KiB
Python
"""虎牙多账号设备画像生成与管理。
|
||
|
||
为每个账号生成并持久化独立的设备身份画像(机型、屏幕、指纹、设备ID等)。
|
||
|
||
注意:画像只承载 *soft* 设备字段(机型/屏幕/随机指纹/随机 device_id)。
|
||
``safedeviceid``(RSA action 令牌)与登录帧 ``device_id`` 由
|
||
:mod:`core.huya.dfp_register` 在每次 WUP 登录前经新设备注册链实时签发,
|
||
不再写入画像,也不再允许任何固定金样本令牌被多账号复用。
|
||
|
||
⚠ 字段状态速览(详见 ``docs/HUYA_APP_OVERVIEW.md`` §四):
|
||
- 随机: fingerprint / 机型 / 屏幕 / 宽高 / device_id(画像侧);
|
||
- 固定: hdid(32hex 硬锚,全账号同一) / app_version / sdk_version;
|
||
- 动态签发: safedeviceid、登录帧 device_id。
|
||
"""
|
||
from __future__ import annotations
|
||
|
||
import hashlib
|
||
import json
|
||
import os
|
||
import random
|
||
from pathlib import Path
|
||
|
||
ROOT = Path(__file__).resolve().parent.parent.parent
|
||
DATA_DIR = ROOT / "data"
|
||
PRIMARY_PROFILE_DB = DATA_DIR / "huya_device_profiles.json"
|
||
FALLBACK_PROFILE_DB = ROOT / "evidence" / "device_profiles.json"
|
||
|
||
REAL_MODELS = [
|
||
("xiaomi", "M2102J2SC", "M2102J2SC,30,11", (1080, 2120)),
|
||
("vivo", "V2370A", "V2370A,34,13", (1080, 2412)),
|
||
("oppo", "PFFM20", "PFFM20,34,13", (1080, 2412)),
|
||
("honor", "SDY-AN00", "SDY-AN00,31,12", (1080, 2400)),
|
||
("samsung", "SM-G9910", "SM-G9910,31,12", (1440, 3200)),
|
||
("oneplus", "PGZ110", "PGZ110,34,13", (1080, 2412)),
|
||
("redmi", "23049PCD8G", "23049PCD8G,34,13", (1080, 2400)),
|
||
("realme", "RMX3366", "RMX3366,34,13", (1080, 2412)),
|
||
("iqoo", "V2183A", "V2183A,34,13", (1080, 2400)),
|
||
("nubia", "NX729J", "NX729J,33,13", (1080, 2400)),
|
||
("motorola", "XT2301-5", "XT2301-5,33,13", (1080, 2400)),
|
||
("gionee", "GN9013", "GN9013,29,10", (720, 1560)),
|
||
]
|
||
|
||
HDID = "ed0db8334cadd236c00cadf7e11ab5a5"
|
||
APP_VERSION = "13.4.22"
|
||
SDK_VERSION = "1.0.80138"
|
||
|
||
|
||
def _rand_sha1_hex() -> str:
|
||
return hashlib.sha1(os.urandom(20)).hexdigest()
|
||
|
||
|
||
def generate_profile(model_pick=None) -> dict:
|
||
"""生成一套随机设备画像。"""
|
||
vendor, model, screen, (w, h) = (
|
||
random.choice(REAL_MODELS) if model_pick is None else model_pick
|
||
)
|
||
return {
|
||
"app_version": APP_VERSION,
|
||
"sdk_version": SDK_VERSION,
|
||
"vendor": vendor,
|
||
"model": model,
|
||
"os": "android",
|
||
"ip": "127.0.0.1",
|
||
"fingerprint": _rand_sha1_hex(),
|
||
"screen": screen,
|
||
"width": str(w),
|
||
"height": str(h),
|
||
"device_id": _rand_sha1_hex(),
|
||
"hdid": HDID,
|
||
# 注: 不含 safedeviceid —— 每次登录前由 dfp_register 注册链签发,
|
||
# 画像不再持久化固定令牌 (见模块注释)。
|
||
}
|
||
|
||
|
||
def _load_db() -> dict:
|
||
if PRIMARY_PROFILE_DB.exists():
|
||
try:
|
||
return json.loads(PRIMARY_PROFILE_DB.read_text("utf-8"))
|
||
except Exception:
|
||
pass
|
||
if FALLBACK_PROFILE_DB.exists():
|
||
try:
|
||
return json.loads(FALLBACK_PROFILE_DB.read_text("utf-8"))
|
||
except Exception:
|
||
pass
|
||
return {}
|
||
|
||
|
||
def _save_db(db: dict) -> None:
|
||
try:
|
||
PRIMARY_PROFILE_DB.parent.mkdir(parents=True, exist_ok=True)
|
||
PRIMARY_PROFILE_DB.write_text(json.dumps(db, indent=2, ensure_ascii=False), encoding="utf-8")
|
||
except Exception:
|
||
pass
|
||
|
||
|
||
def get_profile(account: str, force_new: bool = False) -> dict:
|
||
"""按账号获取或创建画像(幂等:同账号复用同一套)。"""
|
||
db = _load_db()
|
||
if not force_new and account in db:
|
||
return db[account]
|
||
p = generate_profile()
|
||
db[account] = p
|
||
_save_db(db)
|
||
return p
|