Commit Graph

3 Commits

Author SHA1 Message Date
Belugary
87b0b419d6 fix(export_sns): _parse_timeline_xml 兼容 4 种 content 编码 + 老 XML 清洗 (#119)
朋友圈 XML 解析跨版本兼容 + 顺手堵 XXE 绕过.

1. SnsTimeLine.content 跨版本会以 4 种编码出现: bytes (zstd 压缩, magic 28 B5 2F FD) / plain XML / hex / base64. 老逻辑直接 ET.fromstring 喂 raw 入参, 后三种 ParseError → 整条 row 静默丢失, 不报错不警告.

2. 老朋友圈 (2013-2017) XML 还含 ElementTree 拒绝的字符: URL 里的裸 &, 文本字段手打的 < >, 控制字符 (\x00-\x08). 一样导致 ParseError → 静默丢 row.

3. 安全修复: XXE / 长度检查老逻辑跑在 raw 入参, zstd / hex / base64 编码的恶意 DOCTYPE 能绕过. 新逻辑跑在 decoded payload 上, 拦得住.

修复:
- _decode_sns_content_blob: 按 bytes / 已 XML / hex / base64 顺序检测, bytes 带 zstd magic 时先解压
- _sanitize_sns_pseudo_xml: 剥控制字符, CDATA 外裸 & 转义, text-only 节点内部裸 < > 转义
- _parse_timeline_xml: decode → 安全检查 (decoded payload) → sanitize → ET

测试: 17 case (DecodeContentBlobTests 10 + SanitizePseudoXmlTests 4 + SecurityAndLimitsTests 3), 全合成 XML 无 PII.
2026-05-23 18:13:27 +08:00
ylytdeng
e5e2269947 fix: PR #107 后续清理 (security/正确性/一致性)
针对 4 个 review agent 在 PR #107 (5649 行巨型 PR) 找到的关键问题做最小
侵入修复。已合并代码本身能跑,这次是收紧 security + 消重 + 文档一致性。

## 安全修复

### wxwork_keys.json 落盘权限 (find_wxwork_keys.py)
含明文 16-byte raw key 的 keys 文件,之前 default umask 落盘。改成:
  1. 写 tmp 文件
  2. chmod 0o600 (Unix 严格 owner-only; Windows 上 chmod 控制只读位,
     至少避免世界可读最差情况)
  3. atomic rename
旧产物自然过期,新生成的都受保护。

### SNS XXE 防护 (export_sns.py)
朋友圈 XML 来源是不可信输入(他人发的 content),原 `ET.fromstring()`
完全没过滤,可被恶意 entity expansion / 外部实体引用攻击。加跟
`mcp_server._XML_UNSAFE_RE` 同模式的过滤(拒 `<!DOCTYPE>` / `<!ENTITY>`)
+ 200KB 大小上限。`_parse_timeline_xml` 检查后才进 ET.fromstring。

## 正确性 / 消重

### AES 对齐公式统一 (decode_image.py + decrypt_sns.py + export_sns.py)
原本三处各写一份:
  - decode_image.py:   aes_size -= ~(~aes_size % 16)   ← bitwise trick
  - decrypt_sns.py:    同上
  - export_sns.py:     aes_size + (16 - aes_size%16) if … else aes_size+16
两个公式数学等价(对 0/1/15/16/17/100/1000/12345 全部验证一致),但
bitwise trick 难读且漂移风险高。抽 `aligned_aes_block_size()` 到
decode_image.py 作 canonical 实现, 另两处 import 复用。

### 32-bit pointer 假设明确化 (find_wxwork_keys.py)
reviewer 担心 `_read_u32` 在 64-bit 进程上错位,实测 WXWork.exe 5.0.x
是 **32-bit 进程** (`Program Files (x86)\WXWork\` + PE Machine = x86),
所以 4 字节读指针是对的。加注释明确这个假设,腾讯如果升级到 64-bit
要重做整套逆向, 当前实测全部 17 db 解密通过印证。

## 一致性

### main.py show_status() 走 _config_file_path() (main.py)
原硬编码 `config_file = "config.json"` 绕开 PR #107 新引入的
`_config_file_path()`,打包成 exe 后 cwd 不一定是 exe 目录,会读到错
位置。改成 `from config import _config_file_path`。

### EXE_USAGE.md 输出目录写错 (EXE_USAGE.md)
EXE_USAGE 说导出到 `export/`,代码实际 `output_base_dir = wechat_files/
<wxid>/`,联系人下还是 `messages.csv/html/json` 而不是
`message_0.db.csv`。修正成真实结构。

## 文档

README 加两段:
  - 安全提示: keys 文件 chmod 0600 + 不要 commit 到 git
  - 朋友圈 XML XXE 防护说明

## 测试

185/185 通过 (含已有 wxsqlite3 roundtrip + image v2 + msg types filter
+ pagination hint + chat export helpers 等)。
aligned_aes_block_size 单独验证跟旧公式等价(0/1/15/16/17/100/1000/12345)。

## 未跟进 (后续 follow-up issue)

- 3 处 V1/V2/XOR 解密代码完全重复(decode_image / decrypt_sns /
  export_messages 各自实现)——抽出来工作量大,本次先抽 helper 不动
  完整解密路径,后续单独 PR
- export_messages HTML base64 内联图片可能爆几 GB,应改成可选 flag
- SNS / wxwork export / batch_decrypt_images / voice_to_mp3 测试缺位
  (0 个 test)
2026-05-17 17:00:20 +08:00
xincheng
b9f3161f84 Add SNS/image export and GUI contact export
Introduce SNS (朋友圈) and batch image tooling and enhance the GUI export workflow. Added new scripts: decrypt_sns.py (decrypt WeChat SNS cache) and batch_decrypt_images.py (bulk .dat image decrypt). Update build scripts and PyInstaller spec to include the new files. app_gui.py: add contact discovery, contact selection/export options dialog, new buttons (find image key, SNS), orchestrate combined export/voice/SNS tasks via subprocesses and env flags, and auto-run export after decryption. config.py: add output_base_dir, auto-detect WeChat Files path, and expose msgattach/xwechat cache dirs. export_messages.py: switch to output_base_dir, add image resource lookup and .dat locating/decryption helpers, and support environment-driven contact/format/image filters. Misc: update build.bat and packaging datas to include the new modules.

Co-Authored-By: Copilot <198982749+Copilot@users.noreply.github.com>
2026-04-06 23:57:51 +08:00