ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

微信聊天记录解析:SQLite与SQLCipher解密导出备份指南

微信聊天记录解析:SQLite与SQLCipher解密导出备份指南 简介面向需要管理个人微信数据的用户这份资源提供了一套完整的微信数据库解析工具覆盖聊天记录提取、联系人导出、群组信息获取、数据库解密、内容备份与恢复、数据挖掘等核心功能同时也支持PC端与手机端微信数据的同步管理。压缩包共63个文件整体仅187KB以Kotlin源码、XML配置、PNG界面截图和Gradle构建脚本为主Kotlin源码实现核心解析逻辑XML负责配置与界面PNG用于展示操作界面与效果Gradle脚本管理整个工程构建另外还包含JAR库、TXT/DOCX/MD格式的使用说明与辅助文档目录结构清晰便于快速定位相关代码和资料。目前已有235人学习浏览适合需要批量管理微信数据的进阶用户。资源附赠详细的说明文件和操作文档从环境配置、工程构建到数据库解析步骤均有指引并提供数据备份、隐私保护以及误删恢复方面的实用思路完整工程源码可帮助Android开发者深入理解微信数据库结构与解密技术也能作为个人数据管理和日常备份的分析助手。1. 微信数据库解析把散落在 SQLite 里的聊天记录变成可备份的个人资产换了新电脑微信登录后聊天记录全没同步过来才发现这几年和客户、家人的往来记录都锁在本地数据库里。这正是微信数据库解析工具包要解决的问题它面向 PC 端和手机端的微信本地数据提供解密、提取、导出完整流程把 MicroMsg.db、MSG.db 这类 SQLCipher 加密的 SQLite 库还原成可读的 CSV/HTML 报告。适合两类人想迁移微信数据的普通用户以及需要把聊天记录当作分析素材的开发者。但要先立一个边界——只能处理本人设备已授权范围内的数据这一点后面每个环节都要守住。2. 存储结构先摸清SQLite 外壳、SQLCipher 内胆与 PC/手机端数据差异2.1 为什么微信选 SQLite单文件数据库在桌面端的取舍微信把聊天记录放在本地不是云端。所有联系人、群组、消息都存在本地数据库文件里。SQLite 是单文件嵌入式数据库手机端和桌面端都适用不用单独装数据库服务数据读写在应用进程内完成。腾讯选择 SQLite 是常规操作但聊天数据敏感直接明文存肯定不行所以微信在 SQLite 之上套了一层 SQLCipher 加密。SQLCipher 是 SQLite 的加密扩展对数据库文件做 256 位 AES 加密库文件头不再是标准 SQLite 格式。用普通 sqlite3 工具打开会直接报file is not a database必须先拿到密钥再用 SQLCipher 兼容的方式连接。这一步是整条解析链的闸门。判断一个库是否加密最快的方法是用十六进制查看文件头xxd MSG.db | head -n 2 # 加密库开头看不到 SQLite format 3 字样前 16 字节是无规律的随机盐值如果开头能看到SQLite format 3\0说明这个库没加密直接跳过解密环节。实际使用中微信的库基本都是加密的能看到明文头的概率很低。2.2 PC 端库文件清单MicroMsg.db、MSG.db、MediaMSG.db 各管什么PC 端微信的数据目录通常在C:\Users\用户名\Documents\WeChat Files\微信号\下按用途拆成多个库。每个库都是 SQLCipher 加密的 SQLite 文件密钥相同所以只要拿到一套 key就能逐个打开。常用库文件清单如下文件职责备注MicroMsg.db联系人、群列表、公众号、标签信息核心元数据MSG.db / MSG0.db / MSG1.db聊天消息流水数据量大会拆成多个分库MediaMSG.db图片、视频、文件的消息索引实际媒体文件在 cache 目录OpenIM.db企业微信会话相关部分版本才有PublicMsg.db公众号消息旧版本可见拆库逻辑值得留意当单库超过一定大小微信会把历史消息挪到 MSG0.db、MSG1.db 这样的分库中。导出时只查 MSG.db 会丢数据必须先列出所有库文件再逐个执行同样的查询最后按消息 ID 去重合并。很多导出工具「缺消息」的反馈根因就是分库没遍历全。我一般会先dir /b *.db看一眼有几个库文件再决定查询脚本要不要走循环。2.3 手机端 EnMicroMsg.db 与 PC 端存储的差异Android 端微信的聊天主库是/data/data/com.tencent.mm/MicroMsg/md5目录/EnMicroMsg.db。手机端表结构和 PC 端差异很大联系人表叫rcontact消息索引靠talker字段区分会话消息内容存在独立的message表里字段命名和 PC 端的 MSG 表完全不是一套体系。PC 端没有手机端那么复杂的目录散列主要是微信登录后按账号统一拉取数据。多端同步带来的一个现实问题是PC 端能看到的历史消息有一部分是从手机端同步过来的但 PC 本地库不一定包含手机端的全部记录。尤其是手机端删除过、PC 端未同步的会话两边数据天然不一致。做「微信PC端与手机端数据同步」式归档时要以本地库实际内容为准不要假设 PC 端一定比手机端全。这个认知直接影响后面解密模块的选型——手机端库和 PC 端库的解密路径完全不同先确认数据来源再选对应模块。3. 解密实操Key 提取路径与 SQLCipher 连接参数的四个关键值3.1 PC 端 Key 的提取路径确认版本后再动手微信不同版本对本地存储的管理策略不一样。3.x 时代key 可以从本地配置目录中提取有些版本以 32 字节随机值存在特定配置文件中有些则在微信进程启动后从内存里读出。4.x 重构之后key 的保存位置和管理逻辑都有调整旧方法拿到的字节直接拼进 SQLCipher 往往打不开。常见做法是用工具包里自带的 key 提取脚本跑一遍它会自动探测微信版本并输出 hex 格式的 key。手工翻配置文件时有一个关键点不能把整个文件当 key 用要先看字节长度。SQLCipher 的 raw key 常见的长度是 32 字节256 位微信的库绝大多数用这个规格如果文件长度大于 32 字节需要按偏移截取具体偏移以工具输出为准。我一般会用十六进制编辑器看一眼 key 文件很多版本在文件尾部的 32 字节才是真正的 key前面全是无关配置。版本探测不能跳过打开微信「关于」页看版本号或者在数据目录下看文件结构。3.x 的目录下有wxid_开头的文件夹且内部是 msg、db 平铺结构4.x 会多出一些新目录和缓存文件。工具包里的 key 提取脚本会根据目录结构自动切换方案手动操作时先确认版本再选模块能省掉大半调试时间。3.2 SQLCipher 连接参数page_size、kdf_iter、cipher_page_size 别乱动解密成功的关键不只是 key 正确还有一组参数必须和加密时保持一致。很多人把 key 填进去跑不通问题不在 key而在参数。SQLCipher 的密钥派生和加密布局受下面几个参数控制参数常见值说明cipheraes-256-cbcSQLCipher 默认加密算法kdf_iter256000SQLCipher 4.x/ 640003.x密钥派生迭代次数cipher_page_size4096与 SQLite 的 page_size 一致hmac_algorithmHMAC-SHA1旧版本常用新版本可能不同plaintext_header_size0无明文头时默认参数不对即使 key 正确也会报「file is not a database」或者查出来全是乱码。微信 3.x 时代多对应 SQLCipher 3 的 64000 次迭代4.x 之后对应 SQLCipher 4 的 256000 次。用 Python 连接时显式声明参数别依赖库的默认值import sqlcipher3 as sqlite3 conn sqlite3.connect(MSG.db) # 以 hex 字面量传入 key避免字符串编码问题 conn.execute(PRAGMA key \xkey_hex\) # SQLCipher 4.x 必须显式指定迭代次数 conn.execute(PRAGMA kdf_iter 256000) # 页面大小必须与加密时一致 conn.execute(PRAGMA cipher_page_size 4096) conn.execute(PRAGMA cipher_hmac_algorithm HMAC_SHA1) cur conn.execute(SELECT name FROM sqlite_master WHERE typetable LIMIT 10) print(cur.fetchall())逻辑说明PRAGMA key用x...十六进制字面量传 key避免普通字符串在编码转换时污染字节内容kdf_iter决定 PBKDF2 派生的迭代轮数与加密时不一致派生出的密钥就完全不同cipher_page_size影响每页加密的偏移计算不能省略。这段代码跑通后能列出所有表名说明解密成功。如果查sqlite_master报错进第 5 章的排查流程。3.3 手机端解密IMEI uin 的旧逻辑与安卓高版本的现实Android 微信旧版本的 EnMicroMsg.db 密码生成逻辑是公开的取设备 IMEI 和微信 uin用户唯一标识拼接后做 MD5再截取前 7 位作为数据库密码。工具包里一般自带这套算法的实现。但安卓 7.0 之后应用不再能直接读取 IMEI高版本微信也调整了密钥生成逻辑所以这个算法只对旧版本手机端库有效。拿到 root 权限后可以从/data/data/com.tencent.mm/shared_prefs/读取 uin 等关键信息。对高版本安卓常见方案是 hook 微信进程、在运行时拿内存中的密钥这是工具包「手机端解密」模块的主要实现方式。如果你不想 rootAndroid 官方备份adb backup也能拿到部分数据但加密层处理会麻烦很多。iOS 端没有 EnMicroMsg.db 这种可读路径数据在 iTunes 备份里提取还要处理备份密码工具包一般单独拆了一个 ios 分支。如果你是 iPhone 主力机建议直接从 PC 端微信数据入手路径更短。4. 数据提取与导出联系人、群组、聊天记录到 CSV/HTML 报告4.1 消息表 Type 字段从 1 到 47 的常见取值解密之后进入 SQL 查询阶段。MSG 表的关键字段包括StrTalker会话对方标识、CreateTime毫秒时间戳、Type消息类型、SubType子类型、Content消息内容、MsgSvrID服务端消息 ID全局唯一。Type 字段是解析的重中之重常见取值如下Type含义Content 存储形式1文本纯文本3图片图片路径 / XML 描述34语音语音消息 guid43视频视频路径描述47表情表情 XML49文件 / 链接卡片XML 结构化内容注意Type49 的 Content 是一段 XML里面包含 appmsg 的 title、des、url 等字段提取时要先做 XML 解析或者用正则拆字段。很多导出报告里链接卡片显示不全就是因为直接把 XML 当纯文本写进了输出。SubType 也有讲究比如 Type49 时 SubType5 是文件、SubType33 是小程序卡片按 SubType 分流处理更精确。4.2 联系人、群组、消息三类导出脚本准备好解密后的库文件下面这段脚本完成三类导出。它假设你已经拿到解密后的库输出统一使用 UTF-8-SIG 编码保证 Excel 打开不乱码import sqlite3 import csv import datetime import re conn sqlite3.connect(decrypted.db) # 忽略非法 UTF-8 字节避免单条脏数据中断整次导出 conn.text_factory lambda b: b.decode(utf-8, errorsignore) def ms_to_local(ms: int) - str: # 判断是毫秒还是秒13 位是毫秒10 位是秒 if ms 1e12: ms * 1000 return datetime.datetime.fromtimestamp(ms / 1000).strftime(%Y-%m-%d %H:%M:%S) # 1) 联系人导出 with open(contacts.csv, w, newline, encodingutf-8-sig) as f: w csv.writer(f) w.writerow([wxid, nickname, remark]) for row in conn.execute( SELECT UserName, NickName, Remark FROM Contact WHERE Type 0): w.writerow(row) # 2) 群信息导出 with open(chatrooms.csv, w, newline, encodingutf-8-sig) as f: w csv.writer(f) w.writerow([roomid, roomname, member_count]) for row in conn.execute( SELECT UserName, NickName, LENGTH(MemberList) FROM ChatRoom): w.writerow(row) # 3) 单聊消息导出talker 参数替换为目标会话标识 def export_chat(talker: str, out: str): with open(out, w, newline, encodingutf-8-sig) as f: w csv.writer(f) w.writerow([time, type, is_send, content]) for t, typ, send, content in conn.execute( SELECT CreateTime, Type, IsSender, Content FROM MSG WHERE StrTalker? ORDER BY CreateTime, (talker,)): # 把 XML 标签替换成空格让内容在 CSV 里可读 content re.sub(r[^], , str(content)) w.writerow([ms_to_local(t), typ, send, content.strip()]) export_chat(wxid_xxxxxxxx, chat_export.csv)逻辑说明conn.text_factory把非 UTF-8 字节按 UTF-8 解码并忽略错误微信消息里偶尔混入的图片描述、系统通知特殊字符不会拖垮整次导出ms_to_local按位宽判断时间单位微信 PC 端 CreateTime 通常是 13 位毫秒但从手机端同步过来的字段可能出现 10 位秒值IsSender用来区分自己发的消息1还是对方发的0后续做会话统计分析时很有用。参数上ORDER BY CreateTime是硬性要求——微信消息表的物理顺序不一定等于时间顺序不排序导出的 CSV 会被打乱。如果想进一步生成 HTML 报告把 CSV 作为数据源用一个简单模板按日期分组渲染聊天记录即可。工具包里通常带这个模板核心是把time字段按日期分组再按会话维度渲染成浏览器可读的页面。4.3 时间戳与编码毫秒级时间、UTF-8-SIG 和 Excel 的兼容时间戳转换是导出环节最容易出错的地方。微信 PC 端CreateTime是本地时区毫秒值不需要再做时区偏移直接datetime.fromtimestamp(ms / 1000)得到的就是本地时间。但手机端message表的createTime同样是毫秒某些第三方备份里会出现 10 位秒级值所以脚本里做了位宽判断。这个判断逻辑不能省一旦遇到秒级值没有乘 1000导出的时间会变成 1970 年附近排查起来很费劲。输出编码必须用 UTF-8-SIG不能只写 UTF-8。Excel 对不带 BOM 的 UTF-8 文件默认按 ANSI/GBK 解析中文全部乱码UTF-8-SIG 带 BOM 头Excel 能正确识别。这是从「导出文件发给别人打不开乱码」的血泪经验里得出的导出脚本里统一用encodingutf-8-sig不要留给使用者自己改。5. 避坑与常见问题解密失败、乱码、版本迁移里的真实翻车记录5.1 解密失败file is not a database 与 SQLCipher 版本年代错位现象key 看着没问题PRAGMA key执行也不报错但一查sqlite_master就报file is not a database。原因SQLCipher 3.x 和 4.x 的kdf_iter默认值不同旧工具用 64000、新库用 256000参数没对齐时派生出的密钥完全不同引擎认为读到的不是合法库文件。解决先确认微信版本对应的 SQLCipher 版本再在连接时显式写PRAGMA kdf_iter 256000对应 4.x。如果工具包支持自动探测优先用自动模式手工模式下kdf_iter、cipher_page_size、hmac_algorithm三个参数必须配套设置只改其中一个解决不了问题。5.2 Key 文件不能直接拼偏移量与中间态现象从配置目录里拖出一个字符串当成 32 字节 key 转成 hex解密失败。原因key 文件里保存的不一定是最终 key可能是经过变换的中间态或者 key 存在文件末尾、前面是其他配置数据。直接把整段内容当成 key 用等于把噪音一起喂给了密钥派生。解决用十六进制编辑器确认 key 文件的实际长度。如果长度大于 32 字节检查尾部 32 字节是否具有高熵特征十六进制看起来均匀随机没有大量重复如果长度是 44 字符的 base64先 base64 解码再截取。多数版本的 key 提取脚本已经内置偏移逻辑手工操作只是为了验证脚本结果验证通过后就不用每台机器都手动来一遍。5.3 图片路径指向 .dat加密后的媒体文件还得再解一次现象聊天记录导出来了图片消息 Content 里是一个.dat路径按路径找到文件用图片查看器打开却报错。原因微信把图片、语音、视频文件做了 XOR 加密扩展名统一改成.dat这和数据库加密是两套体系。也就是大家常说的「微信 dat 文件查看器」要处理的对象。解决微信 dat 文件是逐字节 XOR 一个固定字节。工具包里一般带 dat 解密脚本思路是「已知明文推导密钥」——取一张已知 jpg 格式的图片用 jpg 文件头FF D8 FF和 dat 文件前三个字节做异或算出 XOR 密钥其余文件都用这个密钥解。关键是要拿到一张格式明确的原文文件jpg/png否则算不出密钥只能靠试错。5.4 4.x 版本迁移旧脚本集体失效后的处理顺序现象电脑微信更新到 4.x 后之前能解密的库打不开了工具包里的旧模块直接报错。原因4.x 不仅改了 key 管理方式本地数据目录结构也变了库文件位置、分库命名都有调整旧版的 key 提取路径走到一半就断了。这不是单个参数的问题是整个数据链路变了。解决处理顺序有讲究——先看版本号再决定用哪套模块不要在一个旧库上反复试新参数。我的习惯是把 PC 端和手机端数据分开处理PC 端 4.x 优先用工具包里的新版 key 提取模块走进程内存读取手机端旧库如果已经用旧算法生成过 key先导出完成再升级微信因为升级后密钥可能被刷新旧库会彻底打不开。5.5 CSV 乱码与消息缺失编码和分库两个隐形坑现象用 Python 写出的 CSV 用 Excel 打开中文全部乱码或者导出的消息数量明显比手机微信上能看到的少。原因乱码是编码问题——写文件用了utf-8编码Excel 默认用 GBK 解析中文。消息缺失则可能是分库问题数据量大时微信把消息拆到 MSG0.db、MSG1.db只查了 MSG.db 自然丢数据。解决输出统一用utf-8-sig避免 Excel 猜编码查询前先列出sqlite_master里的表或者直接在目录里dir /b *.db确认是单库还是分库结构。分库时对多个库执行同一 SQL按MsgSvrID去重合并。6. 进阶把解析流程固化成一条可重复的数据备份管线6.1 解密后的冒烟测试三连每次解密成功后不要直接全量导出先做三件事查sqlite_master看表数量是否正常跑一条SELECT COUNT(*) FROM MSG对比微信设置里的聊天记录体量抽查最近一条消息的 Content 是否可读。三步全过再继续sqlite3 decrypted.db SELECT COUNT(*) FROM MSG; sqlite3 decrypted.db SELECT CreateTime, Content FROM MSG ORDER BY CreateTime DESC LIMIT 3;这三连能识别「解密成功但数据不完整」的隐蔽问题。比如打来的库是旧备份而不是正在使用的最新库表能打开、消息也有但时间停在几个月前或者分库只遍历了主库计数明显偏小。冒烟测试比直接导完再核对高效得多。6.2 增量导出与去重策略第一次全量导出后把消息表最大的MsgSvrID记录在本地文件中。之后每次只导MsgSvrID 上次值的消息。微信的服务端消息 ID 随消息创建时间单调递增这个前提成立时增量方案就是安全的。合并时用MsgSvrID做唯一键去重多端同步产生的重复消息只保留一条。思路和 datax、mongoshake 这类同步工具的全量加增量模式一致只是规模小得多。导出的 CSV 已经带本地时间字符串后续做数据挖掘时时间预处理可以省掉一步。6.3 把脚本挂成定时任务在 Windows 上用任务计划程序在 Linux 上用 cron把「提取 key → 解密 → 冒烟三连 → 增量导出」串成一个脚本每周跑一次。导出的 CSV 统一放到一个目录再快照同步到私有存储。这治好了我一直以来「聊天记录只有一份、丢了就没了」的焦虑。从那以后我每次拿到新版本微信第一件事不是看功能更新而是先跑一遍「key 提取 解密 冒烟三连」确认这套管线没被版本更新打破。希望这份工具包能帮你把同样的流程跑通少踩我踩过的那些坑。本文还有配套的精品资源点击获取
返回列表