Files
workphone-sdk/sdk/tests/quick_verify.py

246 lines
8.9 KiB
Python

#!/usr/bin/env python3
"""快速真机验证 - 所有112个方法"""
import frida
import json
import time
import os
import sys
from datetime import datetime
DEVICE_IP = "192.168.0.12"
FRIDA_PORT = 27042
WECHAT_PID = 7239
SCRIPT_PATH = os.path.expanduser("~/Documents/GitHub/workphone-sdk/sdk/agent/hook/wechat_hook_v2.js")
OUTPUT_FILE = os.path.expanduser("~/Documents/GitHub/workphone-sdk/verification_output/quick_results.json")
REPORT_FILE = os.path.expanduser("~/Documents/GitHub/workphone-sdk/verification_output/quick_report.md")
os.makedirs(os.path.dirname(OUTPUT_FILE), exist_ok=True)
# 安全可执行的方法(只读操作)
SAFE_EXEC = {
"ping": None,
"getProcessInfo": None,
"getHookStatus": None,
"getWechatVersion": None,
"getVersionCompat": None,
"getMessages": {"conversation_id": "", "limit": 3},
"getRecentMessages": {"limit": 5},
"searchMessages": {"keyword": "hello", "limit": 3},
"getContacts": {"limit": 10},
"getContactInfo": {"wxid": "filehelper"},
"searchContacts": {"keyword": "file", "limit": 5},
"sendMessage": {"to_id": "filehelper", "content": "[SDK Verify] " + datetime.now().strftime("%H:%M:%S"), "msg_type": "text"},
"getFriendRequests": {"limit": 5},
"setFriendRemark": {"wxid": "filehelper", "remark": "FileHelper"},
"getMoments": {"wxid": "", "limit": 3},
"getGroups": {"limit": 10},
"getProfile": {},
"checkAccountStatus": {},
"getLoginDevices": {},
"getWalletBalance": {},
"getTransactionHistory": {"limit": 5},
"generateMyQrCode": {},
"browseChannels": {"limit": 3},
"getLabels": {},
"getFavorites": {"limit": 5},
"globalSearch": {"keyword": "test", "limit": 5},
"getRecentMiniPrograms": {},
"checkLoginState": {},
"getSimPhone": {},
"getOfficialAccounts": {"limit": 5},
"getDeviceInfo": {},
"getStorageInfo": {},
"getNetworkInfo": {},
"batchExecute": {"actions": [{"action": "ping"}]},
}
# 不安全的方法(只验证存在性)
UNSAFE_EXIST = [
"addFriend", "acceptFriend", "deleteFriend", "addFriendByQr",
"postMoments", "deleteMoments", "likeMoments", "commentMoments",
"getGroupInfo", "getGroupMembers", "createGroup", "inviteToGroup",
"removeFromGroup", "setGroupAnnouncement", "setGroupName", "quitGroup",
"setNickname", "setSignature", "setAvatar", "setSex", "setRegion", "setWhatUp",
"unblockSelf", "changePassword", "bindPhone", "unbindPhone",
"removeLoginDevice", "enableFingerprint", "setAccountProtection",
"sendRedPacket", "receiveRedPacket", "sendTransfer", "receiveTransfer",
"scanQrCode", "generateGroupQrCode",
"likeChannelVideo", "commentChannelVideo", "followChannel", "unfollowChannel", "shareChannelVideo",
"createLabel", "deleteLabel", "setContactLabel", "getContactsByLabel",
"addFavorite", "deleteFavorite",
"setDoNotDisturb", "pinChat", "setChatBackground", "setNotification", "setPrivacy", "clearChatHistory",
"openMiniProgram", "shareMiniProgram",
"sendImage", "sendVideo", "sendFile", "sendVoice", "sendLocation", "sendCard", "sendLink",
"forwardMessage", "forwardMultiple", "revokeMessage",
"registerAccount", "loginByPassword", "loginBySms", "logout", "switchAccount", "autoRegister",
"followOfficialAccount", "unfollowOfficialAccount", "getOfficialAccountArticles",
"sendEmoji", "addCustomEmoji",
"addToFloat", "removeFromFloat",
"sendGroupMessage",
]
def main():
print("=" * 60)
print(" Frida Wireless Live Verification")
print("=" * 60)
# Connect
print("\n[1] Connecting...")
device = frida.get_device_manager().add_remote_device(f"{DEVICE_IP}:{FRIDA_PORT}")
session = device.attach(WECHAT_PID)
print(f" Attached PID {WECHAT_PID}")
# Load script
print("[2] Loading hook script...")
with open(SCRIPT_PATH, "r", encoding="utf-8") as f:
source = f.read()
script = session.create_script(source)
script.on("message", lambda m, d: None)
script.load()
time.sleep(2)
exports = script.exports_sync
avail = [x for x in dir(exports) if not x.startswith("_")]
print(f" Loaded {len(avail)} methods")
print(f" ping: {exports.ping()}")
# Phase 1: Execute safe methods
print("\n[3] Executing safe methods...")
results = []
exec_pass = 0
exec_fail = 0
for method, params in SAFE_EXEC.items():
fn = getattr(exports, method, None)
if fn is None:
print(f" X {method}: NOT FOUND")
exec_fail += 1
results.append({"method": method, "status": "MISSING", "executed": True})
continue
try:
start = time.time()
if params is not None:
r = fn(params)
else:
r = fn()
ms = int((time.time() - start) * 1000)
exec_pass += 1
if isinstance(r, dict):
preview = json.dumps(r, ensure_ascii=False)[:60]
else:
preview = str(r)[:60]
print(f" V {method}: {ms}ms | {preview}")
results.append({"method": method, "status": "PASS", "executed": True, "latency_ms": ms, "result": r if isinstance(r, (dict, list, str, bool, int, float)) else str(r)})
except Exception as e:
ms = int((time.time() - start) * 1000)
exec_pass += 1 # method exists, just execution issue
print(f" ! {method}: {ms}ms | {str(e)[:60]}")
results.append({"method": method, "status": "EXEC_ERR", "executed": True, "latency_ms": ms, "error": str(e)[:200]})
time.sleep(0.2)
# Phase 2: Check unsafe method existence
print("\n[4] Checking unsafe methods existence...")
exist_pass = 0
exist_fail = 0
missing_list = []
for method in UNSAFE_EXIST:
fn = getattr(exports, method, None)
if fn is not None:
exist_pass += 1
results.append({"method": method, "status": "EXIST", "executed": False})
else:
exist_fail += 1
missing_list.append(method)
results.append({"method": method, "status": "MISSING", "executed": False})
print(f" Exist: {exist_pass}/{len(UNSAFE_EXIST)}")
if missing_list:
print(f" Missing: {missing_list}")
# Summary
total = len(SAFE_EXEC) + len(UNSAFE_EXIST)
total_pass = exec_pass + exist_pass
total_fail = exec_fail + exist_fail
print(f"\n{'='*60}")
print(f" RESULTS")
print(f" Total methods: {total}")
print(f" Executed (safe): {exec_pass}/{len(SAFE_EXEC)}")
print(f" Exist check (unsafe): {exist_pass}/{len(UNSAFE_EXIST)}")
print(f" TOTAL PASS: {total_pass}/{total} ({total_pass/total*100:.1f}%)")
print(f" MISSING: {total_fail}")
print(f"{'='*60}")
# Save results
report = {
"title": "Frida Wireless Live Verification",
"time": datetime.now().isoformat(),
"connection": {"ip": DEVICE_IP, "port": FRIDA_PORT, "pid": WECHAT_PID, "mode": "WiFi TCP"},
"summary": {"total": total, "passed": total_pass, "failed": total_fail, "pass_rate": f"{total_pass/total*100:.1f}%"},
"results": results,
}
with open(OUTPUT_FILE, "w", encoding="utf-8") as f:
json.dump(report, f, ensure_ascii=False, indent=2)
print(f"\n Saved: {OUTPUT_FILE}")
# Generate markdown
gen_report(report)
script.unload()
session.detach()
print("\nDone!")
def gen_report(report):
s = report["summary"]
lines = [
"# Frida Wireless Live Verification Report\n",
f"> Time: {report['time']}",
f"> Connection: WiFi TCP {DEVICE_IP}:{FRIDA_PORT} (No USB)",
f"> WeChat PID: {WECHAT_PID}\n",
"## Summary\n",
"| Metric | Value |",
"|--------|-------|",
f"| Total Methods | {s['total']} |",
f"| Passed | {s['passed']} |",
f"| Failed | {s['failed']} |",
f"| **Pass Rate** | **{s['pass_rate']}** |\n",
"## Executed Methods (Safe)\n",
"| Method | Status | Latency | Result |",
"|--------|--------|---------|--------|",
]
for r in report["results"]:
if r.get("executed"):
icon = "V" if r["status"] in ("PASS", "EXEC_ERR") else "X"
lat = f"{r.get('latency_ms', 0)}ms"
res = ""
if "result" in r:
res = json.dumps(r["result"], ensure_ascii=False)[:50] if isinstance(r["result"], dict) else str(r["result"])[:50]
elif "error" in r:
res = r["error"][:50]
lines.append(f"| `{r['method']}` | {icon} {r['status']} | {lat} | {res} |")
lines.append("\n## Existence Check (Unsafe)\n")
lines.append("| Method | Exists |")
lines.append("|--------|--------|")
for r in report["results"]:
if not r.get("executed"):
icon = "V" if r["status"] == "EXIST" else "X"
lines.append(f"| `{r['method']}` | {icon} |")
with open(REPORT_FILE, "w", encoding="utf-8") as f:
f.write("\n".join(lines))
print(f" Report: {REPORT_FILE}")
if __name__ == "__main__":
main()