Evanyuan-builder/wechat-4.1.10-macos-key

GitHub: Evanyuan-builder/wechat-4.1.10-macos-key

针对微信 macOS 4.1.10 版本,在内存扫描和 sqlite3_key 断点均失效后,通过 Hook CommonCrypto 的 CCCrypt 函数提取 SQLCipher 数据库密钥的修复方案。

Stars: 0 | Forks: 0

# 微信 4.1.10 (macOS) 数据库密钥提取:内存扫描与 `sqlite3_key` 均告失效 —— 请改用 Hook `CCCrypt` **TL;DR** — 在 macOS(Apple Silicon,macOS 26)版的微信 **4.1.10** 中,两种公开文档中用于恢复每个数据库 SQLCipher 密钥的方法**均已失效**: 1. **在内存中扫描 `x'<64hex key><32hex salt>'`**(被 `ydotdog/wechat-export-macos`、`Thearas/wechat-db-decrypt-macos`、WxEcho 等使用)—— 缓存的密钥字符串**已不再存在于进程内存中**。 2. **对 `sqlite3_key` 设置 lldb 断点**(ac0d3r/imipy 的方法)—— 微信 4.1.10 **彻底剥离了 SQLCipher 符号**,因此 `breakpoint set -n sqlite3_key` 会解析到 **0 个位置**。 在 4.1.10 上可用的方法是:**对 CommonCrypto 的 `CCCrypt` / `CCCryptorCreate` 设置 lldb 断点**(微信的 WCDB 使用 CommonCrypto 作为其 AES 后端;`_CCCrypt` 是一个在剥离操作后依然存在的动态导入公开符号),并在页面解密的瞬间捕获 32 字节的密钥参数。你将获得**每个数据库**对应的唯一不同密钥。 这并非一种全新的通用密钥恢复技术(运行时 Hook 早已为人所知)—— 这是一个**针对特定版本的修复方案**:现有工具在 4.1.10 上已失效,而这种新方法依然奏效。 ## 证据 ### 1. 在 4.1.10 上,`x'...'` 密钥字符串已从内存中消失 对微信进程的可读内存进行了详尽扫描(**7.6 GB,约 5.65 亿个候选 32 字节窗口**),发现**没有**任何值能将 `message_0.db` 的第 1 页解密为有效的 SQLite 标头,测试内容包括: - 原始 32 字节窗口(8 字节对齐及 salt 附近未对齐的区域)、 - 64 字符的十六进制字符串形式、 - 以 salt 为锚点的窗口(在数据库 16 字节 salt 每次出现的 ±16 KB 范围内)、 - 一个**与加密参数无关的验证器**(对第 1 页进行 AES-256-CBC 解密 → 检查 `page_size==4096`、`write_ver==read_ver`、reserved-bytes ∈ {32,48,64,80}、第 1 页的 b-tree 类型 ∈ {0x02,0x05,0x0a,0x0d}),并遍历 reserve ∈ {48,64,80} 以及多种 IV 位置。 结果:**未找到密钥**。salt 本身*确实*驻留在内存中(它是缓存的第 1 页映像的前 16 个字节),但派生密钥从未以明文形式存放在它附近。结论是:在 4.1.10 上,派生的 SQLCipher 密钥**并不驻留在可扫描的内存中** —— 它只在每次页面解密时经过 AES 原语。 `Thearas/wechat-db-decrypt-macos/find_key_memscan.py` 使用了 `HEX_PATTERN = re.compile(rb"x'([0-9a-fA-F]{64,192})'")`,其 README 声明它是在 **4.1.2.241** 上测试的 —— 也就是说,那是属于内存扫描的时代。而 4.1.10 早已超越了那个阶段。 ### 2. SQLCipher 符号在 4.1.10 上被彻底剥离 ``` # /Applications/WeChat.app 中的每个 Mach-O: nm -a | grep -iE "sqlite3_key|sqlite3_rekey|sqlcipher|codec_set_cipher" → (nothing) nm -a Contents/Frameworks/wechat.dylib | grep -c sqlite3 → 0 ``` 因此,文档中记录的 `breakpoint set -n sqlite3_key` 无法解析。但主二进制文件导入的 AES 原语: ``` nm -u Contents/MacOS/WeChat | grep _CCCrypt → _CCCrypt ``` ### 3. Hook `CCCrypt` 可获取密钥 lldb 断点(arm64 参数寄存器),自动记录任何 32 字节的密钥然后继续执行: - `CCCrypt(op, alg, options, key, keyLength, iv, …)` → key=`x3`, keyLength=`x4` - `CCCryptorCreate(op, alg, options, key, keyLength, iv, …)` → key=`x3`, keyLength=`x4` - `CCCryptorCreateWithMode(op, mode, alg, padding, iv, key, keyLength, …)` → key=`x5`, keyLength=`x6` 在应用中浏览聊天 / 朋友圈 / 收藏会触发页面解密;每个数据库都会暴露其独有的 32 字节密钥(观察到**每个数据库对应一个密钥**,这与 4.1.x 版本中报告的“24 个按数据库区分的密钥”一致)。离线验证:捕获到的 `message_0.db` 密钥能使用**标准**的 SQLCipher-4 参数(AES-256-CBC、HMAC-SHA512、reserve=80、页面 4096、原始密钥模式)将第 1 页解密为有效的 SQLite 标头。因此,4.1.10 上改变的仅仅是*密钥传递方式*,而不是加密算法。 ### macOS 26 前置条件:你无法原地重新签名 `/Applications/WeChat.app` App Management 保护机制意味着即使是 `sudo codesign --force --deep --sign - /Applications/WeChat.app` 也会返回 `Operation not permitted`。可以通过先将 bundle 复制到用户拥有的目录来绕过此限制: ``` ditto /Applications/WeChat.app ~/wechat_copy/WeChat.app codesign --force --deep --sign - ~/wechat_copy/WeChat.app # ad-hoc, clears hardened runtime open -n ~/wechat_copy/WeChat.app # same container → same login/data ``` 然后执行 `sudo lldb -p ` 并设置 CCCrypt 断点。 ## 诚实的适用范围 - **并非**首个微信 macOS 版的密钥提取方法;运行时 Hook 和按数据库区分的密钥在 4.1.2 中已有记录。 - **确实是**一个适用于 **4.1.10** 的有效途径,通过 Hook CommonCrypto 原语,解决了 `x'...'` 内存扫描和 `sqlite3_key` 断点双双失效的问题。 - 在一台机器上进行了测试:微信 4.1.10,macOS 26.5.1,Apple Silicon。 环境声明:仅供个人导出自己的账户数据使用。
标签:LLDB, SQLCipher, 云资产清单, 客户端加密, 微信, 数据解密, 逆向工程