Files
douyin-captcha/try/sdk_explore.py
T
杨豪 cae37465d2 feat: 尺度精修上线,首次机器 PASS(live_160548 s=1.0375)
- method_l_shape: OK 候选尺度 ±0.0375 精修(步长 0.0125 + ±6px 窗口),
  GT live_165204 Δ 179→176(真人 177),离线 9/10 保持
- 插桩 JSON.stringify 捕获 SDK 日志明文;指针 probe 排除 coalesced/pressure
- 拖动不跟手指标作废:post_pos 晚于 SDK 重置滑块,鼠标事件流始终完整
- 剩余 VerifyErr = 候选整体选错(视觉确证),方向:多候选质量评估
- docs: experiments/solution/retrospective 同步收尾
2026-09-15 16:20:05 +08:00

83 lines
3.4 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.
"""探测验证码 iframe 内 SDK 结构:script 源、addEventListener 采集点、轨迹缓冲。"""
import asyncio, json, urllib.request, sys
import websockets
CDP_HTTP = "http://127.0.0.1:9222"
def _json(path):
try:
with urllib.request.urlopen(f"{CDP_HTTP}{path}", timeout=5) as r:
return json.load(r)
except (OSError, ValueError):
return None
async def main():
ver = _json("/json/version")
targets = _json("/json/list") or []
if not ver or "webSocketDebuggerUrl" not in ver:
print("CDP 9222 不可用", file=sys.stderr); return
cand = [t for t in targets if "rmc" in t.get("url","") or "captcha" in t.get("url","").lower()]
if not cand:
print("未找到 captcha iframetargets")
for t in targets: print(" ", t["type"], t["url"][:80])
return
tgt = cand[0]
print("探测目标:", tgt["url"][:100])
async with websockets.connect(ver["webSocketDebuggerUrl"], max_size=64*1024*1024) as ws:
mid = [0]
async def cdp(method, params=None, sid=None):
mid[0] += 1
m = {"id": mid[0], "method": method, "params": params or {}}
if sid: m["sessionId"] = sid
await ws.send(json.dumps(m))
while True:
try:
r = json.loads(await ws.recv())
except json.JSONDecodeError:
continue
if r.get("id") == mid[0]:
if "error" in r: raise RuntimeError(f"{method}: {r['error']}")
return r.get("result", {})
sid = (await cdp("Target.attachToTarget",
{"targetId": tgt["id"], "flatten": True}))["sessionId"]
await cdp("Runtime.enable", sid=sid)
async def js(expr):
r = await cdp("Runtime.evaluate",
{"expression": expr, "returnByValue": True,
"awaitPromise": True, "userGesture": True}, sid)
return r.get("result", {}).get("value")
# 1) 挂 listener 记录 hook(记录到 window 全局,跨 evaluate 可读)
await js("""
(() => {
if (window.__lh) return 'already';
const orig = EventTarget.prototype.addEventListener;
window.__lh = [];
EventTarget.prototype.addEventListener = function(t, f, o){
try { window.__lh.push([t, String(f && f.name || 'anon'),
String(f).slice(0,120).replace(/\\n/g,' ')]); } catch(e){}
return orig.call(this, t, f, o);
};
return 'hook installed';
})()
""")
# 2) 已有 listenergetEventListeners 仅 DevTools 可用,改用枚举 on* + 重放脚本已知点)
scripts = await js("[...document.scripts].map(s=>s.src||('inline:'+s.textContent.length)).join('\\n')")
print("== scripts ==\\n" + str(scripts))
globals_ = await js("""
Object.getOwnPropertyNames(window).filter(k=>/captcha|verify|secsdk|byted|rms|rmc|track|slid|nocaptcha/i.test(k)).join('\\n')
""")
print("== 全局候选 ==\\n" + str(globals_))
await asyncio.sleep(15)
log = await js("JSON.stringify(window.__lh||[])")
try:
rows = json.loads(log or "[]")
except (TypeError, ValueError) as e:
print(f"__lh 解析失败: {e}", file=sys.stderr)
return
print(f"== 15s 内 addEventListener 调用: {len(rows)} ==")
for t, name, src in rows:
print(f" [{t}] {name} :: {src[:110]}")
asyncio.run(main())