multi_spawn_hook.py
2.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#!/usr/bin/env python3
# frida CLI 的 `-W pattern` 只处理第一个匹配的 spawn,之后同 pattern 的新进程一律
# resume 但不 attach。微信"我的作品"发布一次流程会连续冒出多个 appbrand* 子进程
# (选图用一个、真正宿主 WebView 用另一个),必须逐个都 hook 到,所以改用
# device.enable_spawn_gating() + on('spawn-added') 手动处理每一个匹配的 spawn。
#
# 用法: source .venv/bin/activate && python3 multi_spawn_hook.py
import sys
import time
import frida
PATTERN = "com.tencent.mm:appbrand"
# session.create_script() (raw Python bindings) doesn't auto-bundle
# frida-java-bridge the way `frida -l script.js` (CLI) does, and there's no
# require() available either — must load a pre-compiled bundle instead.
# Regenerate after editing hook_lite_transfer.js's logic:
# npm install frida-java-bridge (in a scratch dir with an entry.js that
# does `import Java from 'frida-java-bridge';` + the hook body)
# frida-compile entry.js -o hook_lite_transfer_bundled.js -P gum
SCRIPT_PATH = "../wechat_send_internal/hook_lite_transfer_bundled.js"
def on_message(pid, message, data):
if message["type"] == "send":
print(f"[pid={pid}] {message['payload']}")
elif message["type"] == "error":
print(f"[pid={pid}] ERROR: {message.get('stack', message)}")
def main():
device = frida.get_usb_device(timeout=10)
with open(SCRIPT_PATH) as f:
source = f.read()
def on_spawn_added(spawn):
identifier = spawn.identifier or ""
pid = spawn.pid
if PATTERN in identifier:
print(f"[+] matched spawn pid={pid} identifier={identifier}, attaching...")
try:
session = device.attach(pid)
script = session.create_script(source)
script.on("message", lambda m, d: on_message(pid, m, d))
script.load()
print(f"[+] hooked pid={pid}")
except Exception as e:
print(f"[!] hook failed for pid={pid}: {e}")
else:
print(f"[ ] ignoring spawn pid={pid} identifier={identifier}")
device.resume(pid)
device.on("spawn-added", on_spawn_added)
device.enable_spawn_gating()
print(f"[*] spawn gating enabled, watching for '{PATTERN}' ... (Ctrl+C to stop)")
try:
while True:
time.sleep(3600)
except KeyboardInterrupt:
print("stopping")
if __name__ == "__main__":
main()