diff --git a/README.md b/README.md index fe3a1f8..47e2a19 100644 --- a/README.md +++ b/README.md @@ -48,15 +48,17 @@ chmod +x patch.sh # 添加可执行权限 ### 可选:启用"撤回通知带原文" -完成基础安装后,在终端前台运行消息监听,撤回通知就会带上原文。 +完成基础安装后,安装消息监听服务,撤回通知就会带上原文(当前只支持私聊,群聊暂不支持)。 ```bash -./patch.sh --monitor # 前台运行消息监听,Ctrl+C 退出 +./patch.sh --monitor-install # 安装(后台自动运行,开机自启) +./patch.sh --monitor-status # 查看状态 +./patch.sh --monitor-uninstall # 卸载 ``` -监听运行期间,收到的消息会被缓存;对方撤回时通知自动展示消息原文。 +安装后无需手动操作。微信启动时自动开始监听消息、微信关闭后自动收尾、下次启动再次跟随。 -不运行此命令也不影响防撤回主功能,撤回通知降级为不带原文。 +不安装也不影响防撤回主功能,撤回通知降级为不带原文。 > **已知限制**:部分群聊消息因内部对象结构差异,可能无法缓存原文,撤回时会降级为不带原文的通知。私聊消息和大部分群聊消息可正常获取原文。 @@ -67,8 +69,9 @@ chmod +x patch.sh # 添加可执行权限 ```bash ./patch.sh --debug # 不装 hook,仅签名允许 lldb attach -./patch.sh --monitor # 前台运行消息监听 +./patch.sh --monitor # 前台运行消息监听(调试用,Ctrl+C 退出) cat /tmp/antirevoke_debug.log # 防撤回日志 +cat /tmp/wechat_monitor_daemon.log # 监听 daemon 日志 cat /tmp/wechat_msg_cache.tsv # 消息缓存 ``` @@ -103,9 +106,9 @@ cat /tmp/wechat_msg_cache.tsv # 消息缓存 - **聊天框内无撤回提示**:由于微信 4.x 的架构限制(C++ 实现 + 符号 strip + 数据库加密),无法在聊天界面内插入系统消息。替代方案为 macOS 系统通知。 -- **撤回通知原文需 monitor 在跑**:消息原文功能依赖前台 `./patch.sh --monitor` 监听消息。不运行时撤回通知降级为不带原文。 +- **撤回通知原文需 monitor 服务运行**:通过 `./patch.sh --monitor-install` 安装后自动后台运行。未安装时撤回通知降级为不带原文。 -- **monitor 运行时微信会被 lldb attach**:性能影响极小(每条消息触发约 1ms 断点回调)。如果不需要原文功能,不启动 monitor 即可。 +- **monitor 运行时微信会被 lldb attach**:性能影响极小(每条消息触发约 1ms 断点回调)。如果不需要原文功能,不安装 monitor 即可。 ## 风险说明 diff --git a/patch.sh b/patch.sh index fa44d99..8638a7d 100755 --- a/patch.sh +++ b/patch.sh @@ -1065,9 +1065,9 @@ do_uninstall() { # ======================== 消息监听(撤回原文)======================== -# 释放内嵌脚本到 MONITOR_INSTALL_DIR +MONITOR_INSTALL_DIR="$HOME/.local/share/wechatintercept" + deploy_monitor_files() { - MONITOR_INSTALL_DIR="/tmp/wechatintercept_monitor" mkdir -p "$MONITOR_INSTALL_DIR" # wechat_msg_monitor.py @@ -1690,6 +1690,111 @@ EOF lldb -s "$INIT_FILE" } +# ── 后台 daemon ────────────────────────────────────────── +MONITOR_LABEL="com.wechatintercept.monitor" +MONITOR_PLIST="$HOME/Library/LaunchAgents/${MONITOR_LABEL}.plist" +MONITOR_DAEMON="$MONITOR_INSTALL_DIR/monitor_daemon.sh" +MONITOR_LOG="/tmp/wechat_monitor_daemon.log" +MONITOR_PID="/tmp/wechat_monitor_daemon.pid" + +deploy_daemon() { + deploy_monitor_files + cat > "$MONITOR_DAEMON" << 'DAEMON_SH' +#!/bin/bash +set -u +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +PY_SCRIPT="$SCRIPT_DIR/wechat_msg_monitor.py" +LOG="/tmp/wechat_monitor_daemon.log" +PID_FILE="/tmp/wechat_monitor_daemon.pid" +log() { echo "[$(date '+%H:%M:%S')] $*" >> "$LOG"; } +cleanup() { [ -n "${LLDB_PID:-}" ] && kill "$LLDB_PID" 2>/dev/null; rm -f "$PID_FILE"; exit 0; } +trap cleanup INT TERM EXIT +[ -f "$PID_FILE" ] && kill -0 "$(cat "$PID_FILE" 2>/dev/null)" 2>/dev/null && exit 0 +echo $$ > "$PID_FILE" +log "daemon start pid=$$" +LLDB_PID="" ; LAST_PID="" +while true; do + WPID=$(pgrep -x WeChat | head -1 || true) + if [ -z "$WPID" ]; then + [ -n "$LLDB_PID" ] && kill "$LLDB_PID" 2>/dev/null && wait "$LLDB_PID" 2>/dev/null + LLDB_PID="" ; LAST_PID="" + sleep 3; continue + fi + if [ "$WPID" != "$LAST_PID" ] || [ -z "$LLDB_PID" ] || ! kill -0 "$LLDB_PID" 2>/dev/null; then + [ -n "$LLDB_PID" ] && kill "$LLDB_PID" 2>/dev/null && wait "$LLDB_PID" 2>/dev/null + log "attach wechat pid=$WPID" + INIT=$(mktemp /tmp/wx_mon.XXXXXX) + cat > "$INIT" << LLDBEOF +command script import "$PY_SCRIPT" +process attach --pid $WPID +wx_monitor_start +continue +LLDBEOF + lldb -b -s "$INIT" >> "$LOG" 2>&1 & + LLDB_PID=$! + LAST_PID="$WPID" + sleep 5 + rm -f "$INIT" + fi + sleep 5 +done +DAEMON_SH + chmod +x "$MONITOR_DAEMON" +} + +do_monitor_install() { + deploy_daemon + mkdir -p "$HOME/Library/LaunchAgents" + cat > "$MONITOR_PLIST" << EOF + + + + + Label + ${MONITOR_LABEL} + ProgramArguments + + ${MONITOR_DAEMON} + + RunAtLoad + + KeepAlive + + StandardOutPath + ${MONITOR_LOG} + StandardErrorPath + ${MONITOR_LOG} + ThrottleInterval + 10 + + +EOF + launchctl unload "$MONITOR_PLIST" 2>/dev/null || true + launchctl load "$MONITOR_PLIST" + echo "[OK] 消息监听已安装(后台自动运行)" + echo " 日志:tail -f $MONITOR_LOG" + echo " 状态:$0 --monitor-status" + echo " 卸载:$0 --monitor-uninstall" +} + +do_monitor_uninstall() { + [ -f "$MONITOR_PLIST" ] && launchctl unload "$MONITOR_PLIST" 2>/dev/null && rm -f "$MONITOR_PLIST" + [ -f "$MONITOR_PID" ] && kill "$(cat "$MONITOR_PID" 2>/dev/null)" 2>/dev/null; rm -f "$MONITOR_PID" + [ -d "$MONITOR_INSTALL_DIR" ] && rm -rf "$MONITOR_INSTALL_DIR" + echo "[OK] 消息监听已卸载" +} + +do_monitor_status() { + [ -f "$MONITOR_PLIST" ] && echo "LaunchAgent: 已安装" || echo "LaunchAgent: 未安装" + if [ -f "$MONITOR_PID" ] && kill -0 "$(cat "$MONITOR_PID" 2>/dev/null)" 2>/dev/null; then + echo "daemon: 运行中 (pid=$(cat "$MONITOR_PID"))" + else echo "daemon: 未运行"; fi + WPID=$(pgrep -x WeChat | head -1 || true) + [ -n "$WPID" ] && echo "微信: 运行中 (pid=$WPID)" || echo "微信: 未运行" + [ -f /tmp/wechat_msg_cache.tsv ] && echo "缓存: $(wc -l < /tmp/wechat_msg_cache.tsv) 行" || echo "缓存: 空" + [ -f "$MONITOR_LOG" ] && echo "" && echo "── 最近日志 ──" && tail -5 "$MONITOR_LOG" +} + # ======================== 入口 ======================== case "${1:-}" in --debug|-d) @@ -1701,14 +1806,26 @@ case "${1:-}" in --monitor) do_monitor_foreground ;; + --monitor-install) + do_monitor_install + ;; + --monitor-uninstall) + do_monitor_uninstall + ;; + --monitor-status) + do_monitor_status + ;; --help|-h) print_banner echo "用法:" - echo " $0 安装防撤回" - echo " $0 --monitor 前台运行消息监听(调试用)" - echo " $0 --debug 调试模式(无 hook,允许 lldb)" - echo " $0 --uninstall 卸载防撤回" - echo " $0 --help 帮助" + echo " $0 安装防撤回" + echo " $0 --monitor-install 安装消息监听(后台自动运行)" + echo " $0 --monitor-uninstall 卸载消息监听" + echo " $0 --monitor-status 查看监听状态" + echo " $0 --monitor 前台运行消息监听(调试用)" + echo " $0 --debug 调试模式(无 hook,允许 lldb)" + echo " $0 --uninstall 卸载防撤回" + echo " $0 --help 帮助" ;; "") do_install