127 lines
4.4 KiB
Python
127 lines
4.4 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
"""
|
||
工作手机SDK - 关键业务功能验证
|
||
验证:朋友圈发送、群发消息、获取手机号、添加好友、群发、解封等
|
||
"""
|
||
import frida, time, sys, 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_business_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
|
||
|
||
# 关键业务功能测试
|
||
BUSINESS_TESTS = [
|
||
# === 手机号获取 ===
|
||
("getSimPhone", None),
|
||
# === 账号信息 ===
|
||
("getProfile", None),
|
||
("getWechatVersion", None),
|
||
# === 联系人操作 ===
|
||
("getContacts", {"limit": 10}),
|
||
("getLabels", None),
|
||
# === 朋友圈 ===
|
||
("getMoments", {"limit": 5}),
|
||
# 发朋友圈(测试内容)
|
||
("postMoments", {"content": "[SDK测试] 工作手机Frida真机验证 - 朋友圈发送功能正常", "image_urls": []}),
|
||
# === 消息发送 ===
|
||
("sendMessage", {"to_id": "filehelper", "content": "[SDK业务验证] 消息发送正常", "msg_type": "text"}),
|
||
# === 群组 ===
|
||
("getGroups", {"limit": 5}),
|
||
# === 好友请求 ===
|
||
("getFriendRequests", {"limit": 5}),
|
||
# === 搜索好友(用于加好友前查找)===
|
||
("searchContacts", {"keyword": "test", "limit": 3}),
|
||
# === 标签管理 ===
|
||
("getLabels", None),
|
||
# === 安全功能 ===
|
||
("getLoginDevices", {}),
|
||
("checkAccountStatus", None),
|
||
# === 设备信息 ===
|
||
("getDeviceInfo", None),
|
||
("getNetworkInfo", None),
|
||
# === 截图验证 ===
|
||
("takeScreenshot", {"path": "/sdcard/business_verify.png"}),
|
||
# === 导航测试 ===
|
||
("navigateToMain", None),
|
||
("navigateToChat", {"wxid": "filehelper"}),
|
||
("simulateBack", None),
|
||
]
|
||
|
||
results = []
|
||
passed = failed = 0
|
||
print("\n=== 关键业务功能验证 ===")
|
||
for name, params in BUSINESS_TESTS:
|
||
fn = getattr(rpc, name, None)
|
||
if fn is None:
|
||
results.append({"name": name, "status": "NOT_FOUND"})
|
||
failed += 1
|
||
print(f" [NOT_FOUND] {name}")
|
||
continue
|
||
try:
|
||
t0 = time.time()
|
||
r = fn(params) if params is not None else fn()
|
||
ms = int((time.time()-t0)*1000)
|
||
ok = r.get("success", True) if isinstance(r, dict) else True
|
||
|
||
# 提取关键数据
|
||
detail = ""
|
||
if isinstance(r, dict):
|
||
for k in ["phone", "version", "data", "contacts", "messages", "groups", "moments", "profile", "wxid", "nickname", "count"]:
|
||
if k in r:
|
||
v = r[k]
|
||
if isinstance(v, list):
|
||
detail += f" {k}=[{len(v)}]"
|
||
else:
|
||
detail += f" {k}={str(v)[:30]}"
|
||
|
||
if ok:
|
||
passed += 1
|
||
print(f" [PASS] {name} ({ms}ms){detail}")
|
||
else:
|
||
failed += 1
|
||
err = str(r.get("error",""))[:80] if isinstance(r, dict) else ""
|
||
print(f" [FAIL] {name} ({ms}ms): {err}")
|
||
results.append({"name": name, "status": "PASS" if ok else "FAIL", "ms": ms, "data": r})
|
||
except Exception as e:
|
||
failed += 1
|
||
print(f" [ERROR] {name}: {str(e)[:100]}")
|
||
results.append({"name": name, "status": "ERROR", "error": str(e)[:200]})
|
||
time.sleep(0.5)
|
||
|
||
report = {
|
||
"title": "工作手机SDK - 关键业务功能验证",
|
||
"device": PHONE_IP,
|
||
"time": datetime.now().isoformat(),
|
||
"total": len(results),
|
||
"passed": passed,
|
||
"failed": failed,
|
||
"pass_rate": f"{passed/len(results)*100:.1f}%" if results else "0%",
|
||
"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业务功能验证: {passed}/{len(results)} 通过 ({report['pass_rate']})")
|
||
print(f"已保存: {RESULT_FILE}")
|
||
script.unload()
|
||
session.detach()
|