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

13 KiB
Raw Permalink Blame History

macOS WeChat 密钥提取:权限与签名完全指南

基于多台机器 (macOS 10.15 ~ 15.x, Intel + Apple Silicon) 的实测经验总结。

核心结论

能否从微信进程提取加密密钥,取决于 两个独立问题

问题 控制什么 关键因素
task_for_pid() 能否成功 读取进程内存 目标 App 的代码签名
codesign 能否重签名 修改 App 文件 调用者的完全磁盘访问

一、task_for_pid 权限(读取微信内存)

决定因素:微信 App 的 Hardened Runtime

# 检查微信签名状态
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都能成功。

# 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 是否生效

# 重连 SSH 后执行
cat ~/Library/Application\ Support/com.apple.TCC/TCC.db > /dev/null 2>&1 && echo "FDA: YES" || echo "FDA: NO"

TCC.db 是受保护文件,只有 FDA 进程能读取。

完整流程SSH 远程重签名微信

# 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 Controlbundle id + csreq 联合校验权限。csreqcode requirement是从 app 的 code signature 推导出的二进制 blob存在 /Library/Application Support/com.apple.TCC/TCC.dbaccess 表里,每条 ~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

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 提示重新允许:

killall WeChat
open /Applications/WeChat.app

这一步应当由用户/agent 手动执行,不在 wx init 里自动跑——TCC 重置会让用户的现有授权失效,需要由人决定时机。

macOS 26 的 UI 拆分

在 macOS 26 上,隐私与安全 → 录屏与系统录音 显示为两块,容易踩坑:

区域 作用
录屏与系统录音(上半区) 录制屏幕内容 + 系统音频;微信截图、屏幕共享需要这一项
仅系统录音(下半区) 只录系统音频;只打开这一项不能修复微信截图

把 WeChat 加进上半区;只勾下半区的"仅系统录音"无效。

验证

确认 WeChat 当前是 ad-hoc 签名(这是修复前提):

codesign -dv --verbose=4 /Applications/WeChat.app 2>&1 | grep -E "Signature|flags|TeamIdentifier"

期望看到:

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要求用户执行

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 签名 WeChatsshd 拿不到 TCC 开发者工具授权,这时才必须走重签路径

长期方向:

  • 这条副作用的真正修复是把 wx init 重新设计成 safe → assisted → invasive fallback 三层:默认不动 WeChat只有在前两条都不可行时才走 ad-hoc 重签,并先打出完整副作用清单让用户显式确认。在那之前,这是已知 trade-off。