137 lines
5.0 KiB
Python
137 lines
5.0 KiB
Python
#!/usr/bin/env python3
|
||
# 工作手机 · Frida 主控通道·实机冒烟脚本(一次性跑完 8 项验证)
|
||
# 用法:python3 sdk/scripts/_hook_smoke.py <device_serial>
|
||
import json, sys, urllib.request, urllib.parse, time
|
||
|
||
DEVICE = sys.argv[1] if len(sys.argv) > 1 else 'xgfe65eimrrofyws'
|
||
BASE = 'http://127.0.0.1:8899'
|
||
|
||
def get(path, params=None):
|
||
url = f'{BASE}{path}'
|
||
if params:
|
||
url += '?' + urllib.parse.urlencode(params)
|
||
with urllib.request.urlopen(url, timeout=60) as r:
|
||
return json.loads(r.read())
|
||
|
||
def post(path, body):
|
||
req = urllib.request.Request(
|
||
f'{BASE}{path}',
|
||
data=json.dumps(body).encode(),
|
||
headers={'Content-Type': 'application/json'},
|
||
method='POST',
|
||
)
|
||
with urllib.request.urlopen(req, timeout=120) as r:
|
||
return json.loads(r.read())
|
||
|
||
def section(title):
|
||
print('\n' + '=' * 60)
|
||
print(f' {title}')
|
||
print('=' * 60)
|
||
|
||
def show(label, value, limit=200):
|
||
s = json.dumps(value, ensure_ascii=False)
|
||
if len(s) > limit:
|
||
s = s[:limit] + ' …(truncated)'
|
||
print(f'{label} → {s}')
|
||
|
||
|
||
# 1) probe
|
||
section('1) /api/v3/hook/probe — Hook 探测')
|
||
probe = get(f'/api/v3/hook/probe/{DEVICE}')
|
||
show('supports_hook', probe.get('supports_hook'))
|
||
show('frida_version', probe.get('frida_version'))
|
||
show('wechat_version', probe.get('wechat_version'))
|
||
show('profile.nickname', probe.get('profile', {}).get('profile', {}).get('nickname'))
|
||
|
||
# 2) actions 清单
|
||
section('2) /api/v3/hook/actions — 全部动作清单')
|
||
acts = get('/api/v3/hook/actions')
|
||
show('total_actions', acts.get('total_actions'))
|
||
show('total_modules', acts.get('total_modules'))
|
||
|
||
# 3) 一次性取数
|
||
section('3) /api/v3/hook/data — 取微信资料/联系人/群/消息/标签')
|
||
data = get(f'/api/v3/hook/data/{DEVICE}',
|
||
{'modules': 'profile,contacts,groups,messages,labels'})
|
||
core = data.get('data', {})
|
||
def _list(node, key1, key2=None):
|
||
inner = node.get('data', node)
|
||
if key2 and isinstance(inner, dict) and key2 in inner:
|
||
return inner[key2]
|
||
if isinstance(inner, dict) and key1 in inner:
|
||
return inner[key1]
|
||
if isinstance(inner, dict) and 'data' in inner and isinstance(inner['data'], list):
|
||
return inner['data']
|
||
return inner if isinstance(inner, list) else []
|
||
contacts = _list(core['contacts'], 'contacts')
|
||
groups = _list(core['groups'], 'groups')
|
||
messages = _list(core['messages'], 'messages')
|
||
labels = _list(core['labels'], 'labels')
|
||
print(f'contacts : {len(contacts)} 条')
|
||
print(f'groups : {len(groups)} 个')
|
||
print(f'messages : {len(messages)} 条')
|
||
print(f'labels : {len(labels)} 个')
|
||
remark = [c for c in contacts if c.get('remark')]
|
||
namedgrp = [g for g in groups if g.get('name')]
|
||
print(f' - 有备注联系人: {len(remark)} | 例子:',
|
||
', '.join((c.get('remark') or '?')[:24] for c in remark[:5]))
|
||
print(f' - 已命名群 : {len(namedgrp)} | 例子:',
|
||
', '.join((g.get('name') or '?')[:24] for g in namedgrp[:5]))
|
||
print(f' - 标签 : {len(labels)} | 例子:',
|
||
', '.join((l.get('name') or '?')[:18] for l in labels[:8]))
|
||
|
||
# 4) hookStatus / getMoments / getWechatVersion 直调
|
||
section('4) /api/v3/hook/execute — hookStatus + getWechatVersion')
|
||
hs = post('/api/v3/hook/execute', {
|
||
'device_id': DEVICE, 'platform': 'wechat',
|
||
'action': 'get_hook_status', 'params': {}, 'hook_only': True
|
||
})
|
||
show('hookStatus', hs)
|
||
gv = post('/api/v3/hook/execute', {
|
||
'device_id': DEVICE, 'platform': 'wechat',
|
||
'action': 'get_wechat_version', 'params': {}, 'hook_only': True
|
||
})
|
||
show('getWechatVersion', gv)
|
||
|
||
# 5) 朋友圈
|
||
section('5) /api/v3/hook/execute — getMoments(limit=3)')
|
||
mm = post('/api/v3/hook/execute', {
|
||
'device_id': DEVICE, 'platform': 'wechat',
|
||
'action': 'get_moments', 'params': {'limit': 3}, 'hook_only': True
|
||
})
|
||
show('getMoments', mm, 400)
|
||
|
||
# 6) 真发一条消息到文件传输助手
|
||
section('6) /api/v3/hook/execute — send_message → 文件传输助手')
|
||
ts = time.strftime('%H:%M:%S')
|
||
send = post('/api/v3/hook/execute', {
|
||
'device_id': DEVICE, 'platform': 'wechat',
|
||
'action': 'send_message',
|
||
'params': {
|
||
'to_id': 'filehelper',
|
||
'content': f'[E2E] Frida 主控通道 实机冒烟 {ts}',
|
||
'msg_type': 'text',
|
||
},
|
||
'hook_only': True
|
||
})
|
||
show('send_message', send)
|
||
|
||
# 7) 拉一条最近消息证明 read-back
|
||
section('7) /api/v3/hook/execute — get_recent_messages(limit=1)')
|
||
rm = post('/api/v3/hook/execute', {
|
||
'device_id': DEVICE, 'platform': 'wechat',
|
||
'action': 'get_recent_messages', 'params': {'limit': 1}, 'hook_only': True
|
||
})
|
||
show('get_recent_messages', rm, 400)
|
||
|
||
# 8) 走标准 unified channel=hook 的 sendMessage(验证存客宝侧路径)
|
||
section('8) /api/v3/message/send channel=hook (存客宝标准入口)')
|
||
um = post('/api/v3/message/send', {
|
||
'device_id': DEVICE, 'platform': 'wechat', 'to_id': 'filehelper',
|
||
'content': f'[E2E] unified channel=hook {ts}',
|
||
'msg_type': 'text', 'channel': 'hook'
|
||
})
|
||
show('unified.sendMessage', um, 400)
|
||
|
||
print('\n ✅ Hook 主控冒烟测试完成')
|