QQ CLI — QQ 聊天记录读取与分析
本技能通过 qq-cli 命令行工具,帮助用户读取和分析本地 QQ(新版 QQNT 架构)的聊天记录、好友资料、群聊等数据。支持数据库解密、会话浏览、消息搜索、聊天记录导出、统计分析等功能。纯 Python 实现,无需编译依赖。
核心能力:自动提取数据库密钥(调试器断点方案,默认请用户协助搜索一次,全程保证 QQ 不被退出)、自动定位数据目录、解密后自动完整性校验与修复(WAL 热复制损坏)、读取会话/消息/导出/统计。
> v1.3.0 安全更新(重要):修复了「提取密钥过程中 QQ 被退出」的根因——PS1 调试循环在断点命中后未继续挂起线程就分离调试器,导致 DebugActiveProcessStop 永久等待、调试器进程被强杀时 Windows 连带终止 QQ。现在:① 断点命中后必先继续线程再分离;② 超时/退出前自动恢复所有单步线程;③ 提取过程中持续监控 QQ 存活;④ 任何情况下都不再强杀调试器进程;⑤ 默认改用「请用户协助搜索」(--trigger manual),不再自动模拟 UI 抢焦点,对 QQ 零干扰。
适用场景
- 查看最近私聊 / 群聊会话列表
- 查看指定好友或群聊的聊天记录
- 按关键词搜索历史消息
- 导出聊天记录为 Markdown / TXT / JSON
- 聊天统计分析(消息总数、发出/收到比例、时间范围)
- 查询好友昵称 / 备注 / QQ 号
- 对聊天记录进行分类总结、重点提取等分析任务
前置条件
系统支持
- Windows(QQNT 9.x 新版架构,进程名
QQ.exe)
> QQNT 是腾讯 2023 年起推行的新版 QQ 架构(Windows 9.9+),聊天记录存储在 SQLCipher 加密的 SQLite 数据库中。旧版 QQ 8.x 不支持。
必须满足
- QQ 客户端已安装并登录过 — 工具读取本地 QQ 数据库,数据库文件随登录生成
- 初始化(提取密钥)时 QQ 必须正在运行并已登录 — 密钥通过附加调试器到 QQ 进程提取(全程不会中断/退出 QQ)
- 提取密钥时可能需要您协助一次 — 默认模式(
--trigger manual)会提示您在 QQ 搜索框输入任意字符以触发断点(仅需一次,约 1 秒),详见下方「初始化」章节 - Python 3.10+ — 需要
pycryptodome依赖(见下方安装)
数据库位置参考
QQNT 聊天数据库位于用户数据目录(init / doctor 会自动探测,也可用 --db-dir 手动指定):
| 库文件 | 内容 |
|---|---|
nt_msg.db |
私聊 / 群聊消息(核心库) |
profile_info.db |
好友资料(昵称 / 备注 / QQ 号) |
group_info.db |
群资料(群号 / 群名) |
group_msg_fts.db |
全文搜索索引(可选) |
典型路径(Windows):
%APPDATA%\Tencent\QQ\nt_qq\<nt_uid>\nt_data\nt_msg.db
%USERPROFILE%\Documents\Tencent Files\<QQ>\nt_qq\nt_db\nt_msg.db
安装
本 skill 自带脚本(scripts/ 目录),无需安装全局命令,直接用 Python 运行即可。
依赖安装
# 推荐使用隔离的 Python 虚拟环境
python -m venv C:/Users/Administrator/.workbuddy/binaries/python/envs/default
C:/Users/Administrator/.workbuddy/binaries/python/envs/default/Scripts/pip install -r scripts/requirements.txt
依赖:pycryptodome>=3.20(AES / PBKDF2 加密原语)
> 本机已就绪:C:/Users/Administrator/.workbuddy/binaries/python/envs/default/Scripts/python.exe
验证安装
python scripts/qq_cli.py --help
python scripts/test_qq_cli.py # 运行自洽测试(加密→解密→解析全链路)
快速开始(推荐路径)
# 0. 打开 QQ 并登录(必须)
# 1. 一键初始化:自动定位数据目录 + 自动提取密钥
# (若 QQ 未重新登录、已有配置仍有效,会直接复用,秒级完成)
python scripts/qq_cli.py init
# 2. 查看最近会话
python scripts/qq_cli.py sessions --format text
# 3. 查看与某人的聊天记录(支持昵称/备注/QQ号)
python scripts/qq_cli.py history 356924915 --limit 30 --format text
# 4. 导出聊天记录(Markdown)
python scripts/qq_cli.py export 356924915 --format md --output chat.md
# 5. 环境诊断(任何异常先跑这个)
python scripts/qq_cli.py doctor
初始化(提取密钥)
初始化会提取 QQ 数据库的加密密钥并生成配置文件(~/.qq-cli/config.json)。通常只需执行一次;QQ 重新登录后密钥更换,才需要重新提取。
一键初始化
python scripts/qq_cli.py init
init 自动按以下顺序尝试,默认全自动,仅提取密钥时可能需要您协助搜索一次:
- 复用已有配置(推荐路径):若
~/.qq-cli/config.json中的密钥仍有效(QQ 未重新登录),直接跳过提取,秒级完成 - 调试器断点方案(唯一提取方案,实战验证最可靠):附加调试器到运行中的 QQ → 在数据库打开函数设断点 → 触发断点 → 自动提取密钥。QQ 全程不会被退出:
- 断点触发方式(--trigger,v1.3.0 起默认manual):manual(默认,推荐):脚本打印醒目提示,请您在 QQ 搜索框输入任意字符(如字母a)触发断点。不模拟 UI、不抢焦点、不干扰 QQ,最安全可靠。auto:自动模拟点击 QQ 搜索框并输入(需脚本与 QQ 在同一桌面会话,否则按键无法送达;可能短暂抢占焦点)。none:静默等待断点自然触发(适合已知要主动搜索的场景)。- 内置常见版本函数地址缓存(如
9.9.7-21484),命中则跳过静态分析,秒级附加 - 新版本首次使用会做一次静态分析(约 1~3 分钟),之后可把 RVA 加入缓存
- PS1(
tools/windows_ntqq_get_key.ps1)支持-TimeoutSec参数,到点自动恢复断点字节、继续所有挂起线程并同步分离调试器 - 任何情况下都不强杀调试器进程(强杀会导致 Windows 连带终止 QQ);提取期间持续监控 QQ 存活
> v1.4.0 变更(重要):密钥提取仅采用调试器断点方案,不再尝试内存快速扫描(内存扫描对 QQNT 9.x 新版本低成功率且耗时)。_auto_extract_key 直接调用 qq_key_debug.interactive_extract。若遇到「未检测到运行中的 QQ」,请确认 QQ 客户端已打开并登录目标账号后再运行 init / key。
> 多账号提醒(重要):同一台电脑可能登录多个 QQ 账号,每个账号有独立的数据目录和独立的数据库密钥。init 未指定 --db-dir 时会列出所有账号目录并默认选择最近更新的;若目标账号不是最近登录的,请显式指定:
> bash
> python scripts/qq_cli.py init --db-dir "C:\Users\...\Tencent Files\<QQ号>\nt_qq\nt_db"
>
> 切换账号后旧密钥对新账号无效(会提示"账号切换"并重新提取),提取前请确认 QQ 已登录该目标账号。
> QQ 安全保证(v1.3.0,重要):历史版本存在「提取密钥后 QQ 被退出」的缺陷——调试循环在断点命中后直接跳出,未对命中断点的线程调用 ContinueDebugEvent,导致线程保持挂起、DebugActiveProcessStop 分离调试器时永久阻塞;外部超时强杀调试器进程时,Windows 将已调试的 QQ 一并终止。v1.3.0 已修复:① 断点命中后必先继续当前线程再退出循环;② 超时/退出前自动恢复所有单步线程;③ Python 侧不再 terminate() 调试器进程,改为等待其安全退出 + 监控 QQ 存活。现在提取密钥不会导致 QQ 退出;万一 QQ 仍异常退出(如 QQ 自身崩溃、反调试保护),重启 QQ 重新登录即可,已写入配置的密钥不受影响。
> 为什么需要触发搜索? 已登录的 QQ 不会自动重新打开数据库,nt_sqlite3_key_v2 函数不会触发。用户在 QQ 里搜索(或程序模拟搜索)会让 QQ 重新访问 FTS 索引数据库,断点随之命中。脚本默认等待最多 300 秒(--timeout 可调),并周期性提醒/重试。
手动指定
# 手动指定密钥(如从其他渠道获得)
python scripts/qq_cli.py init --key "16字节密钥"
# 手动指定数据目录
python scripts/qq_cli.py init --db-dir "C:\path\to\nt_data"
# 强制重新提取(QQ 重新登录后密钥失效时)
python scripts/qq_cli.py init --force
单独提取密钥
# 只提取密钥不写配置(默认 manual 模式:会提示您到 QQ 搜索框搜索一次)
python scripts/qq_cli.py key
# 自定义超时(默认 300 秒)
python scripts/qq_cli.py key --timeout 120
# 指定断点触发方式(v1.3.0+)
python scripts/qq_cli.py key --trigger manual # 请用户协助搜索(默认,最安全)
python scripts/qq_cli.py key --trigger auto # UI 自动触发(需与 QQ 同一桌面会话)
python scripts/qq_cli.py key --trigger none # 静默等待(用户自行搜索)
配置文件说明
初始化后配置保存在 ~/.qq-cli/ 目录:
| 文件/目录 | 说明 |
|---|---|
config.json |
主配置,记录 key(密钥)与 db_dir(数据目录) |
cache/ |
解密后的明文数据库缓存(按源文件 mtime 自动失效,解密后自动完整性校验+修复) |
> 安全提示:config.json 含数据库密钥明文,请勿分享该文件。
命令总览
| 命令 | 说明 | 常用参数 |
|---|---|---|
init |
初始化(自动提取密钥 + 定位数据目录) | --key, --db-dir, --force |
key |
单独提取密钥(调试器断点方案,需 QQ 运行并配合搜索) | --timeout, --trigger |
doctor |
环境诊断(进程/wrapper/目录/密钥/库完整性) | — |
repair |
修复损坏的数据库(VACUUM + 重建索引) | [db] |
decrypt |
解密指定数据库文件 | --key, --output |
sessions |
最近会话列表(私聊 + 群聊) | --limit, --format |
history |
指定会话的聊天记录 | --limit, --offset, --start-time, --end-time, --type |
search |
按关键词搜索消息 | --chat, --start-time, --end-time, --limit |
contacts |
好友 / 联系人列表 | --query, --limit |
groups |
群列表 | --query, --limit |
export |
导出聊天记录(MD/TXT/JSON) | --format, --output, --start-time, --end-time, --limit |
stats |
聊天统计 | [chat], --format |
> 完整命令参数与输出示例详见 references/commands.md
输出格式
大多数命令支持 --format 参数:
- json(默认)— 结构化 JSON,适合程序处理
- text — 简化文本,适合人类阅读
时间过滤格式:YYYY-MM-DD 或 YYYY-MM-DD HH:MM:SS
消息内容类型:文本 / 图片 / 语音 / 视频 / 文件 / 表情 / 回复 / 转发 / 位置 / 应用 / 系统 / 群通知 / 通话 / 动态
重要注意事项
- 默认限制:
history默认 50 条,search默认 500 条,sessions默认 20 个。导出大量数据用--limit 100000 - 密钥时效性:QQ 每次重新登录都会更换数据库密钥,旧的
config.json会失效,需重新init --force - 多账号密钥独立:同一电脑每个 QQ 账号有独立数据库密钥。
config.json只记录一个账号的密钥;切换账号(--db-dir指向其他账号目录)后旧密钥失效,需确认 QQ 已登录目标账号后重新提取。init未指定目录时会列出所有账号并默认选最近更新的 - QQ 不会被退出(v1.3.0):提取密钥全程不中断 QQ。默认
--trigger manual(请用户协助搜索一次),不模拟 UI、不抢焦点;断点命中后必先继续线程再分离调试器;任何情况下不强杀调试器进程;提取期间持续监控 QQ 存活。若 QQ 仍异常退出(自身崩溃/反调试保护),重启 QQ 重新登录即可,已写入配置的密钥不丢失 - auto 触发模式的环境要求:
--trigger auto必须运行在与 QQ 同一个桌面会话的进程中。Git Bash 沙箱或 service session 进程由于 Session 隔离,模拟输入无法抵达用户桌面的 QQ 窗口;此时请改用默认的manual模式,由用户手动搜索一次 - QQ 版本兼容:数据库表结构 / protobuf 字段在不同 QQ 版本间可能有差异。QQNT 9.9.7-21484 实测搜索按钮在聊天列表底部(窗口内部坐标约
x=175, y=575),其他版本若布局变化,auto 模式可能失效,改用 manual 模式由用户手动搜索即可 - 解密后数据库的布局:解密输出头部保留区标记为 48 字节(与 SQLCipher 规范一致)。QQ 原生数据库本就按此布局存储,解密后可直接被标准 sqlite3 读取;但用普通 sqlite3 手工创建的库(保留区为 0)加密后再解密会因页尾数据丢失而无法读取,属预期行为,不影响真实 QQ 库
- 自动防损坏:QQ 运行时复制数据库可能产生页撕裂,本工具在解密后自动做完整性检查,损坏则自动
VACUUM INTO+ 重建索引修复,无需人工干预 - 隐私安全:所有数据仅在本地处理,不会上传任何信息
- 数据只读:查询操作不会修改原始数据库
- 首次 init 一次性成本:只要 QQ 不重新登录(密钥不变),后续所有
sessions/history/contacts/search/export都从~/.qq-cli/config.json复用密钥,完全无需调试器和 UI 操作——"全自动"的实际形态就是 init 一次后持续复用
技术原理(简述)
QQNT 的 nt_msg.db 等数据库使用 SQLCipher 4 加密:
- 文件头部有 1024 字节 QQ 自定义头,解密前需剥离
- 加密参数:cipher_page_size=4096、kdf_iter=4000、HMAC_SHA1、PBKDF2_HMAC_SHA512、AES-256-CBC
- 每页 4096 字节,尾部 48 字节保留区存放 IV(16) + HMAC-SHA1(20) + 填充(12)
- 密钥派生:enc_key = PBKDF2(passphrase, salt, 4000),mac_key = PBKDF2(enc_key, salt⊕0x3A, 2)
- 消息内容列 40800 为 protobuf 编码,工具内置轻量 wire 解析器
密钥提取(调试器断点方案):附加调试器到 QQ 主进程,在 wrapper.node 的 nt_sqlite3_key_v2 函数入口设断点;QQ 打开数据库时命中,R8 寄存器指向 16 字节密钥字符串。断点触发由用户协助(--trigger manual,推荐)或 UI 自动模拟(--trigger auto)完成。实现见 tools/windows_ntqq_get_key.ps1(支持 -AttachPid 附加模式与 -KeyOutFile 直写密钥文件)。v1.3.0 起全程保证 QQ 不被退出:断点命中后先继续挂起线程再分离调试器、超时自动恢复所有单步线程、任何情况不强杀调试器进程、持续监控 QQ 存活。
分析工作流
当用户需要分析聊天记录时,推荐工作流详见 references/analysis-guide.md。
典型流程:
1. sessions — 浏览会话列表,确定分析对象
2. history — 读取目标聊天的消息记录
3. 对消息内容进行分类、总结、提取重点
4. 用 stats 获取统计数据辅助深度分析
5. 用 export 导出完整记录
故障排查
常见问题及解决方案详见 references/troubleshooting.md(含实战中验证过的关键场景:断点不触发、WAL 损坏、附加失败、密钥失效等)。任何异常先运行:
python scripts/qq_cli.py doctor
参考文档
- 完整命令参考
- 消息分析工作流指南
- 常见问题排查