外观
01 · 取密钥与解密
本章把「拿到密钥 → 解密成明文库」这条最硬的链路走通。配套代码在 code/wechat_win/,已在 微信 4.1.12.55 / Windows 11 实测跑通。
模块分工:
| 文件 | 职责 |
|---|---|
mem_windows.py | 进程查找 + 内存枚举/读取(纯 ctypes) |
dll_scan_win.py | 扫 Weixin.dll 提取 internal_db_key(pefile) |
sqlcipher4.py | SQLCipher-4 密钥派生、HMAC 校验、逐页 AES 解密 |
key_extractor_win.py | 内存原始密钥候选 + XOR 合并 + 多进程验证 |
paths_win.py | 数据库路径发现 |
main_win.py | CLI,把上面串起来 |
0. 安装依赖
powershell
cd course/wechat-ai-assistant/code
pip install -r wechat_win/requirements-win.txt依赖只有四个:pycryptodome(AES)、zstandard(消息解压)、psutil(找主进程)、 pefile(解析 DLL)。内存读取用 ctypes,标准库自带。
1. SQLCipher-4:解密与验证(sqlcipher4.py)
这是全链路的地基。上一章的加密参数在这里变成代码。核心是三个函数。
密钥派生——把 32 字节裸密钥 + salt 变成 enc_key(解密用)和 mac_key(校验用):
python
def derive_keys(raw_key: bytes, salt: bytes) -> tuple[bytes, bytes]:
enc_key = hashlib.pbkdf2_hmac("sha512", raw_key, salt, KDF_ITER, KEY_SZ) # 256000 次
mac_salt = bytes(b ^ 0x3a for b in salt)
mac_key = hashlib.pbkdf2_hmac("sha512", enc_key, mac_salt, HMAC_KDF_ITER, KEY_SZ) # 2 次
return enc_key, mac_key验证密钥——重算第 1 页 HMAC,和存储值比对。这是「候选密钥对不对」的判据,很快:
python
def verify_key(first_page, salt, raw_key) -> bool:
_, mac_key = derive_keys(raw_key, salt)
hmac_off = PAGE_SIZE - RESERVE + IV_SZ # = 4032
stored = first_page[hmac_off:hmac_off + HMAC_SZ]
calc = _page_hmac(mac_key, first_page, 1, SALT_SZ) # 第 1 页跳过前 16 字节 salt
return hmac.compare_digest(stored, calc)逐页解密——每页取出 IV,AES-256-CBC 解密密文区;第 1 页把 salt 头补回成 SQLite 头:
python
def decrypt_db(src_path, hex_key, dst_path):
...
for i in range(total_pages):
data_start = SALT_SZ if i == 0 else 0
iv = page[PAGE_SIZE - RESERVE : PAGE_SIZE - RESERVE + IV_SZ]
cipher_text = page[data_start : PAGE_SIZE - RESERVE]
plain = AES.new(enc_key, AES.MODE_CBC, iv).decrypt(cipher_text)
page_out = (SQLITE_HEADER + plain if i == 0 else plain) + page[PAGE_SIZE - RESERVE:]
out.extend(page_out)
verify_enc_key是一个优化:内存里驻留的有时已经是派生后的enc_key,此时只需 2 次 迭代就能校验,适合对海量候选快速筛选。
先自测再往下走——不接触微信,用随机数据造一份合法密文,验证往返一致:
powershell
python wechat_win/selftest_crypto.py
# 期望:SELFTEST PASS: 派生/HMAC/AES 往返一致自测过了,说明你的解密内核完全正确;后面再失败,一定是「密钥没取对」而不是解密错。
2. 读进程内存(mem_windows.py)
Windows 没有 /proc/<pid>/mem,改用 kernel32 的三件套(纯 ctypes):
find_weixin_pid():用 psutil 找所有Weixin.exe,选私有内存最大的那个 (主进程才持有 DB 句柄和密钥,小程序运行时WeChatAppEx.exe不算)。open_process(pid):OpenProcess(PROCESS_VM_READ | QUERY_INFORMATION),失败通常是权限。enum_regions(handle):VirtualQueryEx遍历地址空间,只留已提交、可读写、私有 的区域(密钥藏在私有堆里),跳过超大区域。read_region(handle, base, size):ReadProcessMemory读出来。
同用户下的进程一般无需管理员;读不到时用管理员 PowerShell 重试。
3. 扫 DLL 取内部密钥(dll_scan_win.py)
微信 4.x 内存里的原始密钥要和一个编译进 Weixin.dll 的 internal_db_key XOR 后才可用。 用正则在代码段里匹配「连续 4 条 mov rdx,imm64 + test rax,rax」的特征:
python
_PATTERN = re.compile(
rb"\x48\xBA(.{8})" rb".{3,8}?\x48\xBA(.{8})"
rb".{3,8}?\x48\xBA(.{8})" rb".{3,8}?\x48\xBA(.{8})"
rb".{3,8}?\x48\x85\xC0", re.DOTALL)4 个 8 字节立即数拼成 32 字节候选。resolve_weixin_dll() 会依次从入参、注册表 InstallPath、C:\Program Files\Tencent\Weixin\<版本>\ 里定位 DLL。
4. 合成并验证密钥(key_extractor_win.py)
把前面几步拼起来,这是「取密钥」的主逻辑:
scan_raw_key_candidates(handle):在内存里按签名[ptr(8)][0][0x20][0x2f]找指针,读指针指向的 32 字节,做低熵过滤(去掉明显不是 密钥的字节序列)。- 对每个原始候选,先试不 XOR,再试和每个
internal_db_keyXOR,用sqlcipher4.verify_key校验第 1 页 HMAC。命中即真密钥。 - 候选多时用
multiprocessing并行验证,命中即terminate。 extract_all_keys()为多个库(message / contact)一次性提取,且优先复用 已找到的密钥(多库常共用一把)。
5. 一条命令跑通(main_win.py)
CLI 把「找进程 → 定位库 → 取密钥 → 解密 → 读消息/联系人」串起来:
powershell
# 提取密钥并打印最近消息和联系人(密钥默认脱敏显示)
python -m wechat_win.main_win
# 打印完整密钥
python -m wechat_win.main_win --dump-key
# 导出解密后的明文库(可用 DB Browser 直接打开,也供第 3 章 MCP 使用)
python -m wechat_win.main_win --out C:\temp\wx_plain
# 版本不匹配时手动指定回退
python -m wechat_win.main_win --db-base E:\xwechat_files --pid 1234 `
--dll "C:\Program Files\Tencent\Weixin\4.1.12.55\Weixin.dll"
python -m wechat_win.main_win --internal-key <64位hex>跑通后你会看到消息表数量、若干会话的最近消息、联系人条数。记住 --out C:\temp\wx_plain 这一步导出的明文库——第 3 章的 MCP 直接指向它,MCP 层就 完全不用碰密钥了。
故障排查
- 提取不到密钥:确认微信已登录运行;用管理员 PowerShell;多开时
--pid指定主进程。 - DLL 无候选 / 版本不匹配:新版汇编特征可能变,用
--internal-key手动传,或放宽dll_scan_win.py的匹配间距。 - HMAC 始终不过:先跑
selftest_crypto.py确认内核没问题;再核对mac_key长度=32、reserve=80、SHA512。
macOS
密钥获取方式不同(lldb 断点 CCKeyDerivationPBKDF 截获口令),需要 lldb 且微信可调试; 解密/读库与本章完全一致。步骤见 code/wechat_mac/README-mac.md,可先跑 python3 wechat_mac/selftest_mac.py 验证平台无关部分。
上一章:00 · 架构与原理 | 下一章:02 · 只读读库层