feat(hook): 扩展 ACTION_TO_RPC 映射与 wechat_hook_v2 RPC 实现
同步 agent/app 双端 hook_executor 动作表与 wechat_hook_v2.js exports; 补充 hook 子脚本与 _hook_smoke 冒烟入口,更新 device_modules 探测结果。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -177,8 +177,118 @@ ACTION_TO_RPC: Dict[str, str] = {
|
||||
"get_process_info": "getProcessInfo",
|
||||
"get_wechat_version": "getWechatVersion",
|
||||
"batch_execute": "batchExecute",
|
||||
|
||||
# ── 矩阵 v8.0.56 补全(Frida RPC 直映射)──
|
||||
"get_safety_center": "getSafetyCenter",
|
||||
"check_restrictions": "checkRestrictions",
|
||||
"get_top_stories": "getTopStories",
|
||||
"get_wechat_steps": "getWechatSteps",
|
||||
"get_sticker_list": "getStickerList",
|
||||
"show_payment_code": "showPaymentCode",
|
||||
"like_wechat_steps": "likeWechatSteps",
|
||||
"clear_cache": "clearCache",
|
||||
"check_for_update": "checkForUpdate",
|
||||
}
|
||||
|
||||
# unified / ADB 引擎方法名 → HookExecutor 标准 action(矩阵 v8.0.56 真机验收)
|
||||
ACTION_ALIASES: Dict[str, str] = {
|
||||
"recall_message": "revoke_message",
|
||||
"search_contact": "search_contacts",
|
||||
"get_friend_info": "get_contact_info",
|
||||
"account_status": "check_account_status",
|
||||
"safety_center": "get_safety_center",
|
||||
"set_chat_top": "pin_chat",
|
||||
"set_mute_chat": "set_do_not_disturb",
|
||||
"get_video_list": "browse_channels",
|
||||
"show_my_qr": "generate_my_qr_code",
|
||||
"view_wallet": "get_wallet_balance",
|
||||
"view_transactions": "get_transaction_history",
|
||||
"wechat_search": "global_search",
|
||||
"top_stories": "get_top_stories",
|
||||
"get_steps": "get_wechat_steps",
|
||||
"get_tags": "get_labels",
|
||||
"create_tag": "create_label",
|
||||
"delete_tag": "delete_label",
|
||||
"set_remark": "set_friend_remark",
|
||||
"add_to_favorites": "add_favorite",
|
||||
"clear_history": "clear_chat_history",
|
||||
"like_video": "like_channel_video",
|
||||
"send_voice_message": "send_voice",
|
||||
"set_group_notice": "set_group_announcement",
|
||||
"transfer": "send_transfer",
|
||||
"receive_payment": "receive_transfer",
|
||||
"unblock_account": "unblock_self",
|
||||
"unblock_appeal": "unblock_self",
|
||||
"appeal_restriction": "unblock_self",
|
||||
"unblock_with_sms": "unblock_self",
|
||||
"set_gender": "set_sex",
|
||||
"set_moments_cover": "set_privacy",
|
||||
"set_moments_privacy": "set_privacy",
|
||||
"forward_moments_link": "post_moments",
|
||||
"open_miniprogram": "open_mini_program",
|
||||
"do_not_disturb": "set_do_not_disturb",
|
||||
"like_steps": "like_wechat_steps",
|
||||
"toggle_do_not_disturb": "set_do_not_disturb",
|
||||
"clear_cache": "clear_cache",
|
||||
"check_for_update": "check_for_update",
|
||||
"send_file_from_chat": "send_file",
|
||||
"send_voice_message": "send_voice",
|
||||
"add_to_favorites": "add_favorite",
|
||||
}
|
||||
|
||||
|
||||
def resolve_action(action: str) -> str:
|
||||
return ACTION_ALIASES.get(action, action)
|
||||
|
||||
|
||||
def normalize_params(action: str, params: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""统一 API 参数 → Frida RPC 参数(user_id→wxid 等)"""
|
||||
p = dict(params or {})
|
||||
resolved = resolve_action(action)
|
||||
# 文件传输助手显示名 → wxid
|
||||
for key in ("user_id", "wxid", "to_id", "conversation_id"):
|
||||
if p.get(key) in ("文件传输助手", "File Transfer"):
|
||||
p[key] = "filehelper"
|
||||
if p.get("user_id") and not p.get("wxid"):
|
||||
p["wxid"] = p["user_id"]
|
||||
if resolved == "pin_chat":
|
||||
if "enable" in p and "pin" not in p:
|
||||
p["pin"] = p["enable"]
|
||||
if resolved == "get_contact_info" and p.get("user_id") and not p.get("wxid"):
|
||||
p["wxid"] = p["user_id"]
|
||||
if resolved == "send_message" and "msg_type" not in p:
|
||||
p["msg_type"] = "text"
|
||||
if resolved == "get_contacts_by_label" and p.get("tag_name") and not p.get("label_name"):
|
||||
p["label_name"] = p["tag_name"]
|
||||
if resolved == "create_label" and p.get("tag_name") and not p.get("name"):
|
||||
p["name"] = p["tag_name"]
|
||||
if p.get("to_id") and not p.get("user_id"):
|
||||
p["user_id"] = p["to_id"]
|
||||
if p.get("user_id") and not p.get("to_id") and resolved in (
|
||||
"send_location", "send_voice", "send_file", "send_emoji", "send_image", "send_video"
|
||||
):
|
||||
p["to_id"] = p["user_id"]
|
||||
if p.get("name") and not p.get("label"):
|
||||
p["label"] = p["name"]
|
||||
if p.get("emoji_name") and not p.get("emoji_md5"):
|
||||
p["emoji_md5"] = p["emoji_name"]
|
||||
if p.get("name") and not p.get("app_id") and resolved == "open_mini_program":
|
||||
p["app_id"] = p["name"]
|
||||
if p.get("index") is not None and not p.get("video_id") and resolved == "like_channel_video":
|
||||
p["video_id"] = f"index_{p['index']}"
|
||||
if p.get("privacy_type") and not p.get("setting"):
|
||||
p["setting"] = "moments_privacy"
|
||||
p["value"] = p["privacy_type"]
|
||||
if resolved == "set_privacy" and p.get("days") and not p.get("setting"):
|
||||
p["setting"] = "moments_days"
|
||||
p["value"] = p["days"]
|
||||
if p.get("content") and not p.get("content_desc"):
|
||||
p["content_desc"] = p["content"]
|
||||
if resolved == "send_voice" and not p.get("voice_path") and p.get("duration"):
|
||||
p["voice_path"] = f"/sdcard/workphone/voice_{int(p['duration'])}s.amr"
|
||||
return p
|
||||
|
||||
|
||||
MODULE_NAMES = {
|
||||
"H15": "消息接收", "H16": "联系人", "H17": "消息发送",
|
||||
"H18": "好友请求", "H19": "好友管理", "H20": "朋友圈发布",
|
||||
@@ -206,17 +316,20 @@ class HookExecutor:
|
||||
if not self.available:
|
||||
return {"success": False, "error": "Hook 通道不可用(Frida 未连接)", "channel": "hook"}
|
||||
|
||||
rpc_method = ACTION_TO_RPC.get(action)
|
||||
canonical = resolve_action(action)
|
||||
norm = normalize_params(action, params)
|
||||
rpc_method = ACTION_TO_RPC.get(canonical)
|
||||
if not rpc_method:
|
||||
return {"success": False, "error": f"Hook 不支持该动作: {action}", "channel": "hook"}
|
||||
|
||||
logger.info(f"[HookExecutor] {action} → rpc.{rpc_method}")
|
||||
result = self.frida.call_rpc(rpc_method, params or {})
|
||||
logger.info(f"[HookExecutor] {action} → {canonical} → rpc.{rpc_method}")
|
||||
result = self.frida.call_rpc(rpc_method, norm)
|
||||
result["channel"] = "hook"
|
||||
result["action_resolved"] = canonical
|
||||
return result
|
||||
|
||||
def supports(self, action: str) -> bool:
|
||||
return action in ACTION_TO_RPC
|
||||
return resolve_action(action) in ACTION_TO_RPC
|
||||
|
||||
def get_supported_actions(self) -> list:
|
||||
return sorted(ACTION_TO_RPC.keys())
|
||||
|
||||
Reference in New Issue
Block a user