ksjsb/core/weapon_mf.py
2026-07-30 20:25:56 +08:00

183 lines
5.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""纯 Python 复现 ``new mf(context, event).a()`` 的设备状态 JSON。"""
from __future__ import annotations
import hashlib
import json
import time
from dataclasses import dataclass
from typing import Any, Mapping
from .device_profile import DeviceProfile
from .weapon_vimg import generate_passport_account_image
@dataclass(frozen=True)
class WeaponRuntimeSnapshot:
"""一次 WeaponHI 上报使用的易变 Android 运行时状态。"""
now_ms: int
elapsed_realtime_ms: int
uptime_ms: int
boot_count: int
report_counter: int = 1
def __post_init__(self) -> None:
if self.now_ms < 0:
raise ValueError("now_ms must not be negative")
if self.elapsed_realtime_ms < 0:
raise ValueError("elapsed_realtime_ms must not be negative")
if not 0 <= self.uptime_ms <= self.elapsed_realtime_ms:
raise ValueError("uptime_ms must be between 0 and elapsed_realtime_ms")
if self.boot_count < 0 or self.report_counter < 1:
raise ValueError("boot_count/report_counter out of range")
@classmethod
def fresh(
cls,
profile: DeviceProfile,
*,
now_ms: int | None = None,
report_counter: int = 1,
) -> "WeaponRuntimeSnapshot":
current_ms = int(time.time() * 1000) if now_ms is None else int(now_ms)
seed = _profile_seed(profile)
boot_age_ms = 6 * 60 * 60 * 1000 + seed % (5 * 24 * 60 * 60 * 1000)
sleep_ms = (seed >> 17) % max(1, boot_age_ms // 3)
return cls(
now_ms=current_ms,
elapsed_realtime_ms=boot_age_ms,
uptime_ms=boot_age_ms - sleep_ms,
boot_count=1 + ((seed >> 29) % 180),
report_counter=report_counter,
)
def _profile_seed(profile: DeviceProfile) -> int:
material = "|".join(
(
profile.android_id,
profile.local_did,
profile.sid,
str(profile.install_time_ms),
)
)
return int.from_bytes(hashlib.sha256(material.encode("utf-8")).digest()[:8], "big")
def _installation_id(profile: DeviceProfile) -> str:
source = profile.sid.replace("-", "")
if len(source) < 16:
source = hashlib.sha256(profile.android_id.encode("ascii")).hexdigest()
random_half = "".join(source[index * 2] for index in range(8))
created_ms = profile.install_time_ms or profile.cold_launch_time_ms
time_half = f"{created_ms:x}"[-8:].zfill(8)
return f"a_{random_half}{time_half}"
def build_mf_payload(
profile: DeviceProfile,
*,
event: int = 1,
snapshot: WeaponRuntimeSnapshot | None = None,
field_overrides: Mapping[str, Any] | None = None,
) -> dict[str, Any]:
"""按 ``mf.a()`` 的插入顺序构建设备状态对象。"""
runtime = snapshot or WeaponRuntimeSnapshot.fresh(profile)
seed = _profile_seed(profile)
battery_level = 40 + seed % 61
storage_bytes = profile.runtime_hints.storage_available_bytes or 491_765_592_064
boot_epoch_seconds = (runtime.now_ms - runtime.elapsed_realtime_ms) // 1000
payload: dict[str, Any] = {
"0": 1,
"3": 1,
"8": 0,
"24": 0,
"35": 0,
"30": 0,
"31": 0,
"65": 0,
"66": 0,
"68": 0,
"101": 0,
"102": 0,
"1021": _installation_id(profile),
"6": "0",
"47": "0",
"48": "0",
"37": "0",
"38": "0",
"45": "0",
"91": "0",
"54": "0",
"55": "0",
"79": "0",
"80": "1",
"83": '["{\\"1\\":1}","{\\"2\\":1}"]',
"87": "0",
"89": "0",
"75": "0",
"88": "0",
"92": "0",
"98": "0",
"100": "0",
"02001": profile.manufacturer,
"02002": profile.manufacturer,
"02003": profile.model,
"02008": profile.build_display,
"02016": profile.android_release,
"03014": True,
"03113": "1970-01-01",
"07025": "0",
"03020": "USB charger",
"03033": False,
"03043": runtime.elapsed_realtime_ms,
"03044": runtime.uptime_ms,
"03045": boot_epoch_seconds,
"03085": str(runtime.boot_count),
"03086": str(runtime.boot_count),
"02029": f"{280 + seed % 40}.{(seed >> 8) % 100:02d}",
"03128": str(storage_bytes),
"03030": 20 + ((seed >> 16) % 100),
"03006": (seed >> 24) % 8,
"03007": f"{battery_level}%",
"03015": "0",
"03115": (seed >> 7) % 1_000_000_000,
# 主 APP 在云 DID 更新后调用 WeaponHI.setGmf 的 ne.k() 读取当前 DID。
"03000": profile.did,
"20000": int(event),
"11113": 0,
"11111": runtime.now_ms // 1000,
"11112": runtime.report_counter,
"07069": 0,
"07070": 0,
}
if field_overrides:
for key, value in field_overrides.items():
payload[str(key)] = value
return payload
def serialize_mf_payload(payload: Mapping[str, Any]) -> str:
"""复现 Android ``JSONObject.toString()`` 的紧凑 JSON。"""
return json.dumps(payload, ensure_ascii=False, separators=(",", ":"))
def generate_profile_passport_account_image(
profile: DeviceProfile,
*,
event: int = 1,
snapshot: WeaponRuntimeSnapshot | None = None,
field_overrides: Mapping[str, Any] | None = None,
) -> str:
payload = build_mf_payload(
profile,
event=event,
snapshot=snapshot,
field_overrides=field_overrides,
)
return generate_passport_account_image(serialize_mf_payload(payload))