QQ本地缓存机制初步探寻
起因是在电脑上我想将一个QQ文件存放到其他文件夹下而在QQ缓存文件夹下(...\Tencent Files\电脑登录的qq号\nt_qq\nt_data\右键选择打开文件夹就可以快速找到对应文件的存放位置)对一个视频文件进行了重命名在QQ中想要再预览同一个视频的时候发现又需要重新下载即下图中最左与最右的视频是相同的。所以我又重命名了一遍是的相当于再次预览后有了3个相同的视频可以看到同一个视频在qq缓存时始终拥有一个固定的命名。而这个文件名07274e2fe9990417a1f599611cd36025而这个命名是怎么产生的呢在windows的cmd中输入以下指令测试是不是MD5方式产生的certutil -hashfile D:\...\nt_qq\nt_data\Video\2026-06\Ori\07274e2fe9990417a1f599611cd36025.mp4 MD5得到的值是05fce820355ed39a43e61ffbef3d7f40不匹配。所以让AI去尝试其他常见的哈希方式结果都不匹配测试项目计算结果是否匹配文件名文件内容 MD505fce820355ed39a43e61ffbef3d7f40❌文件内容 SHA151e24aa6f6e6e5c6ac533e03694edc8865be302b❌文件内容 SHA256bdc4cd025276a4407b6d78223e4d0ab812e3b5ee...❌文件内容 CRC329513aeda❌文件前 1KB / 1MB / 末尾 N 字节 MD5多种结果❌文件路径 / 文件名 / 文件大小 的 MD5多种结果❌嵌套哈希 (MD5 of MD5 等)多种结果❌标准 UUID (v1/v4)version 位为0不符合标准❌说明很有可能QQ不是在本地根据视频内容进行的计算因为哈希会出现重复的情况而可能是对原始下载 URL 进行哈希得到的或者是QQ 服务器直接下发的 file_id / file_uuid。不过事实并非如此。查看缓存目录以一个视频为例nt_qq/nt_data/Video/2026-06/Ori/07274e2fe9990417a1f599611cd36025.mp4 nt_qq/nt_data/Video/2026-06/Thumb/07274e2fe9990417a1f599611cd36025_0.png可以看到视频和缩略图共享同一个 ID说明这是 QQ NT 的标准缓存结构。接着对同一缓存目录下的其他十六进制命名视频做 MD5 校验发现并非所有文件都不匹配文件名内容 MD5是否匹配7a4e67066cff62b0d634bb195c4c1b7a.mp47a4e67066cff62b0d634bb195c4c1b7a✅匹配35162df365e45b0b63b604db88540752.mp435162df365e45b0b63b604db88540752✅匹配c34a6824666446818ff0e6524b08b239.mp4577353b33ca4db9bc0f86d0df9f97278❌ 不匹配fb48745972b2bb0f795f7d2382172996.mp45329bf3eeea08efeac87d66ed659965a❌ 不匹配所以推测某些视频可能是本地直发文件使用内容 MD5 命名另一些视频在发送或者缓存过程中进行了压缩导致前后的MD5发生了变化。在nt_qq/nt_db/下找到所有数据库文件包括nt_msg.db、rich_media.db、files_in_chat.db、group_info.db ...尝试用sqlite3直接打开全部报错Error: file is not a database。用 Python 读取文件头确认Header: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 ASCII: SQLite format 3表面是标准 SQLite 头但后续页面是密文——确认是 SQLCipher 4 加密且 QQ NT 在标准头前额外加了 1024 字节自定义头部。1008-1023: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 (16 字节全零) 1024-1039: 5f d9 ca 34 61 b4 8d 82 3f 69 8c 59 f4 8a 33 40 (加密数据开始)既然数据库加密必须获取密钥。由于无法下载到现成的 PowerShell 脚本自行编写了find_key_from_memory.py枚举所有QQ.exe进程 PID用 Windows API (OpenProcess→VirtualQueryEx→ReadProcessMemory) 遍历内存在内存中搜索nt_msg.db和 对应的QQ 号 作为线索在线索附近提取 16 字节可打印 ASCII 字符串作为候选密钥对每个候选密钥尝试连接剥离头部后的数据库并执行SELECT count(*) FROM sqlite_master;扫描结果扫描 7 个 QQ 进程共 3.8 GB 内存收集到 40,001 个候选密钥验证到第 1,500 个左右时命中成功提取密钥接着按剥离 1024 字节头部 → 生成 → 逐表导出 → 生成明文数据库 的过程进行在c2c_msg_table和group_msg_table的40800列Protobuf BLOB中搜索字节串b07274e2fe9990417a1f599611cd36025。在c2c_msg_table中找到1 条匹配记录group_msg_table中未找到。$07274e2fe9990417a1f599611cd36025.mp4 $07274E2FE9990417A1F599611CD36025.png fEhRag8Q-jb6FPILieEkWWDWf-8xdUxic2Y4dIIULKJGAuq6X-ZQDMgRwcm9kUID1JFoQDn4OJuj0FqmYXaS4jYYW3XoCsK2CAQJuag dEhQ4k-yIPDEk7SC5169Krv88fxHQLRjNhgMghgso7-O8rpf5lAMyBHByb2RQgPUkWhAlwP3hH60xpVJhi9ABSKO-egLrWYIBAm5q是 Protobuf 二进制需要解析才能读出结构化字段。将Protobuf 解析为结构化 JSON在messages表中搜索目标字符串得到如下结果{ type: video, filename: 07274e2fe9990417a1f599611cd36025.mp4, filesize: 61058204, md5_hex: 07274e2fe9990417a1f599611cd36025, duration: 49997, cdn_url: null, local_path: null }结合本地文件比对大小即可得到维度消息记录中的原始文件本地缓存文件md5_hex07274e2fe9990417a1f599611cd36025—filesize61,058,204 bytes (58.2 MB)51,226,940 bytes (48.8 MB)内容 MD5—05fce820355ed39a43e61ffbef3d7f40文件名07274e2fe9990417a1f599611cd36025.mp407274e2fe9990417a1f599611cd36025.mp4说明文件名是发送方原始视频文件的 MD5。QQ 用这个 MD5 作为本地缓存文件名。但 在本地存储时对视频进行了压缩/转码导致文件变小、内容 MD5 改变因此本地的.mp4文件内容 MD5 与文件名不一致。之所以改名后会重新下载是因为和浏览器缓存类似QQ 识别本地文件是否已存在通常靠的是文件路径和文件名而不是文件内容的 MD5 哈希值。文件名一变索引就失效了。虽然视频内容完全没变MD5 值相同但 QQ 并不会在打开前先做完整的内容校验。它只查之前有没有下载过这个名称的文件查不到就重新拉取。参考资料https://qqbackup.github.io/QQDecrypt/

相关新闻