102 lines
7.7 KiB
Markdown
102 lines
7.7 KiB
Markdown
# WxAgent
|
||
|
||
WxAgent 使用 C#/.NET 8 独立实现微信 Windows 桌面端自动化能力。当前已完成 **M1 技术验证**、M2 会话/消息扩展切片、M3 监听和完整消息模型,并包含只读数据库 MVP。
|
||
|
||
## 项目结构
|
||
|
||
- `node-agent/`:Windows 节点端,C#/.NET 8;包含 UIA、Win32、Desktop Agent、CLI、托盘和节点本地服务兼容层。
|
||
- `control-plane/`:远程中心控制面,Go;Go 测试与实现代码同目录。
|
||
- `tests/node-agent/`:节点端 .NET 测试及只读 SQL 离线检查。
|
||
- 远程控制面架构、部署、验证与限制见 [`docs/WxAgent-远程控制面架构与部署说明-v1.0.md`](docs/WxAgent-远程控制面架构与部署说明-v1.0.md)。
|
||
|
||
## 当前能力
|
||
|
||
- `doctor`:检测 Windows 会话、`Weixin.exe` 进程/版本/只读访问权限、微信窗口、关键 UIA 控件和数据库根目录。
|
||
- `inspect-ui`:通过 FlaUI.UIA3 导出脱敏 UI 树;名称和动态 AutomationId 只保留长度和短哈希。
|
||
- `session list/search/current/open`:列出可见会话、输出分类搜索结果和精确匹配、读取及切换当前会话。
|
||
- `chat send/read/history/listen/monitor`:仅以文件传输助手做默认验证,支持文本发送、可见及历史消息读取,并以 UIA 结构事件结合两秒低频轮询实时发现消息。
|
||
- `chat monitor`:逐行输出 `MessageEvent` JSON,使用有界语义指纹去重和受当前用户 ACL 保护的 checkpoint,支持 Host 重启后的短期续接;默认隐藏正文和引用内容。
|
||
- 消息模型覆盖文本、图片、文件、视频、语音、链接、引用和系统消息;公开监听 API 为 `IAsyncEnumerable<MessageEvent>`,可选回调逐个隔离异常。
|
||
- `chat reply-latest`:通过消息行实时边界右侧气泡定位执行引用回复;解析微信 `回复文本\n引用 <发送者> 的消息 : <原文>` 格式。
|
||
- `chat send-file/send-image`:使用剪贴板粘贴发送文件或真实图片数据,不打开文件选择框,并恢复常见文本、图片或文件剪贴板内容。
|
||
- `smoke`:执行 `doctor`、脱敏 UI 树导出,并向文件传输助手发送唯一 ASCII 标记后读回确认。
|
||
- 远程控制面支持节点注册、心跳、任务队列、`send-text` 以及受本地白名单保护的会话/联系人/消息只读任务;当前实现与部署方式见架构说明文档。
|
||
- 文本输入使用 UIA ValuePattern 直接设置并在发送前逐字校验,避免中文输入法组合态改变消息内容。
|
||
- `db scan`:以 `PROCESS_QUERY_INFORMATION | PROCESS_VM_READ` 扫描 WCDB 十六进制候选,只保存通过具体数据库 page 1 HMAC-SHA512 验证的密钥。
|
||
- `db query`:通过 SQLCipher 4 以文件系统 ReadOnly、私有缓存、无连接池和 `query_only` 读取 `sqlite_master` 元数据,并确认写操作被拒绝。
|
||
|
||
## 安全边界
|
||
|
||
允许读取本机 `Weixin.exe` 的已提交可读内存和本机加密数据库。禁止 DLL 注入、内存修改、数据库写入、协议破解、登录/验证码/风控绕过。候选密钥不会被输出;只有带 `--save` 的显式命令才会将已验证密钥原子保存到当前用户 LocalAppData,并应用当前用户 ACL。当前受控环境使用明文 hex key 存储,尚未引入 DPAPI。
|
||
|
||
没有进程句柄到数据库文件路径关联时,`PageHmacVerified` 仅证明密钥属于具体数据库,不表示账号当前活跃。
|
||
|
||
## 构建
|
||
|
||
```bash
|
||
export PATH="$HOME/.dotnet:$PATH"
|
||
dotnet restore WxAgent.sln -p:EnableWindowsTargeting=true
|
||
dotnet test tests/node-agent/WxAgent.Core.Tests -c Release
|
||
dotnet build WxAgent.sln -c Release -p:EnableWindowsTargeting=true
|
||
dotnet publish node-agent/WxAgent.Host -c Release -r win-x64 --self-contained true \
|
||
-p:EnableWindowsTargeting=true -p:PublishSingleFile=true \
|
||
-p:IncludeNativeLibrariesForSelfExtract=true -p:PublishTrimmed=false
|
||
```
|
||
|
||
## CLI
|
||
|
||
```powershell
|
||
WxAgent.Host doctor
|
||
WxAgent.Host inspect-ui --output artifacts/ui-tree.json
|
||
WxAgent.Host smoke --timeout 45
|
||
WxAgent.Host chat send --text "hello"
|
||
WxAgent.Host session list
|
||
WxAgent.Host session search --query "文件传输助手" --exact
|
||
WxAgent.Host session current
|
||
WxAgent.Host session open --name "文件传输助手"
|
||
WxAgent.Host chat read --limit 20
|
||
WxAgent.Host chat read --limit 20 --include-content
|
||
WxAgent.Host chat history --limit 100 --scrolls 10
|
||
WxAgent.Host chat reply-latest --text "quoted reply"
|
||
WxAgent.Host chat send-file --path C:\path\file.txt
|
||
WxAgent.Host chat send-image --path C:\path\image.png
|
||
WxAgent.Host chat listen --seconds 30
|
||
WxAgent.Host chat monitor --seconds 60 --state-file artifacts\listener-state.json
|
||
WxAgent.Host db scan --timeout 120
|
||
WxAgent.Host db scan --save --timeout 120
|
||
WxAgent.Host db status
|
||
WxAgent.Host db query --account <account-root-fingerprint> --database contact/contact.db
|
||
WxAgent.Host db contacts --account <account-root-fingerprint> --limit 200 --offset 0
|
||
WxAgent.Host db contacts --account <account-root-fingerprint> --contains "搜索文本" --limit 200 --offset 200
|
||
```
|
||
|
||
默认密钥文件:`%LOCALAPPDATA%\WxAgent\database-keys.json`。CLI 和日志不会打印完整密钥。
|
||
|
||
`db contacts` 按 username 排序,`--contains` 为区分大小写的字面量子串,不把 `%`、`_` 当通配符。根据 `hasMore/nextOffset` 继续读取,下一页须保持相同账号和筛选条件;默认隐藏昵称、备注及头像地址,标识符脱敏。跨页不是事务快照,读取期间发生联系人增删时可能重复或遗漏。
|
||
|
||
公共 C# 分页入口为 `WechatChatClient.GetContactsPageAsync(limit, offset, contains, groupsOnly, accountId, keyFile, cancellationToken)`;`groupsOnly: true` 读取数据库已知群,`false` 读取非群联系人,`null` 读取全部。多账号必须明确选择,不推断哪个账号当前已登录。`GetFriendsAsync` 是有数量上限的兼容接口;完整读取使用分页入口。群成员通过 `chat_room`、`chatroom_member`、`contact` 的只读 join 读取,不回退 UI 枚举;原生 URL 卡片通过微信内置浏览器的“更多 → 转发…”发送,`chat send-url-card` 不需要 `--confirm`。其余管理操作必须检查 `Success/Code`;只有明确返回 `ResultUnconfirmed` 时才表示未完成确认、禁止自动重试。剩余限制见 [PENDING](docs/PENDING.md)。
|
||
|
||
## Windows 真机验证
|
||
|
||
目标主机:`10.1.1.101`,用户 `rogee`,微信 `C:\Program Files\Tencent\Weixin\Weixin.exe`。UIA 命令必须在微信所在的已登录、未锁定交互会话中运行;SSH Session 0 只能用于部署和非 UI 数据库命令。
|
||
|
||
```bash
|
||
scp -r node-agent/WxAgent.Host/bin/Release/net8.0-windows10.0.19041.0/win-x64/publish/* \
|
||
rogee@10.1.1.101:'C:/Users/Rogee/wx-agent/'
|
||
```
|
||
|
||
发布后至少运行:
|
||
|
||
```powershell
|
||
WxAgent.Host doctor
|
||
WxAgent.Host inspect-ui --output artifacts/ui-tree.json
|
||
WxAgent.Host smoke
|
||
WxAgent.Host db scan --save --timeout 180
|
||
WxAgent.Host db status
|
||
WxAgent.Host db query --account <fingerprint> --database <relative-db-path>
|
||
```
|
||
|
||
M1 已完成文件传输助手激活、文本发送/读回、新消息发现和微信重启后的重新连接验证。M2 扩展切片已完成会话搜索精确匹配、引用回复解析、历史滚动读取及去重;验收见 `docs/validation/M2-Search-Quote-History-2026-09-04.md`。M3 已完成实时监听、轮询兜底、完整消息类型、有界去重、回调隔离和 checkpoint 重启续接;验收见 `docs/validation/M3-Listening-2026-09-04.md`。重启后若微信要求手机确认登录,必须由用户正常确认;WxAgent 不绕过登录流程。
|
||
|
||
`SQLitePCLRaw.bundle_e_sqlcipher` 2.1.11 仅用于当前开发与真机验证。正式商业发布前必须完成许可与安全基线评审;若不能接受其已弃用状态、SQLCipher 4.5.2 community 和 SQLite 3.39.2,则切换 Zetetic 官方 SQLCipher for .NET 后重新执行全部数据库验收。
|