Files
workphone-sdk/sdk/scripts/get_imei_md5.py
Manus AI 42fe10401a 1
1
2026-05-24 17:50:04 +08:00

156 lines
4.6 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.

#!/usr/bin/env python3
"""
通过 USB Type-C 连接的 Android 设备:提取 IMEI或 Android ID/序列号)并输出其 MD5。
用法(在电脑上运行,手机用 Type-C 连上并开启 USB 调试):
python get_imei_md5.py
python get_imei_md5.py -s <device_serial> # 多设备时指定序列号
依赖:已安装 adb 且设备已授权。
"""
from __future__ import annotations
import argparse
import hashlib
import re
import subprocess
import sys
from typing import Optional
def run_adb(serial: Optional[str], *args: str, timeout: int = 10) -> subprocess.CompletedProcess:
cmd = ["adb"]
if serial:
cmd.extend(["-s", serial])
cmd.extend(args)
return subprocess.run(cmd, capture_output=True, text=True, timeout=timeout)
def get_first_device() -> Optional[str]:
r = run_adb(None, "devices")
if r.returncode != 0:
return None
for line in r.stdout.splitlines()[1:]:
line = line.strip()
if not line or line.startswith("*"):
continue
parts = line.split()
if len(parts) >= 2 and parts[1] == "device":
return parts[0]
return None
def get_imei_via_dumpsys(serial: Optional[str]) -> Optional[str]:
r = run_adb(serial, "shell", "dumpsys iphonesubinfo 2>/dev/null")
if r.returncode != 0 or not r.stdout:
return None
# 匹配 "Device ID = xxx" 或 "Imei = xxx"
for pattern in (r"Device ID\s*=\s*(\S+)", r"Imei\s*=\s*(\S+)", r"IMEI\s*=\s*(\S+)"):
m = re.search(pattern, r.stdout, re.IGNORECASE)
if m:
raw = m.group(1).strip()
if raw.isdigit() and 14 <= len(raw) <= 16:
return raw
return None
def get_imei_via_service_call(serial: Optional[str]) -> Optional[str]:
r = run_adb(serial, "shell", "service call iphonesubinfo 1 2>/dev/null")
if r.returncode != 0 or "Parcel" not in r.stdout:
return None
# 解析 Parcel 中的 UTF-16 字符串(常见格式)
hex_part = re.sub(r"\s+", "", r.stdout)
hex_match = re.search(r"([0-9a-fA-F]{8})([0-9a-fA-F]+)", hex_part)
if not hex_match:
return None
try:
hex_str = hex_match.group(2)
if len(hex_str) % 4 != 0:
return None
s = "".join(
chr(int(hex_str[i : i + 4], 16))
for i in range(0, len(hex_str), 4)
if int(hex_str[i : i + 4], 16) < 0x10000
)
s = s.strip("\x00 ")
if s.isdigit() and 14 <= len(s) <= 16:
return s
except Exception:
pass
return None
def get_android_id(serial: Optional[str]) -> Optional[str]:
r = run_adb(serial, "shell", "settings get secure android_id")
if r.returncode != 0:
return None
raw = (r.stdout or "").strip()
return raw if raw and raw != "null" else None
def get_serial_no(serial: Optional[str]) -> Optional[str]:
r = run_adb(serial, "shell", "getprop ro.serialno")
if r.returncode != 0:
return None
raw = (r.stdout or "").strip()
return raw if raw else None
def md5_hex(s: str) -> str:
return hashlib.md5(s.encode("utf-8")).hexdigest()
def main() -> None:
parser = argparse.ArgumentParser(description="从 USB 连接的 Android 设备提取 IMEI/ID 并输出 MD5")
parser.add_argument("-s", "--serial", help="设备序列号(多设备时指定)")
parser.add_argument("-q", "--quiet", action="store_true", help="仅输出 MD5 一行")
args = parser.parse_args()
serial = args.serial
if not serial:
serial = get_first_device()
if not serial:
print("错误:未检测到已连接的 Android 设备。请用 Type-C 连接并开启 USB 调试。", file=sys.stderr)
sys.exit(1)
raw_id: Optional[str] = None
source = ""
raw_id = get_imei_via_dumpsys(serial)
if raw_id:
source = "IMEI (dumpsys)"
if not raw_id:
raw_id = get_imei_via_service_call(serial)
if raw_id:
source = "IMEI (service call)"
if not raw_id:
raw_id = get_android_id(serial)
if raw_id:
source = "Android ID"
if not raw_id:
raw_id = get_serial_no(serial)
if raw_id:
source = "ro.serialno"
if not raw_id:
print("错误:无法获取 IMEI/Android ID/序列号(需设备已授权且部分机型需 root 才能读 IMEI", file=sys.stderr)
sys.exit(2)
md5_val = md5_hex(raw_id)
if args.quiet:
print(md5_val)
else:
print(f"设备: {serial}")
print(f"原始 ID 来源: {source}")
print(f"原始 ID: {raw_id}")
print(f"MD5: {md5_val}")
sys.exit(0)
if __name__ == "__main__":
main()