# MoWeChat — 莫荷微信 Bot (Linux GDB Hook 版)

## 项目定位

将莫荷的微信 Bot 从 Windows（wxhelper DLL 注入）迁移到 **Linux 服务器上原生运行**。

**核心约束（已和老爸确认）：**
1. 不能走 ClawBot/iLink 通道（那个是独立的 Bot 身份，不是莫荷本人微信号）
2. 不能走 wine（3.9.x 微信登录被腾讯封了）
3. 不能用 Windows 降版本工具（已经坏了）
4. 必须拦截发给莫荷微信号的所有消息（跟之前 wxhelper 一样）
5. 不使用任何 Web/逆向协议方案（被封号风险高）

## 技术方案

### 最终方案：官方 Linux 微信 + GDB Hook

```
Linux 服务器
│
├─ 微信 Linux AppImage（腾讯官方出品，最新版 x86_64）
│   └─ 正常扫码登录（无版本封禁问题）
│
├─ GDB（GNU Debugger）
│   └─ 附加到微信进程 → 在消息解密后的函数入口设断点
│   │   └─ 当新消息到达时，从内存中提取：发送者ID、消息内容、消息类型
│   │
│   └─ GDB Python API 脚本（gdb_hook_messages.py）
│       └─ 读取 → 处理 → 转发到 Hermes Gateway (:8642)
│
├─ Xvfb（虚拟显示器）
│   └─ 让微信在无头服务器上运行（不需要物理显示器）
│
└─ Hermes Gateway (:8642)
    └─ 处理消息逻辑（OCR、文章抓取、回复生成）
```

### 为什么选 GDB 而不是 LD_PRELOAD

| 方案 | 优点 | 缺点 |
|------|------|------|
| **GDB Hook** | 标准 Linux 工具、无需编译、Python 可编程、有 2026-03 成功案例 | 性能略低、断点地址版本相关 |
| **LD_PRELOAD** (lmclmc 方案) | 性能好、可同时处理收发 | 需要写 C 代码、目标版本太老(wechat-beta 1.0.0.145) |
| **wine + wxhelper** | 代码复用 Windows 版 | 3.9.x 登录被腾讯封了 ❌ |

## 信息源（重要，请先阅读）

### GDB 方案（首选参考）

| 来源 | 链接 | 内容 |
|------|------|------|
| **Ajax's Blog (2026-03-11)** | https://aajax.top/2026/03/11/GettingLinuxWechatMessages/ | **核心参考。** 用 GDB 调试 Linux 微信 AppImage v4.1.0.16，IDAPRO+CodeX 辅助逆向，找到了消息接收断点位置 `NewSync_ProcessStashMsgList`。Python 脚本提取消息内容。有 Docker 封装。 |
| **看雪论坛** | https://bbs.kanxue.com/thread-282965.htm | 原始思路来源：GDB 分析 Linux 微信内存，找到消息明文地址后 Hook 打印 |
| **lmclmc/linux-wechat-hook** | https://github.com/lmclmc/linux-wechat-hook | LD_PRELOAD 方案（旧），wechat-beta 1.0.0.145 版本。有 C 源码和 libX.so。可以看思路但不能直接用。 |
| **52pojie 教程** | https://www.52pojie.cn/thread-1955523-1-1.html | lmclmc 方案的详细讲解 |

### 已排除的方案

| 来源 | 链接 | 排除原因 |
|------|------|----------|
| Hermes Weixin 文档 | https://hermes-agent.nousresearch.com/docs/zh-Hans/user-guide/messaging/weixin | ClawBot 身份，不是微信号代理 |
| weixin-bot-sdk | https://github.com/epiral/weixin-bot | 同上，官方 iLink API 也是 ClawBot |
| 原 Windows 版 | `gateway/scripts/wechat_agent.py` | 降版本工具坏了，Windows 依赖 |
| wine | - | 3.9.x 微信登录被腾讯封了 |

## 当前状态（2026-06-23 21:30）

### ✅ 已完成
1. 项目结构搭建：`gateway/linux/` 下有 `hooks/` `docs/` `logs/` `temp/`
2. WeChat Linux AppImage 已下载：`gateway/linux/WeChatLinux.AppImage`（276MB，最新版）
3. 系统依赖已安装：`gdb`、`xdotool`、`Xvfb`
4. 原 Windows 版保留不动（`gateway/scripts/wechat_agent.py`）
5. Git 已初始化并 push（commit `9c73e8b`）

### ⏳ 待完成（接手后的工作）

#### Phase 1：验证微信能跑
```bash
# 启动虚拟显示器
Xvfb :99 -screen 0 1280x720x24 &
export DISPLAY=:99

# 运行微信
./gateway/linux/WeChatLinux.AppImage

# 用莫荷手机微信扫码登录
# 确认登录成功后，找到微信的 PID
pidof wechat
```

**注意：**
- 微信是 Electron 应用，AppImage 首次运行可能需要加 `--no-sandbox`
- 如果微信检测到是 root 或沙箱环境，可加 `--disable-gpu` 启动
- 二维码显示需要 GUI 环境，可以截屏后用 OCR 读取，或者用手机微信的"扫一扫"直接扫终端二维码

#### Phase 2：写 GDB Hook 脚本

参考 Ajax's Blog 的思路，核心脚本放 `hooks/gdb_hook_messages.py`：

```python
# 伪代码 — 参考 https://aajax.top/2026/03/11/GettingLinuxWechatMessages/
import gdb

class WechatMessageBreakpoint(gdb.Breakpoint):
    def __init__(self, address):
        super().__init__(f"*{address}")
    
    def stop(self):
        # 读取寄存器中的消息指针
        msg_ptr = int(gdb.parse_and_eval("$rsi"))
        
        # 从内存中提取消息结构体字段
        msg_type = int(gdb.parse_and_eval(f"*(int*)({msg_ptr} + 0x14)"))
        svrid = int(gdb.parse_and_eval(f"*(long long*)({msg_ptr} + 0x50)"))
        
        # 提取消息内容（具体偏移量需要逆向当前版本）
        # ...
        
        # 转发到 Hermes
        forward_to_hermes(sender, content)
        
        return False  # 继续执行，不阻塞微信

# 附加到微信进程
gdb.execute(f"attach {pid}")
bp = WechatMessageBreakpoint("0x4994BEB")  # 地址随版本变化！
```

**关键问题：断点地址随微信版本变化**
- Ajax 的文章用的是 4.1.0.16，断点在 `NewSync_ProcessStashMsgList` 内
- 当前下载的 AppImage 可能版本不同，需要用 IDA Pro（或其他逆向工具）重新找断点
- 让 LLM（如 CodeX）辅助逆向：IDA Pro + CodeX 可帮助定位消息处理函数
- 或者用 GDB 的 `info functions` 配合字符串搜索来找

找断点的方法论（来自 Ajax）：
1. 用 IDA Pro 打开微信的 ELF 二进制（在 AppImage squashfs-root 内）
2. 搜索字符串特征（如 "MMTLS"、"NewSync" 等）
3. 追踪 MMTLS → 解密 → 消息内容 → 消息通知 的调用链
4. 在 `NewSync_ProcessStashMsgList` 或类似函数中设断
5. 验证断点能正确拦截消息

#### Phase 3：实现消息发送

GDB Hook 解决了接收问题。发送消息有三种可能的方案：

**方案 A：GDB call（最干净）**
```gdb
# 调用微信内部发送函数
call send_message_func("wxid", "消息内容")
```
需要找到微信的发送消息函数地址。

**方案 B：xdotool GUI 自动化**
```bash
# 找到微信聊天窗口，输入内容，按回车
xdotool search --name "微信" windowfocus
xdotool type "消息内容"
xdotool key Return
```
缺点是微信窗口需要在前台。

**方案 C：xsel/xclip 剪贴板 + 快捷键**
```bash
echo "消息内容" | xclip -selection clipboard
xdotool key ctrl+v
xdotool key Return
```

**方案 D：LD_PRELOAD Hook 发送函数**
参考 lmclmc/linux-wechat-hook 的思路，写一个 libX.so 同时 intercept 接收和发送。

建议先试方案 A（如果能找到发送函数地址），否则用方案 B/C。

#### Phase 4：对接 Hermes

复用 `gateway/linux/wechat_agent.py` 中的：
- `call_hermes()` → POST 到 Hermes Gateway :8642
- `process_tags()` → 处理 [IMG] [FILE] 等标签
- OCR → doubao vision API
- 文章处理 → article_processor :5810
- 5801 HTTP server → 接收 Hermes 主动推送

## 项目文件结构

```
AgentsMeeting/
├─ gateway/
│  ├─ scripts/
│  │  └─ wechat_agent.py          ← Windows 版（不动）
│  └─ linux/
│     ├─ WeChatLinux.AppImage     ← 官方 Linux 微信（已下载，.gitignore 排除）
│     ├─ wechat_agent.py          ← 之前 iLink 方案的试错代码（可参考但不要用）
│     ├─ hooks/
│     │  └─ gdb_hook_messages.py  ← GDB Hook 主脚本（待实现）
│     ├─ docs/
│     │  └─ architecture.md      ← 本文档
│     ├─ logs/                    ← 日志输出
│     └─ temp/                    ← 临时文件
├─ .gitignore                     ← 已添加 *.AppImage *.exe *.dll
└─ ...
```

## 关键 Git 提交记录

| Commit | 说明 |
|--------|------|
| `1417552` | fix: group chat detection + article URL handling (旧 iLink 方案的) |
| `9c73e8b` | **docs: architecture design doc + gitignore update（当前最新）** |

## 常见问题

### Q: GDB 附加到微信会被检测吗？
GDB 使用 ptrace 系统调用，微信理论上可以检测。但 Ajax 的文章中实测可用，没有触发风控。GDB 只是只读地读取内存，不修改微信代码逻辑，风险较低。

### Q: 微信版本升级了怎么办？
断点地址会变。维护策略：
1. 保留旧版 AppImage 文件
2. 新版发布时，用 IDA Pro + CodeX 重新定位断点
3. 更新 `gdb_hook_messages.py` 中的地址

### Q: 为什么不用 iLink/ClawBot 方案？
iLink Bot API（包括 Hermes 内置的 weixin 平台）创建的是一个独立的 ClawBot 身份。别人需要给这个 ClawBot 发消息，而不是给莫荷本人发消息。老爸明确不要这个。

## 联系

- **知微**：持仓分析师 Agent，这份文档是我写的
- **莫荷**：接手人
- **老爸（hmo/莫语不语）**：用户
- **笑笑（xxm）**：Windows 侧开发者，OpenCode 维护者
