Davy
fe5cc633ff
feat: transcribe_voice 新增 whisper.cpp 后端(macOS Metal GPU 加速) ( #78 )
...
* Add transcribe_chat_whisper_cpp.py: macOS whisper.cpp transcription
whisper.cpp variant of transcribe_chat.py for Apple Silicon Macs.
Advantages over transcribe_chat.py:
- Uses whisper-cpp CLI with Metal/ANE GPU acceleration (3-5x faster)
- No PyTorch or openai/whisper Python dependency
- Same idempotent, crash-safe design as transcribe_chat.py
- Auto-detects model from common macOS locations:
~/Library/Application Support/whisper-cpp/,
~/Library/Application Support/Recordly/whisper/, etc.
- --model-size flag for automatic download if no model found
- Configurable --language (default: zh) and --threads
Usage: python3 transcribe_chat_whisper_cpp.py <input.json> [output.json]
* refactor: 将 whisper.cpp 转为后端选项集成到 mcp_server.py 中
根据 PR #78 review 反馈,将独立的 transcribe_chat_whisper_cpp.py 重构为
mcp_server.py 中的 whisper_cpp 后端,与 PR #66 OpenAl 后端模式对齐。
变更:
- mcp_server.py: 新增 _transcribe_whisper_cpp()、_resolve_whisper_cpp_binary()、
_resolve_whisper_cpp_model(),更新 _resolve_active_backend()/_cache_signature()/
_transcribe() 以分发至 whisper_cpp 后端
- transcribe_chat.py: 统一入口 mcp_server._transcribe 自动支持新后端,
仅补充了 backend 打印信息
- 删除 transcribe_chat_whisper_cpp.py
config.json 启用方式:
"transcription_backend": "whisper_cpp",
"whisper_cpp_binary": "...", # 可选,默认自动检测
"whisper_cpp_model": "...", # 可选,默认自动检测
"whisper_cpp_language": "zh", # 可选
"whisper_cpp_threads": 4 # 可选,默认自动检测
* docs: 在语音转录隐私章节补充 whisper.cpp 后端说明
根据 PR #78 review 反馈,在 README.md ⚠️ 语音转录隐私章节
新增 whisper.cpp 后端(macOS Metal GPU 加速)的配置说明、隐私
属性和回退行为,与 OpenAI 后端并列。
2026-05-12 11:42:53 +08:00
Belugary
49356e1692
feat: macOS 图片 AES key 从磁盘 kvcomm 缓存派生(解决 #23) ( #60 )
...
* feat: macOS 图片 AES key 从磁盘 kvcomm 缓存派生(issue #23)
macOS 用户长期无法用 C 版 find_image_key_macos 从微信进程内存提取
V2 图片密钥(issue #23 报告 197K 候选全部失败)。新增
find_image_key_macos.py 走完全不同的路径:从磁盘 kvcomm 缓存
文件名派生密钥,无需扫描内存、无需 root、无需重签名。
派生算法
--------
- 扫 ~/.../app_data/net/kvcomm/key_<code>_*.statistic 文件名
- 对每个 (code, wxid) 候选:
xor_key = code & 0xFF
aes_key = MD5(str(code) + cleaned_wxid).hex()[:16] # ASCII 字符串
- 用 V2 _t.dat 文件 [0xF:0x1F] 16 字节做 AES-128-ECB 模板验证:
解出来必须是图像 magic(JPEG / PNG / GIF / WebP / wxgf)
- 为防短 magic 偶然命中,要求多个不同模板都通过验证才算成功
- 命中后写回 config.json 的 image_aes_key / image_xor_key,
monitor_web.py 自动加载
致谢
----
派生算法源自 @hicccc77 在 issue #23 的评论;参考实现见其 WeFlow
项目 (CC BY-NC-SA 4.0)。本模块是独立的 Python clean-room 实现,
未复制其 TypeScript 源码;函数边界与变量命名沿用算法的自然结构
(regex 模式 / MD5 调用顺序 / magic 字节表等不可避免地相同)。
健壮性细节
----------
- 多候选 kvcomm 路径:枚举 5 个不同的 macOS 微信版本路径布局
- 多模板交叉验证:默认收集 3 个不同密文,全部通过才算命中
- 已有 image_aes_key 仍有效时短路返回,不重写 config
- 原子写 config.json:tmp + os.replace + finally 清理 .tmp
- 多 wxid 候选:同时试 raw 和归一化后的 wxid(A_Hare_626a → A_Hare)
- print(flush=True) 逐次显式(与 find_image_key.py 风格一致)
测试
----
新增 tests/test_find_image_key_macos.py,53 个测试覆盖:
派生算法 / wxid 归一化 / kvcomm 路径推算(含多候选)/ 模板收集
(去重 / 子目录 / max_files 边界)/ AES 验证(5 种 magic / 短输入
/ 空 key)/ 多模板交叉验证 / 端到端集成(命中 / 各种失败分支)/
原子写 / main 短路(已有有效 key 不重写 / 已有错 key 落到派生)。
全部通过:python -m unittest discover tests → 88/88。
兼容性
------
- 无新增依赖(pycryptodome 已在 requirements.txt)
- 不改任何现有 Python 文件,零回归风险
- 现有 Windows / Linux 路径 (find_image_key.py / find_image_key_monitor.py) 不受影响
* feat: macOS 图片 AES key 加方案2 fallback (issue #68 思路)
PR #60 的方案1 (kvcomm 缓存派生) 在 kvcomm 缺失 / 多账号歧义 / 首次
启动等场景下会失败。@H3CoF6 在 issue #68 提出关键洞察:
wxid 目录后 4 位 hex == md5(str(uin))[:4]
意味着不需要 kvcomm,可以从 wxid 目录名 + 任意 V2 .dat 反推 uin。
本 commit 在保留 PR #60 方案1 不变的前提下,加方案2 作为 dispatcher
fallback。
方案2 算法
----------
1. 从 db_dir 提 wxid 后 4 位 hex 作为 md5 前缀目标
2. 扫多个 V2 .dat 末字节投票反推 xor_key (假设 JPG EOI 0xD9,
默认至少 3 个样本投票)
3. 枚举 0~2^32 中 (uin & 0xff == xor_key) 的 2^24 个候选,
md5(str(uin))[:4] 匹配 wxid 后缀 → 得 ~256 个 uin 候选
4. 对每个候选算 aes_key, 用 PR #60 的 verify_aes_key_against_all
做 AES 模板交叉验证, 唯一定位 uin
实现
----
- find_image_key_macos 重构为 dispatcher: 先方案1 (kvcomm),
失败 fallback 方案2 (候选搜索); 模板收集移到 dispatcher 共享
- 新增 helper: extract_wxid_parts, derive_xor_key_from_v2_dat,
bruteforce_uin_candidates
- 模块顶部 docstring 加方案2 算法说明 + @H3CoF6 致谢
(保留 PR #60 对 @hicccc77 的方案1 致谢)
clean-room 声明
---------------
方案2 按 issue #68 的算法描述独立实现,未引用 @H3CoF6 任何代码。
方案1 仍沿用 PR #60 实现 (其 clean-room 声明对 @hicccc77 / WeFlow
保持不变)。
健壮性细节
----------
- xor_key 反推默认 min_samples=3, 样本不足直接放弃方案2 (避免
1-2 个样本时一旦撞到非 JPG 就 lock 错 xor_key)
- wxid 后缀正则收紧为 [0-9a-fA-F]{4} (md5 hex), 非 hex 后缀直接
返回 None 而非误导用户跑空候选搜索
- 投票分歧时打印 warning, 但仍试取多数 (兼容 attach 含少量非 JPG)
- 删除重构后未用的 import glob; Counter 统一在模块顶部 import
测试
----
新增 17 个测试 (53 → 70), 全部 7.4s 内通过:
- ExtractWxidPartsTests (5)
- DeriveXorKeyFromV2DatTests (7, 含新增 below_min_samples 边界)
- BruteforceUinCandidatesTests (1, 真跑全空间金标准验证)
- FindViaBruteforceTests (3)
- DispatcherFallbackTests (1, mock 加速)
顺手修复 2 个 pre-existing 测试 fail
------------------------------------
test_account_with_4char_alnum_suffix_stripped 与
test_returns_raw_and_normalized_when_different 用 6-char 后缀
your_wxid_a1b2c3, 但 normalize_wxid 只去 4-char 后缀 (匹配真实
macOS 路径) → 测试期望与代码不一致, 长期 fail。统一改用 4-char
后缀让测试与 macOS 现实对齐。
兼容性
------
- API 不变: find_image_key_macos(db_dir) 签名 / 返回值不变
- 现有 53 个测试全部仍通过 (含 happy path / 各种返回 None 分支 /
main 短路 / 原子写)
- 真实数据验证: 在本地 macOS 微信 4.x 上方案2 端到端跑通, 结果
与方案1 完全一致
* fix: replace test fixture with synthetic uin/wxid (privacy hardening)
PR #60 测试 fixture 与 docstring 示例之前用了真实 uin (8 位十进制)
作为 golden value,并在 docstring 里把 wxid 后缀作为示例展示。虽然
单独的 uin/suffix 不直接 unlock 任何资产 (需要配合真实 wxid + 物理
访问加密文件),但行业最佳实践 (yt-dlp / openssl / Linux kernel test
fixture) 都明确要求用合成确定性值, 不绑定任何真实账号。
合成方案
--------
- uin: 12345678 (8 位, 一目了然 placeholder)
- suffix: md5("12345678")[:4] = "25d5" (派生, self-consistent)
- wxid_full 示例: your_wxid_25d5
- wxid_norm 示例: your_wxid
- aes_key_test_value: a0c093edddc98490 = md5("12345678your_wxid")[:16]
- xor_key: 0x4E (= 12345678 & 0xFF)
改动范围
--------
- tests/test_find_image_key_macos.py: 全部 fixture 改用合成值,
bruteforce 测试的 xor 也对应更新 (0x7F → 0x4E)
- find_image_key_macos.py:260 docstring 示例: 真实 wxid 字符串
替换为 placeholder
- 长 kvcomm 缓存文件名 fixture 同步合成 (避免暴露真实时间戳 / 内部 ID)
测试
----
70/70 仍通过 (7.1s), 合成 fixture self-consistent。
非范围 (历史 commit b37d440 仍含真 uin fixture)
-----------------------------------------------
按行业惯例不 force push 重写 PR history (代价: PR 显得有问题; 收益:
真 uin alone 不构成 unlock — 需配真 wxid + 物理设备)。本 commit 保证
未来 review 看到的是干净版本; 历史 commit 保留以维护 review 链完整性。
* feat: 方案2 多进程加速 (~60x speedup, 借鉴 PR #69 )
吸收 @H3CoF6 在 PR #69 (https://github.com/ylytdeng/wechat-decrypt/pull/69 )
的 3 个加速优化, 让方案2 fallback 从单核 ~7s 降到多核 ~0.1-1s 量级。
加速优化
--------
1. 多进程: cpu_count 个 worker 并行扫 0~2^32 候选 (multiprocessing)
2. 二进制 md5 比较: digest()[:2] 替代 hexdigest()[:4], 省 hex 转换开销
3. 内联 AES 验证 + 早停: worker 内 md5 命中 → 直接 AES cross-validate →
推 queue → 主进程 terminate 其他 worker (任一进程命中即胜, 无两 pass)
与 PR #69 的差异
----------------
- 保留 PR #60 的多模板 AES 交叉验证 (PR #69 单模板; 本实现不退化防短
magic 偶然命中的能力)
- 集成在 dispatcher 的 fallback 路径 (PR #60 双方案架构), 而非 main()
自动跑
- 保留 bruteforce_uin_candidates 单进程版本作为算法金标准 (测试 +
parallel 不可用时的 fallback)
实现细节
--------
- 模块顶层 _bruteforce_worker_chunk + _aes_template_match (multiprocessing
pickle 要求 worker 必须是 module-level 函数)
- 60s timeout + daemon=True worker (主进程异常退出时 worker 不变僵尸)
- _bruteforce_with_aes_parallel 是新生产入口
性能
----
本地 macOS 实数据验证: 多核 (M2 16 workers) ~0.1s, 单核基线 ~7s = 60x
加速。合成 fixture 命中更早, 70 测试总时长 7.4s 不变 (单进程金标准
test_real_bruteforce_against_golden 仍单跑 ~7s)。
致谢
----
方案2 加速三连 (multiprocessing + 二进制 md5 + 早停 queue) 思路源自
@H3CoF6 在 PR #69 的实现 (find_all_keys.py)。本 commit 按其算法思路
独立实现 (worker 函数 / chunk 划分 / Queue 通信 / terminate 等技术
模式是 multiprocessing 的自然结构), 未引用其源码。
* test: clean dead bruteforce mocks + add direct parallel coverage
B refactor 让 _find_via_bruteforce 不再调 bruteforce_uin_candidates,
原 mock 变成空跑 dead code。同时 _bruteforce_with_aes_parallel 之前
没有针对性单测, 覆盖只来自集成路径。
清理
----
- FindViaBruteforceTests.test_full_flow_with_mocked_bruteforce →
test_full_flow_finds_synthetic_uin (移除 dead mock + 改名反映真实行为)
- DispatcherFallbackTests.test_kvcomm_missing_falls_back_to_bruteforce
移除 dead mock (HOME patch 仍保留, 强制方案1 失败走 fallback)
新增 BruteforceParallelTests (4 个测试)
--------------------------------------
- test_worker_finds_known_uin_in_chunk: 直调 worker, 验证算法核心
- test_worker_no_match_returns_silently: 区间不含命中 → queue 保持空
- test_worker_skips_when_aes_fails: md5 命中但 AES 验证失败不入队
(防止短 magic / 单 gate 假阳)
- test_parallel_workers_1_finds_synthetic_uin: workers=1 验证 spawn +
pickle + queue 跨进程通信链路
Worker 直调 (无 process spawn) 跑 ms 级。Workers=1 spawn 测试 ~1s。
全套 74 个测试 (此前 70 + 4 新) 跑 8.5s。
设计选择
--------
- 不 mock multiprocessing.Process / Queue (会变成测 mock 库自己, 不测算法)
- multiprocessing.Queue.put 通过 feeder thread 异步刷, get_nowait() 会 race;
用 q.get(timeout=...) 给 feeder 充足时间
- 多进程 e2e 由 FindViaBruteforceTests / DispatcherFallbackTests 间接覆盖
(cpu_count workers, 真实 fixture), 这里只测函数契约避免重复 spawn 开销
2026-05-05 17:04:11 +08:00
btc-z
66eddaff0e
feat: transcribe_voice 新增 OpenAI Whisper API 后端 ( #66 )
...
默认 local,零行为变化。opt-in 双因素:transcription_backend=openai
且 openai_api_key 都齐才生效;任一缺失静默回退 local + stderr 一行警告。
首次进入云路径会 stderr 警告"语音将上传至 OpenAI 服务器"。
新增 config.json 字段:
- transcription_backend: "local" (默认) | "openai"
- local_whisper_model: "base" (替换 mcp_server.py 里硬编码 DEFAULT_WHISPER_MODEL)
- openai_api_key: "" (默认空;openai 包为 optional,按需 pip install)
关键技术选择:
- _transcribe(wav, backend) 单一 if/else 分发,不引入插件/工厂层
(Rule of Three —— 只有一个云后端时不值得抽象)
- 文件 > 25MB 在 OpenAI() 实例化之前提前拒绝,避免无谓上传
- 错误分类清晰: 缺 key / 缺 openai 包 / 401 / 429 / APIError 各自的提示
- PR #58 缓存 schema 自然扩展: 条目加 backend 字段,命中需 backend+model_size 都匹配
- 旧条目缺 backend 字段视为 "local",向前兼容 PR #58 已落盘的所有数据
- transcribe_chat.py 批量 CLI 与 MCP 工具共享同一份配置,保持一致
新增 2 个测试 (tests/test_openai_backend.py),只覆盖回归风险最高的两条:
- 文件 > 25MB 必须在 SDK 实例化前拒绝(隐私契约的防线)
- backend 不匹配的旧条目不命中(避免切后端时返回错后端结果)
其余路径要么琐碎(默认值读取)、要么坏掉时声音很大(SDK 错误、ImportError),
要么已被 PR #58 现有测试隐式覆盖(缺 backend 字段的旧条目),不再单独写测试。
顺手把 README 里 PR #53 漏掉的 voice 三件套(get_voice_messages /
decode_voice / transcribe_voice)补进 MCP 工具表,并新增"⚠️ 语音转录隐私"
章节说清数据流向、成本(约 \$0.006/分钟)、25MB 上限、回退行为。
Closes ylytdeng/wechat-decrypt#59
2026-05-01 13:56:32 +08:00
ylytdeng
a8cf64c0a6
docs: 补充 README macOS 操作说明
...
- 环境要求和快速开始章节新增 macOS 小节
- 添加 macOS 版 config.json 示例
- 明确 codesign、编译、扫描、解密四步流程
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com >
2026-04-22 20:56:31 +08:00
ylytdeng
69a2f44240
feat: /api/history 支持按群过滤和增量拉取,更新 README API 文档
...
- /api/history 新增 chat、since、limit 参数
- README 新增 HTTP API 端点说明和联系人标签工具文档
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com >
2026-04-09 11:43:41 +08:00
joshua-deng
0821dc0e4e
Update README.md
...
加了一个tg群,防失联
2026-03-23 17:25:19 +08:00
joshua-deng
67244597f2
Merge pull request #28 from dsjzazs/feat/auto-install-deps
...
fix: 改为通过 requirements 安装依赖
2026-03-14 22:22:54 +08:00
dsjzazs
7c42ff5d38
Investigate get_chat_history limit
2026-03-14 16:59:17 +08:00
dsjzazs
2e03247fb9
Add MCP dependency and pin versions ( #1 )
2026-03-14 15:13:28 +08:00
dsjzazs
b623711410
Add MCP search unit tests
2026-03-14 14:07:51 +08:00
dsjzazs
4bda20f7aa
feat: 更新 README
2026-03-14 10:24:23 +08:00
dsjzazs
7e7f7a2516
feat: 增强消息查询功能,支持时间范围和分页
2026-03-14 10:21:21 +08:00
dsjzazs
8e8edc649c
fix: 改为通过 requirements 安装依赖
...
README 改为统一使用 requirements.txt 安装依赖,并补充 zstandard 依赖,避免手动漏装。
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-03-13 16:27:09 +08:00
PeanutSplash
bf77cc97d8
refactor(linux): improve wechat detection and sudo db path fallback
2026-03-07 21:35:24 +08:00
PeanutSplash
6d9b2c0fe4
refactor(find_all_keys): extract shared key scan logic
2026-03-07 21:35:24 +08:00
PeanutSplash
f9c338b48d
feat: add Linux support with cross-platform memory scanning
...
- Add Linux memory scanner (`find_all_keys_linux.py`) using `/proc/<pid>/mem`,
same approach as Windows/macOS — no GDB, no function offsets, no restart needed
- Extract Windows-specific code to `find_all_keys_windows.py`
- Make `find_all_keys.py` a platform dispatcher (Windows / Linux)
- Add `key_utils.py` for cross-platform path matching (`/` vs `\` in all_keys.json)
- Update `config.py` with Linux auto-detection of db_storage paths
- Update all consumers (decrypt_db, monitor, monitor_web, mcp_server) to use
`get_key_info()` for platform-agnostic key lookup
Tested on remote Linux container: 15/15 DBs scanned, decrypted, and verified.
2026-03-07 21:35:24 +08:00
bbingz
03582dd82c
fix: narrow Method 2 scan to hex charset [0-9a-f]
...
Previous range [a-z0-9] was too broad, matching non-hex characters
g-z which wastes CPU on false candidates. WeChat image keys are
lowercase hex strings.
2026-03-07 21:35:00 +08:00
bbingz
0576151b67
feat: add macOS image key scanner and batch decryptor (C)
...
- find_image_key.c: scans WeChat process memory for V2 image AES keys
using Mach VM API + CommonCrypto batch decryption
- decrypt_images.c: batch decrypts V2 .dat image files using keys
from image_keys.json, handles AES-ECB + XOR + raw_data segments
Build: cc -O3 -o find_image_key find_image_key.c -framework Security
cc -O3 -o decrypt_images decrypt_images.c -framework Security
2026-03-07 21:35:00 +08:00
joshua-deng
1294953681
Merge pull request #14 from bbingz/pr/macos-c-scanner
...
核心功能已验证,新增独立文件不影响现有功能。
2026-03-06 09:29:42 +08:00
bbingz
d38d7ebf9c
fix: replace glob() with nftw() and add chunk overlap
...
- glob() does not support ** recursive matching on macOS (POSIX).
Replace with nftw() + opendir to recursively walk db_storage/.
- Add overlap between memory chunks to catch x'...' patterns
spanning chunk boundaries.
2026-03-05 22:02:49 +08:00
bbingz
1f9ca3792a
feat: add macOS C memory key scanner
...
Scans WeChat process memory for SQLCipher encryption keys using
Mach VM API. Outputs all_keys.json compatible with decrypt_db.py.
Build: cc -O2 -o find_all_keys_macos find_all_keys_macos.c -framework Foundation
Usage: sudo ./find_all_keys_macos [pid]
2026-03-05 21:49:00 +08:00
PeanutSplash
6898a065d7
feat: add unified entry point and multi-process key extraction
...
Add main.py as single entry point that auto-detects config, extracts keys, and launches Web UI or decrypts databases in one command.
Refactor find_all_keys to scan all Weixin.exe processes instead of only the largest one, enabling multi=account support.
2026-03-03 22:20:12 +08:00
PeanutSplash
bf68409c39
docs: Updated configuration instructions to automatically detect the WeChat data directory and generate config.json.
2026-03-03 21:43:40 +08:00
ylytdeng
c85367ff08
feat: 富媒体内容解析、表情包显示、组合消息修复
...
- 表情包内联显示: emoticon.db CDN映射 + 下载缓存
- 富媒体内容: 链接卡片/文件/视频号/小程序/引用/位置等完整渲染
- 修复文字+图片组合消息丢失 (前端去重key加消息类型)
- 新增隐藏消息检测: 异步查message DB找回同秒内其他消息
- MonitorDBCache线程安全: per-key锁防并发解密损坏
- Web UI优化: 气泡样式/群聊发送者/图片点击放大
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com >
2026-03-03 11:55:11 +08:00
ylytdeng
24ae180669
Update README with image decryption docs and V2 format details
...
Add usage instructions for image key extraction, file descriptions
for new modules, and technical details of the three .dat encryption
formats (old XOR, V1, V2).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com >
2026-03-02 00:40:25 +08:00
ylytdeng
05b8ba4d45
Add MCP usage examples with redacted real outputs
2026-02-28 16:58:46 +08:00
joshua-deng
5057206222
Add MCP server for Claude AI integration
...
New mcp_server.py provides 5 tools (get_recent_sessions, get_chat_history,
search_messages, get_contacts, get_new_messages) via FastMCP stdio transport.
Features on-demand decryption with mtime-based caching and WAL support.
2026-02-28 12:22:50 +08:00
joshua-deng
4c91eb34ef
WeChat 4.0 database decryptor and real-time message monitor
...
Extract encryption keys from Weixin.exe process memory, decrypt all
SQLCipher 4 databases, and monitor new messages via Web UI with ~100ms latency.
2026-02-28 12:03:38 +08:00