spawn_mm_and_hook.py 2.24 KB
#!/usr/bin/env python3
# 贴图号发布 hook 的真正入口点是 Ljs1/m;->c(TransferRequestInfo, callback)(见
# BRANDSERVICE_PUBLISH_RESEARCH.md §3.5),大概率跑在微信主进程(长驻,不是
# spawn-gating 能抓的子进程)。长驻进程 Java.perform 枚举存量类会超时,唯一办法是
# force-stop 整个微信、用 frida 重新 spawn 它,在类加载膨胀之前就把钩子挂上。
#
# v1(spawn-paused 时就 attach+hook+resume)实测会把微信主进程冷启动搞坏
# ("无法连接服务器",见 §3.6)。v2 改成:spawn 后立刻 resume(不在暂停态注入),
# 隔 ATTACH_DELAY_SEC 再正常 attach——避开暂停态注入这个可疑触发点,但没验证过
# 是否真的安全,也没验证过延迟这么久还能不能赶在类加载膨胀前挂上钩子。
#
# 用法: source .venv/bin/activate && python3 spawn_mm_and_hook.py
import subprocess
import time

import frida

PACKAGE = "com.tencent.mm"
SCRIPT_PATH = "../wechat_send_internal/hook_transfer_sink_bundled.js"
ATTACH_DELAY_SEC = 0.8


def on_message(message, data):
    if message["type"] == "send":
        print(f"[msg] {message['payload']}")
    elif message["type"] == "error":
        print(f"[error] {message.get('stack', message)}")


def main():
    print(f"[*] force-stopping {PACKAGE} ...")
    subprocess.run(
        ["adb", "shell", "su", "-c", f"am force-stop {PACKAGE}"], check=True
    )
    time.sleep(1)

    device = frida.get_usb_device(timeout=10)
    with open(SCRIPT_PATH) as f:
        source = f.read()

    print(f"[*] spawning {PACKAGE} (paused) ...")
    pid = device.spawn([PACKAGE])
    print(f"[+] spawned pid={pid}, resuming immediately (no injection while paused)...")
    device.resume(pid)
    print(f"[*] waiting {ATTACH_DELAY_SEC}s before attaching...")
    time.sleep(ATTACH_DELAY_SEC)
    print(f"[*] attaching to pid={pid} ...")
    session = device.attach(pid)
    script = session.create_script(source)
    script.on("message", on_message)
    script.load()
    print(f"[+] script loaded on running pid={pid}. Reopen WeChat on the phone and redo the flow.")

    try:
        while True:
            time.sleep(3600)
    except KeyboardInterrupt:
        print("stopping")


if __name__ == "__main__":
    main()