无需root的微信聊天记录导出方案

价值三台手机&至少10个工作日的研究成果
前置要求:
编程开发能力(必须->未来可能会封装解决方案)
小米手机(必须)
ubuntu运行环境(用于安装sqlcipher)

微信前后用了近10年, 最近两年每回换手机都想把聊天记录导成文本进行记录, 但没找到好方法. 今天终于把路径跑通了, 记录一下.

微信聊天记录导出分为三步:

  1. 将微信数据库从手机端导出, 得到微信数据库EnMicroMsg.db
  2. 破解微信数据库密码, 得到解密后的数据库EnMicroMsg.db.decrypted
  3. 读取数据库内容, 导出为html格式

这里边最难的是前两步.

准备阶段

导出聊天记录需要以下前提

  • 硬件: 小米/红米手机(必须)
    • 微信版本8.0.37
    • MIUI版本14及以下
  • 操作系统: Ubuntu22.04

该方案要求用户使用的必须是小米/红米手机. 如果没有的话可买台任意的二手小米手机, 三四百块钱不算太贵. 考虑到只用一次的话, 临时借台也能接受.

拿到小米手机后, 为避免意外, 需要对操作环境状态进行初始化. 流程如下

  1. 将原聊天记录备份到电脑端
  2. 删除小米手机内的微信, 安装微信8.0.37版本
  3. 从电脑端将聊天内容恢复到手机上.

通过这个步骤, 可以保证微信聊天记录一定是以8.0.37的加密算法进行的加密, 避免未来微信升级, 加密策略变更导致流程失效

然后开始处理

从手机中导出微信数据库

首先从手机中导出微信数据库. MIUI版本14及以下提供了手机端备份App功能, 依次点击设置-我的设备-备份与恢复-手机备份恢复-手机备份(备份内容只选择微信)-立即备份

设置-我的设备
备份与恢复
手机备份
备份产物路径
备份产物路径-2

备份完成后, 文件位于MIUI/Backup/AllBackup中, 微信(com.tencent.mm).bak即为微信应用的所有内容, 复制到电脑上, 将后缀名从.bak修改为.zip, 解压即可.

解压后微信聊天记录数据库名为EnMicroMsg.db, 位于微信(com.tencent.mm)/apps/com.tencent.mm/r/MicroMsg/xxxxxx文件夹内. 这个位置不太好找, 可以直接在操作系统下搜索文件名.

由于准备环节中我们通过重装微信的方式, 保证了当前手机上只有一个用户, 所以这里只会出现一个聊天数据库文件, 不需要和其他数据库进行分辨.

确认数据库文件位置
微信聊天记录数据库

接下来是数据库解密环节

解密微信数据库

生成解密密码

解密微信数据库需要两个参数:

IMEI: 这个在8.0.37版本是固定值, 恒定为1234567890ABCDEF
uin: 可以理解为是微信uid, 获取方法是登陆文件传输助手-网页版, cookie里的wxuin字段即是

微信uin

uin也可以直接查看导出的./微信(com.tencent.mm)/apps/com.tencent.mm/sp/auth_info_key_prefs.xml文件, 里边有_auth_uin字段

或者更暴力一点用find /mnt/d/redmi_微信数据备份测试/微信\(com.tencent.mm\)/apps/com.tencent.mm/sp/ -name "*.xml" -type f -exec sh -c 'grep -q uin "$1" && echo "$1"' _ {} \; 直接过滤也可以----当然从路径中可以看出, 需要在wsl下执行这个命令

对应的密码是md5(imei + uin)的前7位(密码中如有字母, 均为小写)

将加密数据库转换为无密码数据库

拿到数据库密码后, 确保sqlcipher为4.1及以上版本, 执行命令sqlcipher ./resource/EnMicroMsg.db, 打开加密数据库, 依次执行以下代码即可转换得到无密码数据库decryption_en_micro_msg.sqlite3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- 查看sqlcipher版本, 要求必须是4.1以上
-- 本次验证通过的版本是 4.5.4 community
PRAGMA cipher_version;
-- 配置密码
PRAGMA key = '1234567';
-- 配置解密算法
PRAGMA cipher_compatibility = 1;
-- 创建无密码数据库
ATTACH DATABASE 'decryption_en_micro_msg.sqlite3' AS db KEY '';
-- 将加密数据库导出到无密码数据库中
SELECT sqlcipher_export('db');
-- 导出完毕, 关闭连接
DETACH DATABASE db;
-- 退出sqlcipher
.q

将原始数据库转换为html聊天记录

wechat-dump本身提供了简单的将数据库转换为html的能力, 不过聊天样式还停留在古早时代, 输出的文件名也只是简单的按序号递增, 没有区分日期时间. 考虑到这是个人项目, 实现上有待完善的点可以理解. 记录一下转换命令

准备阶段

参考wechat-dump本身的项目说明, 需要以下几步.

  1. 执行bash third-party/compile_silk.sh, 构建silk执行文件, 似乎是一个将微信语音转换为mp3的程序, 执行就是了
  2. 下载https://github.com/ppwwyyxx/wechat-dump/releases/download/0.1/emoji.cache.tar.bz2文件, 将解压得到的emoji.cache放在项目根目录下, 方便读取
  3. 整理resource文件夹, 将avatar/emoji/image2/sfs/video/voice2文件夹都放在同一个文件夹下, 作为res目录
    1. 这里边emoji位于./微信(com.tencent.mm)/apps/com.tencent.mm/f/public文件夹下
    2. 其他所有文件夹(avatar/image2/sfs/video/voice2)都在./微信(com.tencent.mm)/apps/com.tencent.mm/r/MicroMsg/${userid}文件夹下----就是EnMicroMsg.db所在的文件夹
  4. 最好注释掉wechat/emoji.py里的日志输出, 报错过多会影响运行速度

执行

项目目录下执行./dump-html.py 联系人的微信备注名 --db decrypted_enmicrossg.sqlite3 --res /mnt/e/微信\(com.tencent.mm\)/apps/com.tencent.mm/r/MicroMsg/xxxxxxxx --output ./resource/html/test.html即可.

如果忘记了联系人的备注名, 可以数据库的rcontact表中查询, 对应字段是conRemark, 具体数据库结构介绍可以自行百度, 或者看这篇文章, 有简单的介绍

更暴力的方法是通过sqlite3浏览器直接查看message表里的聊天内容

但总而言之, 目前还没看到很好的导出方案. 后续可以考虑自己搞一个

特别注意

特别注意: 绝对要保护好无加密的聊天数据库文件, 这里边有所有的微信聊天记录内容, 而且完全没有加密, 所有人都能查看. 放出去就能当场社死…

不过这都是后话, 属于幸福的烦恼…

接下来是纯技术部分, 仅为记录方案发现过程. 非代码爱好者可以Ctrl+W

方案探索过程笔记-与正文无关

事实上, 上述流程是一个非常取巧的过程, uin和imei一步都不能错. 错了之后排查问题也相当麻烦. 所以还是得知其所以然, 记录一下正确的探索流程.

排查思路的来源

以上思路实际上均来源于wechat-dump开源项目, 具体来说是他的Decrypt database file步骤.

项目提供了一个./decrypt-db.py decrypt --input ./resource/EnMicroMsg.db --imei 1234567890ABCDEF --uin 123456789 命令, 可以用这个命令快速验证imei和uin组合是否正确, 正确就可以得到无密码数据库, 不正确就报错.

而这个项目又依赖pysqlcipher3包, 这个包要求操作系统中有4.10以上版本的libsqlcipher-dev, 但ubuntu/debian目前libsqlcipher-dev只提供到 3.4.1, 不能满足要求. 所以问题来了…

如何获得sqlcipher应用程序

目前官方未提供直接的应用程序下载, 我们需要的是…手工编译

首先克隆sqlcipher项目

构建前可能需要一些依赖, 可以提前安装

1
sudo apt-get install openssl tcl

如果configure失败, 提示configure: error: C compiler cannot create executables 的话, 可以先卸载sudo apt-get autoremove gcc g++后重新安装sudo apt-get install gcc g++, 还不行就运行prelink -au && depmod -a以更新系统

执行以下代码

1
2
export SQLITE_HAS_CODEC
export SQLITE_TEMP_STORE=2

然后开始构建

1
2
3
4
5
6
7
8
9
# 生成构建配置
./configure --enable-tempstore=yes CFLAGS="-DSQLITE_HAS_CODEC" LDFLAGS="-lcrypto"
# 构建sqlcipher的可执行文件. 如果构建失败, 或需要重新构建前, 记得先执行make clean 清理之前的残留构建产物
make
# 将构建产物推送至/usr/local/lib, 提供libsqlcipher.so动态链接库供pysqlcipher3绑定
# 由于是推送到/usr/local/lib, 所以需要sudo权限
sudo make install
# 将构建后的sqlcipher推送至全局Path下, 方便使用
cp sqlcipher /usr/local/sbin/

构建完成后执行sudo /sbin/ldconfig -v, 否则pip install pysqlcipher3时会有cannot open shared object file: No such file or directory报错

pip install pysqlcipher3默认会有缓存, 如果需要强制重新安装的话, 需要先执行rm -rf ~/.cache清理pip缓存

可以通过python3 -c "from pysqlcipher3 import dbapi2 as sqlite; print(sqlite.sqlite_version)"确认pysqlcipher3绑定的是不是预期中的sqlite版本, SQLCipher 4.5.4 community的输出是3.41.2. 如果输出值是3.37.2, 说明是sqlcipher (3.4.1-2build1)的产物, apt autoremove把官方的sqlcipher卸掉吧.

其他的破解微信数据库密码的方法

wechat-dump的思路是已知密码生成规则破解密码. 还有其他的两种思路:

方案一: 暴力破解.
对应于EnMicroMsg.db-Password-Cracker这个项目. 由于密码只取了md5的前7位, 一共只有16^7=268435456种可能. 只要用程序反复尝试肯定也能搞出来.

但这里其实也有风险: 这里只考虑了密码的状态空间有穷, 但没有想到加密算法组合本身也是一个问题----如果加密算法组合配置不正确, 密码正确也一样解不出来. 目前只能祈祷微信别换加密算法了

方案二: root手机后, 利用xposed框架拦截微信运行时的密码. 好处是该方法肯定可行. 问题是: 需要安卓开发能力----但这是我的弱项.

好了, 就这样. 剩下的看什么时候有空, 把数据库转html写写, 预计要明年了

参考资料


无需root的微信聊天记录导出方案
https://www.yaozeyuan.online/2023/06/03/2023/06/无需root的微信聊天记录导出方案/
作者
姚泽源
发布于
2023年6月3日
许可协议