wx-cli/docs/macos-permission-guide.md

322 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# macOS WeChat 密钥提取:权限与签名完全指南
> 基于多台机器 (macOS 10.15 ~ 15.x, Intel + Apple Silicon) 的实测经验总结。
## 核心结论
能否从微信进程提取加密密钥,取决于 **两个独立问题**
| 问题 | 控制什么 | 关键因素 |
|------|---------|---------|
| `task_for_pid()` 能否成功 | 读取进程内存 | **目标 App 的代码签名** |
| `codesign` 能否重签名 | 修改 App 文件 | **调用者的完全磁盘访问** |
---
## 一、task_for_pid 权限(读取微信内存)
### 决定因素:微信 App 的 Hardened Runtime
```bash
# 检查微信签名状态
codesign -dv /Applications/WeChat.app 2>&1 | grep -E "Signature|flags"
```
#### 情况 AAd-hoc 签名(无 Hardened Runtime
```
flags=0x2(adhoc)
Signature=adhoc
TeamIdentifier=not set
```
**原因**: 安装过防撤回补丁等第三方修改工具App 被重新签名。
**权限要求**: 只需 `sudo`任何上下文Terminal、SSH、cron都能成功。
```bash
# SSH 远程直接可用
sudo ./find_all_keys_macos
```
#### 情况 BApple 官方签名(有 Hardened Runtime
```
flags=0x10000(runtime)
Signature size=9092
Authority=...Apple...
```
**原因**: App Store 下载或官方 DMG 安装,未经修改。
**权限要求**: `sudo` + 本机 GUI 终端 + TCC "开发者工具"授权。SSH **不可行**。
```
taskgated 检查流程:
目标有 hardened runtime?
YES → 检查调用者的"负责应用"是否有 TCC DeveloperTool 授权
SSH 的负责应用是 sshd → 无法获得 TCC 授权 → 拒绝
Terminal.app 可以弹窗获得授权 → 允许
NO → root (sudo) 即可 → 允许
```
### 实测数据
| 机器 | macOS | WeChat 签名 | 本机 Terminal sudo | SSH sudo |
|------|-------|------------|-------------------|---------|
| MacBook (macOS 15.x) | 15.x | **ad-hoc** (防撤回补丁) | ✅ | ✅ |
| Mac mini (Catalina) | 10.15.8 | Apple 官方 runtime | ✅ | ❌ |
| MacBook Pro (Big Sur) | 11.1 | Apple 官方 runtime | ✅ | ❌ |
### SSH 下穷举过的所有方法Apple 签名时全部失败)
| 方法 | 结果 | 错误信息 |
|------|------|---------|
| `sudo frida -p <pid>` | ❌ | unable to access process |
| `lldb -p <pid>` | ❌ | non-interactive debug session |
| `sudo gcore <pid>` | ❌ | insufficient privilege |
| 带 debugger entitlement 的 C 程序 | ❌ | KERN_FAILURE=5 |
| `launchctl asuser` (用户会话) | ❌ | task_for_pid=5 |
| LaunchAgent (Aqua GUI 会话) | ❌ | 非 root需要 sudo |
| LaunchDaemon (root) | ❌ | 系统域无 GUI 上下文 |
| `launchctl submit` (root) | ❌ | 同上 |
| `osascript` 操控 Terminal.app | ❌ | 需要辅助功能权限/挂起 |
| 修改 TCC.db 给 sshd 授权 | ❌ | SIP 保护restricted 只读 |
| `vmmap` / `heap` | ⚠️ | 只能看元数据,无法读内存 |
---
## 二、codesign 权限(重签名微信 App
如果微信是 Apple 官方签名,需要重签名为 ad-hoc 来解锁 SSH 提取。
### 问题SSH 下 codesign 可能失败
```
$ sudo codesign --force --deep --sign - /Applications/WeChat.app
/Applications/WeChat.app: Operation not permitted
In subcomponent: /Applications/WeChat.app/Contents/MacOS/WeChatAppEx.app
```
**原因**: SSH 进程没有「完全磁盘访问」(Full Disk Access, FDA) 权限,无法修改 `/Applications` 下的 App bundle 文件。
### 给 SSH 授予完全磁盘访问
在目标机器的 **GUI** 上操作:
```
系统偏好设置 → 安全性与隐私 → 隐私 → 完全磁盘访问
点击 🔒 解锁 → 点 + 号 → Cmd+Shift+G 输入路径
```
**必须添加这两个**(缺一不可):
| 路径 | 说明 |
|------|------|
| `/usr/sbin/sshd` | SSH 守护进程 |
| `/usr/libexec/sshd-keygen-wrapper` | SSH 的实际执行进程(负责应用) |
> ⚠️ 添加后必须**断开 SSH 重新连接**TCC 权限在进程启动时检查,不会热更新。
### 验证 FDA 是否生效
```bash
# 重连 SSH 后执行
cat ~/Library/Application\ Support/com.apple.TCC/TCC.db > /dev/null 2>&1 && echo "FDA: YES" || echo "FDA: NO"
```
TCC.db 是受保护文件,只有 FDA 进程能读取。
### 完整流程SSH 远程重签名微信
```bash
# 0. 前提SSH 已有 FDA上面的步骤
# 1. 确认微信已退出
kill $(pgrep -x WeChat) 2>/dev/null
sleep 2
pgrep -x WeChat && echo "还在运行!" || echo "已退出"
# 2. 清除扩展属性(可选,防止干扰)
sudo xattr -cr /Applications/WeChat.app
# 3. Ad-hoc 重签名
sudo codesign --force --deep --sign - /Applications/WeChat.app
# 4. 验证签名
codesign -dv /Applications/WeChat.app 2>&1 | grep -E "Signature|flags"
# 期望: flags=0x2(adhoc), Signature=adhoc
# 5. 用户需在 GUI 上重新打开微信并登录
# (或者 SSH 执行 open但用户仍需在 GUI 上完成登录)
open /Applications/WeChat.app
```
### 注意事项
| 事项 | 说明 |
|------|------|
| 微信必须先退出 | 运行中的 App其 dylib/binary 被占用codesign 会报 `internal error` |
| **重签名后必须重启微信** | 已运行的进程仍使用旧签名的内存映像task_for_pid 仍会失败。必须 kill 后重新启动 |
| 重签名后需重新登录微信 | 签名变更会使登录态失效 |
| 自动更新可能覆盖签名 | 微信更新后变回 Apple 签名,需要再次重签 |
| 小程序可能受影响 | 部分小程序校验签名ad-hoc 可能报安全错误 |
---
## 三、权限矩阵总结
| 操作 | 需要的权限 | SSH 需要额外配置 |
|------|-----------|-----------------|
| 读取微信数据库文件 | 文件系统权限(通常有) | 无 |
| `task_for_pid` (ad-hoc App) | sudo | 无 |
| `task_for_pid` (Apple 签名 App) | sudo + TCC DeveloperTool | **不可行**,必须本机 Terminal |
| `codesign` 重签名 App | sudo + FDA | SSH 需添加 sshd + sshd-keygen-wrapper 到 FDA |
| 修改 TCC.db | sudo + 关闭 SIP | **不推荐** |
### 完全远程操作清单(一次性 GUI 配置)
只需在目标机器 GUI 上做一次,之后 SSH 永久可用:
1. **完全磁盘访问** → 添加 `/usr/sbin/sshd``/usr/libexec/sshd-keygen-wrapper`
2. SSH 连入 → `sudo codesign --force --deep --sign - /Applications/WeChat.app`
3. 用户在 GUI 重开微信并登录
4. 之后 SSH 永久可以 `sudo` 提取密钥,微信重启也不影响(除非更新覆盖签名)
---
## 四、常见误区
| 误区 | 真相 |
|------|------|
| "需要给终端完全磁盘访问才能调试" | ❌ FDA 控制文件访问,不控制进程调试 |
| "需要给终端开发者工具权限" | ⚠️ 仅当目标 App 有 hardened runtime 时才需要 |
| "SSH 下永远无法提取密钥" | ❌ 目标 App 是 ad-hoc 签名时SSH sudo 可以 |
| "macOS 版本决定了能否 SSH 调试" | ❌ 主要取决于目标 App 的签名状态 |
| "SIP 阻止了调试微信" | ❌ SIP 只保护系统进程,微信不受 SIP 保护 |
| "加了 sshd 到 FDA 就行" | ❌ 还需要加 `sshd-keygen-wrapper`,且要重连 SSH |
| "微信开着也能重签名" | ❌ 运行中的 binary/dylib 被占用codesign 会失败 |
---
## 五、重签名后微信权限 silent 失效
### 现象
完成 ad-hoc 重签名后,微信任意以下功能都可能"看起来已授权但实际被拒绝"
- 截图 / 屏幕共享(`ScreenCapture`
- 视频通话 / 扫码(`Camera`
- 语音消息 / 通话(`Microphone`
- 自动化、第三方输入法(`AppleEvents`
- 同步通讯录(`AddressBook`
- 文件发送 / 接收(`SystemPolicyDocumentsFolder` / `Downloads` / `Desktop`
System Settings 里通常仍看到"微信.app"开关是 ON但运行时权限校验失败。微信会反复弹"需要开启 X 权限"。
### 根因(第一性原理)
macOS TCCTransparency, Consent, and Control**bundle id + csreq** 联合校验权限。`csreq`code requirement是从 app 的 code signature 推导出的二进制 blob存在 `/Library/Application Support/com.apple.TCC/TCC.db``access` 表里,每条 ~160 字节。
`codesign --force --deep --sign -` 把 WeChat 从官方签名换成 ad-hoc 签名(甚至 ad-hoc → ad-hoc 重签也会变),新进程的 csreq 跟旧记录里那条对不上 —— tccd 拒绝。
System Settings UI 只按 client 显示开关、不重算 csreq所以视觉上是"已授权",运行时实际拒绝。这是 silent drift。
### 修复步骤
把 WeChat 在 TCC 里的旧记录全部抹掉,让 macOS 在下次微信请求权限时按新签名重新生成 csreq
```bash
for s in ScreenCapture Camera Microphone AppleEvents AddressBook \
SystemPolicyDocumentsFolder SystemPolicyDownloadsFolder SystemPolicyDesktopFolder; do
tccutil reset "$s" com.tencent.xinWeChat
done
```
`tccutil` 对没有授权过的 service 会报 "No such bundle identifier",这是 no-op不影响其他 service 的 reset。
之后退出并重新打开微信,按 GUI 提示重新允许:
```bash
killall WeChat
open /Applications/WeChat.app
```
> 这一步**应当由用户/agent 手动执行**,不在 `wx init` 里自动跑——TCC 重置会让用户的现有授权失效,需要由人决定时机。
#### macOS 26 的 UI 拆分
在 macOS 26 上,**隐私与安全 → 录屏与系统录音** 显示为两块,容易踩坑:
| 区域 | 作用 |
|------|------|
| **录屏与系统录音**(上半区) | 录制屏幕内容 + 系统音频;微信截图、屏幕共享需要这一项 |
| **仅系统录音**(下半区) | 只录系统音频;只打开这一项**不能**修复微信截图 |
把 WeChat 加进上半区;只勾下半区的"仅系统录音"无效。
### 验证
确认 WeChat 当前是 ad-hoc 签名(这是修复前提):
```bash
codesign -dv --verbose=4 /Applications/WeChat.app 2>&1 | grep -E "Signature|flags|TeamIdentifier"
```
期望看到:
```text
flags=0x2(adhoc)
Signature=adhoc
TeamIdentifier=not set
```
最直接的功能验证:在微信里使用截图、视频通话、麦克风等功能,按 GUI 弹窗的"允许"重新授权一次,之后正常工作。
---
## 六、`"微信" 想访问其他 App 的数据` 弹窗
### 现象
执行过 `wx init`、对 `/Applications/WeChat.app` 做过 ad-hoc 重签名之后,再使用微信时会比较频繁地看到 macOS 弹出:
```
"微信" 想访问其他 App 的数据。
单独存放 App 数据可让你更容易管理隐私和安全。
[ 不允许 ] [ 允许 ]
```
最常见的触发面是**在微信里打开公众号文章**,但这只是高频触发面,不是根因。
### 根因(第一性原理)
这弹窗是 macOS Ventura+ / 14 / 15 对 **app data container 跨身份访问** 的保护:当前进程("微信")正在读取另一个 code identity 的 app 留下的数据。
我们当前 macOS 方案为了让 `task_for_pid` 能拿到 WeChat 的 task port、读取进程内存里的 raw key要求用户执行
```bash
codesign --force --deep --sign - /Applications/WeChat.app
```
这一步把 WeChat 从 Apple 官方签名换成 ad-hoc 身份。对用户来说它仍然是"微信";对 macOS 安全模型来说,**重签前的 WeChat** 和 **重签后的 WeChat** 已经不是同一个 app identity。
之后当(重签后的)微信访问它原本的 `~/Library/Containers/com.tencent.xinWeChat/...`、缓存、app group 等数据时,系统看到的是"一个新身份在读旧身份留下的 container 数据",于是按隐私保护策略弹这个对话框。公众号文章里的 webview / cookie / 缓存路径刚好踩到了这条访问路径,所以"打开公众号就弹"会非常容易复现,但**本质不是公众号页面的问题**,而是 code identity + container access。
> 注意:这**不是** "wx-cli 在偷偷读别的 App 的数据"wx-cli 进程本身对 WeChat container 是只读访问;但**要求用户重签 WeChat** 这一步本身就是这类弹窗的直接诱因。所以这是当前 macOS invasive init 路径的已知副作用,不是与 wx-cli 无关的系统行为。
### 应对
短期缓解:
- 点"允许"通常只是放行**当前这次** WeChat 进程;下一次 WeChat 启动权限会 reset可能还会再弹
- 该授权一般不会在 System Settings 里留下显式开关,因为它绑定的是动态的 code identity
彻底不弹:
-`/Applications/WeChat.app` 恢复成官方签名(重装官方 WeChat 包),不再执行 `codesign --force --deep --sign -`
- 这一步只是放弃**当前依赖 ad-hoc 重签的默认路径**,并不等于放弃 macOS memory-scan在本机 GUI Terminal 下、对 Terminal.app 授予「开发者工具」TCC 权限后,`task_for_pid` 对 Apple 官方签名hardened runtime的 WeChat 应当仍能走通——参考 §一 实测表里的"Apple 签名 + 本机 Terminal sudo = ✅"
- ⚠️ 实测覆盖范围说明:§一 实测表里 "Apple 签名 + 本机 Terminal sudo ✅" 的两条实证只覆盖 macOS 10.15 (Catalina) 与 11.1 (Big Sur)macOS 14 (Sonoma) / 15 (Sequoia) 上是否仍走通**未在本项目内实测**。如果你按这条路恢复官方签名后发现 init 走不通,请回到重签路径并接受本节描述的弹窗副作用
- 真正受限的场景是 SSH 远程 + Apple 签名 WeChat`sshd` 拿不到 TCC 开发者工具授权,这时才必须走重签路径
长期方向:
- 这条副作用的真正修复是把 `wx init` 重新设计成 `safe → assisted → invasive fallback` 三层:默认不动 WeChat只有在前两条都不可行时才走 ad-hoc 重签,并先打出完整副作用清单让用户显式确认。在那之前,这是已知 trade-off。