Files
workphone-sdk/sdk/app/routers/wechat_full.py
karuo cfc0d9d70a feat: 完整实现Frida无线控制SDK + 微信全量Skill
新增文件:
- agent/hook/wireless_deployer.py: Frida无线部署器(Root/免Root双模式)
- agent/hook/wireless_bridge.py: Frida无线桥接器(WebSocket↔Frida RPC)
- agent/wireless_agent.py: Agent端无线增强混入类
- app/routers/frida_wireless.py: 服务端Frida无线管理API路由
- app/routers/wechat_full.py: 微信全量操作路由(补全缺失端点)
- app/skills/wechat/skill_v2.py: 服务端微信Skill完整版(110方法/25模块)
- tests/test_wireless_frida.py: 验证测试套件
- 开发文档/6、测试/Frida无线控制验证报告_20260518.md

核心特性:
- WiFi TCP无线连接(无需USB)
- Root模式: frida-server远程连接
- 免Root模式: frida-gadget注入连接
- 自动检测Root状态选择最佳模式
- 110个微信操作全覆盖(25个模块)
- 通道降级: Hook > WebSocket > UI自动化
- 验证通过率: 100%
2026-05-18 06:18:28 +00:00

625 lines
21 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.

"""
微信全量操作路由 — 补全统一路由缺失的端点
==========================================
对齐 agent 端 112 个 RPC 方法,通过 WechatSkillV2 统一分发。
所有操作通过 WiFi Frida 无线执行,无需 USB。
新增端点(统一路由已有的不重复):
- 视频号操作6个
- 小程序操作3个
- 收藏管理3个
- 公众号操作4个
- 账号安全8个
- 支付操作6个
- 浮窗管理2个
- 表情管理2个
- 搜索1个
- 设备信息3个
"""
from __future__ import annotations
import logging
from typing import Optional, List
from fastapi import APIRouter, HTTPException
from pydantic import BaseModel, Field
router = APIRouter(prefix="/wechat", tags=["微信全量操作"])
logger = logging.getLogger(__name__)
# ============================================================
# § 1 请求模型
# ============================================================
class WechatBaseRequest(BaseModel):
device_id: str
timeout: int = 30
class WxidRequest(WechatBaseRequest):
wxid: str
class SearchRequest(WechatBaseRequest):
keyword: str
limit: int = 50
class ChannelVideoRequest(WechatBaseRequest):
video_id: str
class ChannelCommentRequest(WechatBaseRequest):
video_id: str
comment: str
class ChannelFollowRequest(WechatBaseRequest):
channel_id: str
class ShareChannelRequest(WechatBaseRequest):
video_id: str
to_id: str
class MiniProgramRequest(WechatBaseRequest):
app_id: str
path: str = ""
class ShareMiniProgramRequest(WechatBaseRequest):
app_id: str
to_id: str
title: str = ""
class FavoriteRequest(WechatBaseRequest):
msg_svr_id: str = ""
local_id: str = ""
type: str = "message"
class OfficialAccountRequest(WechatBaseRequest):
account_id: str
class OfficialAccountArticlesRequest(WechatBaseRequest):
account_id: str
limit: int = 10
class PasswordRequest(WechatBaseRequest):
old_password: str
new_password: str
class PhoneRequest(WechatBaseRequest):
phone: str
class DeviceRemoveRequest(WechatBaseRequest):
target_device_id: str
class ToggleRequest(WechatBaseRequest):
enable: bool = True
class RedPacketRequest(WechatBaseRequest):
to_id: str
amount: str
message: str = "恭喜发财"
class TransferRequest(WechatBaseRequest):
to_id: str
amount: str
description: str = ""
class ReceiveRequest(WechatBaseRequest):
msg_svr_id: str
class FloatRequest(WechatBaseRequest):
wxid: str
class EmojiSendRequest(WechatBaseRequest):
to_id: str
emoji_md5: str
class EmojiAddRequest(WechatBaseRequest):
image_path: str
class ProfileSetRequest(WechatBaseRequest):
value: str
class PrivacyRequest(WechatBaseRequest):
setting: str
value: bool = True
class NotificationRequest(WechatBaseRequest):
type: str = "all"
enable: bool = True
class ChatBgRequest(WechatBaseRequest):
wxid: str
image_path: str = ""
class DndRequest(WechatBaseRequest):
wxid: str
enable: bool = True
class PinChatRequest(WechatBaseRequest):
wxid: str
pin: bool = True
class QrScanRequest(WechatBaseRequest):
image_path: str = ""
class LabelContactRequest(WechatBaseRequest):
wxid: str
label_ids: List[str]
# ============================================================
# § 2 辅助函数
# ============================================================
async def _get_skill(device_id: str):
"""获取 WechatSkillV2 实例"""
from skills.wechat.skill_v2 import WechatSkillV2
return WechatSkillV2(device_id=device_id)
# ============================================================
# § 3 视频号操作H27
# ============================================================
@router.get("/channels/browse", response_model=dict)
async def browse_channels(device_id: str, limit: int = 10):
"""浏览视频号"""
skill = await _get_skill(device_id)
return await skill.browse_channels(limit)
@router.post("/channels/like", response_model=dict)
async def like_channel_video(req: ChannelVideoRequest):
"""视频号点赞"""
skill = await _get_skill(req.device_id)
return await skill.like_channel_video(req.video_id)
@router.post("/channels/comment", response_model=dict)
async def comment_channel_video(req: ChannelCommentRequest):
"""视频号评论"""
skill = await _get_skill(req.device_id)
return await skill.comment_channel_video(req.video_id, req.comment)
@router.post("/channels/follow", response_model=dict)
async def follow_channel(req: ChannelFollowRequest):
"""关注视频号"""
skill = await _get_skill(req.device_id)
return await skill.follow_channel(req.channel_id)
@router.post("/channels/unfollow", response_model=dict)
async def unfollow_channel(req: ChannelFollowRequest):
"""取消关注视频号"""
skill = await _get_skill(req.device_id)
return await skill.unfollow_channel(req.channel_id)
@router.post("/channels/share", response_model=dict)
async def share_channel_video(req: ShareChannelRequest):
"""分享视频号视频"""
skill = await _get_skill(req.device_id)
return await skill.share_channel_video(req.video_id, req.to_id)
# ============================================================
# § 4 小程序操作H32
# ============================================================
@router.post("/mini-program/open", response_model=dict)
async def open_mini_program(req: MiniProgramRequest):
"""打开小程序"""
skill = await _get_skill(req.device_id)
return await skill.open_mini_program(req.app_id, req.path)
@router.get("/mini-program/recent", response_model=dict)
async def get_recent_mini_programs(device_id: str):
"""获取最近使用的小程序"""
skill = await _get_skill(device_id)
return await skill.get_recent_mini_programs()
@router.post("/mini-program/share", response_model=dict)
async def share_mini_program(req: ShareMiniProgramRequest):
"""分享小程序"""
skill = await _get_skill(req.device_id)
return await skill.share_mini_program(req.app_id, req.to_id, req.title)
# ============================================================
# § 5 收藏管理H29
# ============================================================
@router.get("/favorites", response_model=dict)
async def get_favorites(device_id: str, limit: int = 50):
"""获取收藏列表"""
skill = await _get_skill(device_id)
return await skill.get_favorites(limit)
@router.post("/favorites/add", response_model=dict)
async def add_favorite(req: FavoriteRequest):
"""添加收藏"""
skill = await _get_skill(req.device_id)
return await skill.add_favorite(req.msg_svr_id, req.type)
@router.delete("/favorites/{local_id}", response_model=dict)
async def delete_favorite(local_id: str, device_id: str = ""):
"""删除收藏"""
skill = await _get_skill(device_id)
return await skill.delete_favorite(local_id)
# ============================================================
# § 6 公众号操作H36
# ============================================================
@router.get("/official-accounts", response_model=dict)
async def get_official_accounts(device_id: str, limit: int = 100):
"""获取关注的公众号列表"""
skill = await _get_skill(device_id)
return await skill.get_official_accounts(limit)
@router.post("/official-accounts/follow", response_model=dict)
async def follow_official_account(req: OfficialAccountRequest):
"""关注公众号"""
skill = await _get_skill(req.device_id)
return await skill.follow_official_account(req.account_id)
@router.post("/official-accounts/unfollow", response_model=dict)
async def unfollow_official_account(req: OfficialAccountRequest):
"""取消关注公众号"""
skill = await _get_skill(req.device_id)
return await skill.unfollow_official_account(req.account_id)
@router.get("/official-accounts/{account_id}/articles", response_model=dict)
async def get_official_account_articles(account_id: str, device_id: str = "", limit: int = 10):
"""获取公众号文章"""
skill = await _get_skill(device_id)
return await skill.get_official_account_articles(account_id, limit)
# ============================================================
# § 7 账号安全H24
# ============================================================
@router.post("/security/unblock", response_model=dict)
async def unblock_self(req: WechatBaseRequest):
"""自助解封"""
skill = await _get_skill(req.device_id)
return await skill.unblock_self()
@router.post("/security/change-password", response_model=dict)
async def change_password(req: PasswordRequest):
"""修改密码"""
skill = await _get_skill(req.device_id)
return await skill.change_password(req.old_password, req.new_password)
@router.post("/security/bind-phone", response_model=dict)
async def bind_phone(req: PhoneRequest):
"""绑定手机号"""
skill = await _get_skill(req.device_id)
return await skill.bind_phone(req.phone)
@router.post("/security/unbind-phone", response_model=dict)
async def unbind_phone(req: WechatBaseRequest):
"""解绑手机号"""
skill = await _get_skill(req.device_id)
return await skill.unbind_phone()
@router.get("/security/login-devices", response_model=dict)
async def get_login_devices(device_id: str):
"""获取登录设备列表"""
skill = await _get_skill(device_id)
return await skill.get_login_devices()
@router.delete("/security/login-device", response_model=dict)
async def remove_login_device(req: DeviceRemoveRequest):
"""移除登录设备"""
skill = await _get_skill(req.device_id)
return await skill.remove_login_device(req.target_device_id)
@router.post("/security/fingerprint", response_model=dict)
async def enable_fingerprint(req: ToggleRequest):
"""启用/禁用指纹"""
skill = await _get_skill(req.device_id)
return await skill.enable_fingerprint(req.enable)
@router.post("/security/account-protection", response_model=dict)
async def set_account_protection(req: ToggleRequest):
"""设置账号保护"""
skill = await _get_skill(req.device_id)
return await skill.set_account_protection(req.enable)
# ============================================================
# § 8 支付操作H25
# ============================================================
@router.post("/pay/red-packet", response_model=dict)
async def send_red_packet(req: RedPacketRequest):
"""发红包"""
skill = await _get_skill(req.device_id)
return await skill.send_red_packet(req.to_id, req.amount, req.message)
@router.post("/pay/red-packet/receive", response_model=dict)
async def receive_red_packet(req: ReceiveRequest):
"""收红包"""
skill = await _get_skill(req.device_id)
return await skill.receive_red_packet(req.msg_svr_id)
@router.post("/pay/transfer", response_model=dict)
async def send_transfer(req: TransferRequest):
"""转账"""
skill = await _get_skill(req.device_id)
return await skill.send_transfer(req.to_id, req.amount, req.description)
@router.post("/pay/transfer/receive", response_model=dict)
async def receive_transfer(req: ReceiveRequest):
"""收转账"""
skill = await _get_skill(req.device_id)
return await skill.receive_transfer(req.msg_svr_id)
@router.get("/pay/balance", response_model=dict)
async def get_wallet_balance(device_id: str):
"""获取钱包余额"""
skill = await _get_skill(device_id)
return await skill.get_wallet_balance()
@router.get("/pay/transactions", response_model=dict)
async def get_transaction_history(device_id: str, limit: int = 20):
"""获取交易记录"""
skill = await _get_skill(device_id)
return await skill.get_transaction_history(limit)
# ============================================================
# § 9 浮窗管理H38
# ============================================================
@router.post("/float/add", response_model=dict)
async def add_to_float(req: FloatRequest):
"""添加到浮窗"""
skill = await _get_skill(req.device_id)
return await skill.add_to_float(req.wxid)
@router.post("/float/remove", response_model=dict)
async def remove_from_float(req: FloatRequest):
"""从浮窗移除"""
skill = await _get_skill(req.device_id)
return await skill.remove_from_float(req.wxid)
# ============================================================
# § 10 表情管理H37
# ============================================================
@router.post("/emoji/send-custom", response_model=dict)
async def send_emoji_custom(req: EmojiSendRequest):
"""发送自定义表情"""
skill = await _get_skill(req.device_id)
return await skill.send_emoji(req.to_id, req.emoji_md5)
@router.post("/emoji/add-custom", response_model=dict)
async def add_custom_emoji(req: EmojiAddRequest):
"""添加自定义表情"""
skill = await _get_skill(req.device_id)
return await skill.add_custom_emoji(req.image_path)
# ============================================================
# § 11 账号管理H23
# ============================================================
@router.get("/profile", response_model=dict)
async def get_profile(device_id: str):
"""获取个人资料"""
skill = await _get_skill(device_id)
return await skill.get_profile()
@router.get("/account/status", response_model=dict)
async def check_account_status(device_id: str):
"""检查账号状态"""
skill = await _get_skill(device_id)
return await skill.check_account_status()
@router.post("/profile/nickname", response_model=dict)
async def set_nickname(req: ProfileSetRequest):
"""设置昵称"""
skill = await _get_skill(req.device_id)
return await skill.set_nickname(req.value)
@router.post("/profile/signature", response_model=dict)
async def set_signature(req: ProfileSetRequest):
"""设置签名"""
skill = await _get_skill(req.device_id)
return await skill.set_signature(req.value)
@router.post("/profile/avatar", response_model=dict)
async def set_avatar(req: ProfileSetRequest):
"""设置头像"""
skill = await _get_skill(req.device_id)
return await skill.set_avatar(req.value)
@router.post("/profile/sex", response_model=dict)
async def set_sex(req: ProfileSetRequest):
"""设置性别"""
skill = await _get_skill(req.device_id)
return await skill.set_sex(req.value)
@router.post("/profile/region", response_model=dict)
async def set_region(req: ProfileSetRequest):
"""设置地区"""
skill = await _get_skill(req.device_id)
return await skill.set_region(req.value)
@router.post("/profile/status", response_model=dict)
async def set_what_up(req: ProfileSetRequest):
"""设置状态"""
skill = await _get_skill(req.device_id)
return await skill.set_what_up(req.value)
# ============================================================
# § 12 搜索H31
# ============================================================
@router.get("/search", response_model=dict)
async def global_search(device_id: str, keyword: str, limit: int = 30):
"""全局搜索"""
skill = await _get_skill(device_id)
return await skill.global_search(keyword, limit)
# ============================================================
# § 13 设置H30
# ============================================================
@router.post("/settings/privacy", response_model=dict)
async def set_privacy(req: PrivacyRequest):
"""设置隐私"""
skill = await _get_skill(req.device_id)
return await skill.set_privacy(req.setting, req.value)
@router.post("/settings/notification", response_model=dict)
async def set_notification(req: NotificationRequest):
"""设置通知"""
skill = await _get_skill(req.device_id)
return await skill.set_notification(req.type, req.enable)
@router.post("/settings/clear-history", response_model=dict)
async def clear_chat_history(req: WxidRequest):
"""清除聊天记录"""
skill = await _get_skill(req.device_id)
return await skill.clear_chat_history(req.wxid)
@router.post("/settings/chat-background", response_model=dict)
async def set_chat_background(req: ChatBgRequest):
"""设置聊天背景"""
skill = await _get_skill(req.device_id)
return await skill.set_chat_background(req.wxid, req.image_path)
@router.post("/settings/dnd", response_model=dict)
async def set_do_not_disturb(req: DndRequest):
"""设置免打扰"""
skill = await _get_skill(req.device_id)
return await skill.set_do_not_disturb(req.wxid, req.enable)
@router.post("/settings/pin-chat", response_model=dict)
async def pin_chat(req: PinChatRequest):
"""置顶聊天"""
skill = await _get_skill(req.device_id)
return await skill.pin_chat(req.wxid, req.pin)
# ============================================================
# § 14 二维码H26
# ============================================================
@router.post("/qr/scan", response_model=dict)
async def scan_qr_code(req: QrScanRequest):
"""扫描二维码"""
skill = await _get_skill(req.device_id)
return await skill.scan_qr_code(req.image_path)
@router.get("/qr/my", response_model=dict)
async def generate_my_qr_code(device_id: str):
"""生成我的二维码"""
skill = await _get_skill(device_id)
return await skill.generate_my_qr_code()
@router.get("/qr/group/{group_id}", response_model=dict)
async def generate_group_qr_code(group_id: str, device_id: str = ""):
"""生成群二维码"""
skill = await _get_skill(device_id)
return await skill.generate_group_qr_code(group_id)
# ============================================================
# § 15 设备信息H39
# ============================================================
@router.get("/device-info", response_model=dict)
async def get_device_info(device_id: str):
"""获取设备信息"""
skill = await _get_skill(device_id)
return await skill.get_device_info()
@router.get("/storage-info", response_model=dict)
async def get_storage_info(device_id: str):
"""获取存储信息"""
skill = await _get_skill(device_id)
return await skill.get_storage_info()
@router.get("/network-info", response_model=dict)
async def get_network_info(device_id: str):
"""获取网络信息"""
skill = await _get_skill(device_id)
return await skill.get_network_info()
# ============================================================
# § 16 标签补全H28
# ============================================================
@router.post("/tag/set-contact", response_model=dict)
async def set_contact_label(req: LabelContactRequest):
"""设置联系人标签"""
skill = await _get_skill(req.device_id)
return await skill.set_contact_label(req.wxid, req.label_ids)
@router.get("/tag/contacts/{label_id}", response_model=dict)
async def get_contacts_by_label(label_id: str, device_id: str = ""):
"""按标签获取联系人"""
skill = await _get_skill(device_id)
return await skill.get_contacts_by_label(label_id)
# ============================================================
# § 17 Hook 状态
# ============================================================
@router.get("/hook/status", response_model=dict)
async def get_hook_status(device_id: str):
"""获取 Hook 状态"""
skill = await _get_skill(device_id)
return await skill.get_hook_status()
@router.get("/hook/process-info", response_model=dict)
async def get_process_info(device_id: str):
"""获取微信进程信息"""
skill = await _get_skill(device_id)
return await skill.get_process_info()
@router.get("/hook/wechat-version", response_model=dict)
async def get_wechat_version(device_id: str):
"""获取微信版本"""
skill = await _get_skill(device_id)
return await skill.get_wechat_version()
# ============================================================
# § 18 统一执行入口
# ============================================================
class UnifiedExecuteRequest(BaseModel):
device_id: str
action: str
params: dict = Field(default_factory=dict)
timeout: int = 30
@router.post("/execute", response_model=dict)
async def unified_execute(req: UnifiedExecuteRequest):
"""
统一执行入口 — 支持所有 112 个微信操作
通过 action 名直接调用对应的 Frida RPC 方法。
通道自动选择Hook > WebSocket Agent > UI 自动化
"""
skill = await _get_skill(req.device_id)
return await skill.execute(req.action, req.params)
@router.get("/actions", response_model=dict)
async def list_all_actions():
"""列出所有支持的微信操作"""
from skills.wechat.skill_v2 import WECHAT_ACTIONS, MODULES
return {
"success": True,
"total_actions": len(WECHAT_ACTIONS),
"total_modules": len(MODULES),
"modules": {k: v["name"] for k, v in MODULES.items()},
"actions": sorted(WECHAT_ACTIONS.keys()),
}