Files
workphone-sdk/test_frida_screenshot_v2.py

203 lines
7.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.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
工作手机SDK - 截图验证v2
用ADB截图可靠Frida控制微信操作
"""
import frida, time, json, os, subprocess
from datetime import datetime
PHONE_IP = "192.168.110.80"
ADB_SERIAL = "192.168.110.80:5555"
FRIDA_PORT = 27042
WECHAT_PID = 16816
BASE = "/Users/karuo/Documents/开发/2、私域银行/工作手机"
HOOK_SCRIPT = BASE + "/sdk/agent/hook/wechat_hook_v2.js"
SCREENSHOT_DIR = BASE + "/开发文档/6、测试/live_verify_20260518/screenshots"
RESULT_FILE = BASE + "/verification_screenshot_v2_20260518.json"
os.makedirs(SCREENSHOT_DIR, exist_ok=True)
def adb_screenshot(name, wait=0.5):
"""用ADB截图并拉取到本地"""
remote = f"/sdcard/{name}.png"
local = f"{SCREENSHOT_DIR}/{name}.png"
time.sleep(wait)
# 截图
r1 = subprocess.run(["adb", "-s", ADB_SERIAL, "shell", "screencap", "-p", remote],
capture_output=True, text=True)
# 拉取
r2 = subprocess.run(["adb", "-s", ADB_SERIAL, "pull", remote, local],
capture_output=True, text=True)
size = os.path.getsize(local) if os.path.exists(local) else 0
print(f" [截图] {name}.png ({size} bytes)")
return local if size > 0 else None
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 = {}
ts = datetime.now().strftime("%H%M%S")
# ============================================================
# 阶段1真实数据统计
# ============================================================
print("\n" + "="*50)
print("阶段1真实数据统计")
print("="*50)
r_type3 = rpc.raw_sql({"sql": "SELECT COUNT(*) as cnt FROM rcontact WHERE type=3"})
type3_count = r_type3.get("rows", [{}])[0].get("cnt", "?")
r_groups = rpc.raw_sql({"sql": "SELECT COUNT(*) as cnt FROM chatroom"})
groups_count = r_groups.get("rows", [{}])[0].get("cnt", "?")
r_total = rpc.raw_sql({"sql": "SELECT COUNT(*) as cnt FROM rcontact"})
total_count = r_total.get("rows", [{}])[0].get("cnt", "?")
# 群组名称
r_named = rpc.raw_sql({"sql": "SELECT chatroomname, chatroomnick FROM chatroom WHERE chatroomnick IS NOT NULL AND chatroomnick != '' LIMIT 10"})
named_groups = r_named.get("rows", [])
# 联系人样本
r_sample = rpc.raw_sql({"sql": "SELECT username, nickname, conRemark FROM rcontact WHERE type=3 AND username != 'filehelper' LIMIT 10"})
contact_sample = r_sample.get("rows", [])
print(f" rcontact总记录: {total_count}")
print(f" 真实好友(type=3): {type3_count}")
print(f" 群组数量: {groups_count}")
print(f" 有名称的群组: {len(named_groups)}")
for g in named_groups[:5]:
print(f" {g.get('chatroomnick','')} ({g.get('chatroomname','')})")
print(f" 联系人样本前5:")
for c in contact_sample[:5]:
print(f" {c.get('nickname','')} ({c.get('username','')})")
results["data_stats"] = {
"total_rcontact": total_count,
"type3_friends": type3_count,
"groups_count": groups_count,
"named_groups": named_groups,
"contact_sample": contact_sample
}
# ============================================================
# 阶段2截图验证朋友圈发送
# ============================================================
print("\n" + "="*50)
print("阶段2朋友圈发送截图验证")
print("="*50)
# 2a. 导航到主界面截图
print(" 2a. 导航到主界面...")
rpc.navigate_to_main({})
adb_screenshot(f"moment_A_main_{ts}", wait=1.5)
# 2b. 发送朋友圈
moment_content = f"[SDK验证{datetime.now().strftime('%m/%d %H:%M')}] 工作手机Frida真机验证-朋友圈功能正常 好友:{type3_count}人 群:{groups_count}"
print(f" 2b. 发送朋友圈: {moment_content[:40]}...")
moment_result = rpc.post_moments({"content": moment_content, "image_urls": []})
print(f" 发送结果: {json.dumps(moment_result, ensure_ascii=False)}")
results["moment_send"] = moment_result
# 2c. 发送后截图
adb_screenshot(f"moment_B_after_send_{ts}", wait=2)
# 2d. 读取朋友圈验证
moments = rpc.get_moments({"limit": 10})
print(f" 朋友圈读取: {moments.get('count', 0)}")
results["moments_read"] = moments
# ============================================================
# 阶段3截图验证消息发送
# ============================================================
print("\n" + "="*50)
print("阶段3消息发送截图验证")
print("="*50)
# 3a. 导航到文件传输助手
print(" 3a. 导航到文件传输助手...")
rpc.navigate_to_chat({"wxid": "filehelper"})
adb_screenshot(f"msg_A_before_{ts}", wait=1.5)
# 3b. 发送消息
msg1 = f"[SDK验证{datetime.now().strftime('%H:%M:%S')}] 真实数据: 好友{type3_count}人 | 群组{groups_count}个 | 总记录{total_count}"
print(f" 3b. 发送消息1: {msg1[:50]}...")
msg_result1 = rpc.send_message({"to_id": "filehelper", "content": msg1, "msg_type": "text"})
print(f" 发送结果: {json.dumps(msg_result1, ensure_ascii=False)}")
results["message_send_1"] = msg_result1
time.sleep(0.8)
# 3c. 发送后截图(消息应出现在聊天界面)
adb_screenshot(f"msg_B_after_send1_{ts}", wait=1)
# 3d. 再发一条确认
msg2 = f"[SDK验证{datetime.now().strftime('%H:%M:%S')}] 第2条消息 - Frida真机控制正常"
rpc.send_message({"to_id": "filehelper", "content": msg2, "msg_type": "text"})
results["message_send_2"] = {"content": msg2}
adb_screenshot(f"msg_C_after_send2_{ts}", wait=1)
# ============================================================
# 阶段4群组详情验证
# ============================================================
print("\n" + "="*50)
print("阶段4群组详情验证")
print("="*50)
groups_full = rpc.get_groups_full({"limit": 100})
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
# 获取第一个群的成员
if groups_full.get("groups"):
first_group = groups_full["groups"][0]
group_id = first_group.get("group_id", "")
if group_id:
members = rpc.get_group_members({"group_id": group_id})
print(f"{group_id} 成员数: {members.get('count', 0)}")
results["first_group_members"] = members
# ============================================================
# 保存结果
# ============================================================
report = {
"title": "工作手机SDK - 截图验证报告v2",
"time": datetime.now().isoformat(),
"device": PHONE_IP,
"real_data": {
"total_rcontact": total_count,
"type3_friends": type3_count,
"groups": groups_count,
},
"screenshots": [
f"moment_A_main_{ts}.png",
f"moment_B_after_send_{ts}.png",
f"msg_A_before_{ts}.png",
f"msg_B_after_send1_{ts}.png",
f"msg_C_after_send2_{ts}.png",
],
"results": results
}
with open(RESULT_FILE, "w", encoding="utf-8") as f:
json.dump(report, f, ensure_ascii=False, indent=2, default=str)
print(f"\n结果已保存: {RESULT_FILE}")
script.unload()
session.detach()
print("完成!")