Files
workphone-sdk/test_frida_stats_20260518.py

145 lines
5.7 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.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
工作手机SDK - 真实数据统计验证
目标:查明联系人/群组真实数量,截图验证朋友圈和消息发送
"""
import frida, time, json, os
from datetime import datetime
PHONE_IP = "192.168.110.80"
FRIDA_PORT = 27042
WECHAT_PID = 16816
BASE = "/Users/karuo/Documents/开发/2、私域银行/工作手机"
HOOK_SCRIPT = BASE + "/sdk/agent/hook/wechat_hook_v2.js"
RESULT_FILE = BASE + "/verification_stats_20260518.json"
print(f"[{datetime.now().strftime('%H:%M:%S')}] 连接Frida: {PHONE_IP}:{FRIDA_PORT}")
dm = frida.get_device_manager()
device = dm.add_remote_device(f"{PHONE_IP}:{FRIDA_PORT}")
session = device.attach(WECHAT_PID)
print(f"[OK] 附加微信 PID={WECHAT_PID}")
with open(HOOK_SCRIPT, encoding="utf-8") as f:
src = f.read()
script = session.create_script(src)
script.on("message", lambda m, d: None)
script.load()
print("[OK] Hook已加载等待3秒...")
time.sleep(3)
rpc = script.exports_sync
results = {}
# === 1. 联系人/群组真实统计 ===
print("\n=== 1. 联系人/群组数据统计 ===")
stats = rpc.get_contact_stats()
print(json.dumps(stats, ensure_ascii=False, indent=2, default=str)[:3000])
results["contact_stats"] = stats
# === 2. 完整联系人列表(无过滤)===
print("\n=== 2. 完整联系人type=3好友===")
contacts_full = rpc.get_contacts_full({"limit": 500, "filter_type": 3})
print(f" type=3好友数量: {contacts_full.get('count', 0)}")
if contacts_full.get("contacts"):
for c in contacts_full["contacts"][:10]:
print(f" {c.get('username','')} | {c.get('nickname','')} | type={c.get('type','')} | verifyFlag={c.get('verifyFlag','')}")
results["contacts_type3"] = contacts_full
# === 3. 放宽过滤的联系人 ===
print("\n=== 3. 放宽过滤联系人type!=0, 非群非公众号)===")
contacts_relaxed = rpc.get_contacts_full({"limit": 500})
print(f" 放宽过滤联系人数量: {contacts_relaxed.get('count', 0)}")
if contacts_relaxed.get("contacts"):
for c in contacts_relaxed["contacts"][:10]:
print(f" {c.get('username','')} | {c.get('nickname','')} | type={c.get('type','')} | verifyFlag={c.get('verifyFlag','')}")
results["contacts_relaxed"] = contacts_relaxed
# === 4. 完整群组列表 ===
print("\n=== 4. 完整群组列表 ===")
groups_full = rpc.get_groups_full({"limit": 500})
print(f" 群组数量: {groups_full.get('count', 0)} (来源: {groups_full.get('source', '?')})")
if groups_full.get("groups"):
for g in groups_full["groups"][:10]:
print(f" {g.get('group_id','')} | {g.get('name','')} | 成员:{g.get('member_count','?')}")
results["groups_full"] = groups_full
# === 5. 原始SQL查询验证 ===
print("\n=== 5. 原始SQL验证 ===")
# 5a. 总联系人数
r_total = rpc.raw_sql({"sql": "SELECT COUNT(*) as cnt FROM rcontact"})
print(f" rcontact总记录: {r_total.get('rows', [{}])[0].get('cnt', '?')}")
results["raw_total"] = r_total
# 5b. type分布
r_type = rpc.raw_sql({"sql": "SELECT type, COUNT(*) as cnt FROM rcontact GROUP BY type ORDER BY cnt DESC LIMIT 20"})
print(f" type分布: {json.dumps(r_type.get('rows', []), ensure_ascii=False)[:300]}")
results["raw_type_dist"] = r_type
# 5c. 真实好友type=3
r_t3 = rpc.raw_sql({"sql": "SELECT COUNT(*) as cnt FROM rcontact WHERE type=3"})
print(f" type=3好友数: {r_t3.get('rows', [{}])[0].get('cnt', '?')}")
# 5d. chatroom表群组数
r_chatroom = rpc.raw_sql({"sql": "SELECT COUNT(*) as cnt FROM chatroom"})
print(f" chatroom表群组数: {r_chatroom.get('rows', [{}])[0].get('cnt', '?')}")
results["raw_chatroom_count"] = r_chatroom
# 5e. 标签数
r_labels = rpc.raw_sql({"sql": "SELECT COUNT(*) as cnt FROM contactlabelinfo"})
print(f" 标签数: {r_labels.get('rows', [{}])[0].get('cnt', '?')}")
# === 6. 截图验证朋友圈发送前状态 ===
print("\n=== 6. 截图验证 ===")
# 截图当前状态(发送前)
rpc.take_screenshot({"path": "/sdcard/before_moment.png"})
print(" 截图已保存: /sdcard/before_moment.png")
# === 7. 发送朋友圈并截图 ===
print("\n=== 7. 发送朋友圈 ===")
moment_content = f"[SDK验证{datetime.now().strftime('%H:%M')}] 工作手机Frida真机验证-朋友圈功能正常"
moment_result = rpc.post_moments({"content": moment_content, "image_urls": []})
print(f" 发送结果: {json.dumps(moment_result, ensure_ascii=False)}")
results["moment_send"] = moment_result
time.sleep(2)
# 截图发送后
rpc.take_screenshot({"path": "/sdcard/after_moment.png"})
print(" 截图已保存: /sdcard/after_moment.png")
# === 8. 导航到朋友圈确认 ===
print("\n=== 8. 导航到朋友圈验证 ===")
# 先截图当前状态
rpc.navigate_to_main({})
time.sleep(1)
rpc.take_screenshot({"path": "/sdcard/main_screen.png"})
print(" 主界面截图: /sdcard/main_screen.png")
# === 9. 发送消息并截图 ===
print("\n=== 9. 消息发送验证 ===")
# 导航到文件传输助手
rpc.navigate_to_chat({"wxid": "filehelper"})
time.sleep(1)
rpc.take_screenshot({"path": "/sdcard/before_msg.png"})
print(" 发送前截图: /sdcard/before_msg.png")
# 发送消息
msg_content = f"[SDK验证{datetime.now().strftime('%H:%M:%S')}] 消息发送功能正常 ✓"
msg_result = rpc.send_message({"to_id": "filehelper", "content": msg_content, "msg_type": "text"})
print(f" 发送结果: {json.dumps(msg_result, ensure_ascii=False)}")
results["message_send"] = msg_result
time.sleep(1)
# 发送后截图
rpc.take_screenshot({"path": "/sdcard/after_msg.png"})
print(" 发送后截图: /sdcard/after_msg.png")
# === 保存结果 ===
with open(RESULT_FILE, "w", encoding="utf-8") as f:
json.dump(results, f, ensure_ascii=False, indent=2, default=str)
print(f"\n结果已保存: {RESULT_FILE}")
script.unload()
session.detach()
print("完成!")