#!/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()