ksjsb/tools/phone_watch_manual.py
2026-07-30 20:25:56 +08:00

70 lines
3.1 KiB
Python

"""监视人工手指滑动: 你滑, 我抓结果。
检测: 活动离开 KwaiWebViewActivity => PASS(result=1); 图片 md5 变化 => 刷新(350014/350002); 不变 => 未滑或静默回弹。
"""
from __future__ import annotations
import subprocess
import time
import hashlib
from io import BytesIO
import numpy as np
from PIL import Image
PHOTO_LEFT, PHOTO_RIGHT = 66, 1013
PHOTO_TOP, PHOTO_BOT = 267, 819
def adb_text(*a):
r = subprocess.run(["adb", *a], capture_output=True, text=True,
encoding="utf-8", errors="replace", timeout=30)
return r.stdout
def state():
d = subprocess.run(["adb", "exec-out", "screencap", "-p"],
capture_output=True, timeout=30).stdout
img = np.asarray(Image.open(BytesIO(d)).convert("L"))
photo = img[PHOTO_TOP:PHOTO_BOT, PHOTO_LEFT:PHOTO_RIGHT]
md5 = hashlib.md5(photo.tobytes()).hexdigest()[:10]
top = adb_text("shell", "dumpsys", "activity", "activities")
act = next((l.strip() for l in top.splitlines() if "topResumedActivity" in l), "(none)")
on_captcha = "KwaiWebViewActivity" in act
return md5, on_captcha, act, img
def moved(a, b):
d = np.abs(b[PHOTO_TOP:PHOTO_BOT, PHOTO_LEFT:PHOTO_RIGHT].astype(np.int16)
- a[PHOTO_TOP:PHOTO_BOT, PHOTO_LEFT:PHOTO_RIGHT].astype(np.int16))
return int((d > 45).sum())
def main():
print("[watch] 开始监视 (~45s)。请现在用手指把拼图块滑进缺口。", flush=True)
base_md5, base_captcha, base_act, base_img = state()
print(f"[watch] baseline md5={base_md5} on_captcha={base_captcha}", flush=True)
t0 = time.monotonic(); last_print = 0; motion_seen = False
while time.monotonic() - t0 < 45:
time.sleep(0.6)
md5, on_captcha, act, img = state()
mv = moved(base_img, img)
if mv > 2000 and not motion_seen:
motion_seen = True
print(f"[watch] t={time.monotonic()-t0:.0f}s 检测到手指拖动(diff={mv})。等释放结果...", flush=True)
if not on_captcha:
print(f"\n>>> [PASS] t={time.monotonic()-t0:.0f}s 活动离开验证码页(人工滑动通过)。", flush=True)
print(f">>> top={act[:75]}", flush=True)
print(">>> 结论: 是自动化被检测(非号码标记)。路径=人工/root+Frida。", flush=True)
return 0
if md5 != base_md5 and motion_seen:
print(f"\n>>> [REFRESH] t={time.monotonic()-t0:.0f}s 图片变化(md5 {base_md5}->{md5})但仍在验证码页。", flush=True)
print(">>> 即人工正确滑动仍被拒 => 350014(号码被永久标记)。只能换号(新号不触发验证码)。", flush=True)
return 0
if time.monotonic() - last_print > 4:
print(f"[watch] t={time.monotonic()-t0:.0f}s 等待中... md5={'' if md5==base_md5 else ''} motion={'' if motion_seen else ''}", flush=True)
last_print = time.monotonic()
print("\n[watch] 超时未检测到明确结果。可能没滑/滑错回弹。再跑一次或告诉我结果。", flush=True)
return 0
if __name__ == "__main__":
raise SystemExit(main())