提取安卓微信本地聊天记录数据库解密

最近需要提取微信聊天记录作为证据提交,由于量大截图太麻烦,就想直接提取微信的聊天记录数据。

Posted by 浅唱 on November 27, 2023

背景

整个过程分为三步:

  1. 提取聊天消息数据库 EnMicroMsg.db 文件
  2. 获取数据库密码,解密
  3. 使用 Sql 命令指定条件导出聊天记录

获取数据库文件

微信的本地数据库 EnMicroMsg.db 存储在 /data/data/com.tencent.mm/MicroMsg/{hash}/EnMicroMsg.db

  1. 手机 Root 后,使用 RE 文件浏览器等文件浏览器复制出来,
  2. 使用手机自带的备份功能,将微信应用数据备份下来,解压提取

获取数据库密码与解密数据库

上一步取出的 EnMicroMsg.db 数据库文件是加密过的,加密方式为 SQLCipher V1 加密

微信本地数据库密码算法

  1. 获取手机 IMEI 码 IMEI 码在手机上拨号 *#06# 就可以查看,一般手机使用卡槽 1 的 IMEI,如若不行可以试试卡槽 2 的,CDMA 手机使用 MEID。
    针对 MIUI 等隐私保护系统无法获取到 IMEI 码,则使用默认的 1234567890ABCDEF
    也有说法说:IMEI 码 存储在/data/data/com.tencent.mm/MicroMsg下的systemInfo.cfgCompatibleInfo.cfg中,或/data/data/com.tencent.mm/shared_prefs/DENGTA_META.xml,可以尝试找找。
  2. 获取当前登录微信账号的 uin(存储在 sp 里面) uin 存储在/data/data/com.tencent.mm/shared_prefs/com.tencent.mm_preferences.xmlauth_hold_prefs.xmlauth_info_key_prefs.xml等文件中,博主在最后一个文件中找到,类型为 int,名称为_auth_uni,数据是带有负号的 int 型。 形如<int name="_auth_uin" value="-123456789" />

  3. 拼接 IMEI 和 uin 不管 uin 是不是负数,当作字符串和 IMEI 拼接起来就好。然后把 IMEI + uin 这个拼接完的字符串拿去计算 32 位 md5 值(百度一下就会有计算的在线工具),截取加密后的字符串的前七位(字母必须为小写)就是密码。

暴力破解方案参考

https://zhuanlan.zhihu.com/p/123942610
https://github.com/chg-hou/EnMicroMsg.db-Password-Cracker
https://github.com/whiteblackitty/SQLCipher-Password-Cracker-OpenCL

打开连接数据库

使用最新版本的 sqlitestudio

下载地址:

参考https://www.jianshu.com/p/eb7f96c0c36f文章
查看 Android 微信数据库使用 SqlCipher 加密代码,可见使用 sqlcipher 1 版本

private static final SQLiteCipherSpec qDP =
new SQLiteCipherSpec().setPageSize(1024).setSQLCipherVersion(1);

再查看 SQLCipher 的源码发现设置 CipherVersion 为 1 时 , 会关闭 hmac, kdf_iter 为 4000。

public SQLiteCipherSpec setSQLCipherVersion(int version) {
switch (version) {
    case 1: hmacEnabled = false; kdfIteration = 4000;  break;
    case 2: hmacEnabled = true;  kdfIteration = 4000;  break;
    case 3: hmacEnabled = true;  kdfIteration = 64000; break;
    default: throw new IllegalArgumentException("Unsupported SQLCipher version: " + version);
}
return this;
}

于是手动指定参数配置 Cipher configuration 来连接:

PRAGMA kdf_iter = '4000';
PRAGMA cipher_use_hmac = OFF;
PRAGMA cipher = 'AES-256-CBC';
PRAGMA cipher_page_size = 1024;

失败告终,查阅官方文档,发现

PRAGMA cipher_compatibility :Force SQLCipher to operate with default settings consistent with that major version number for the current connection.
强制 SQLCipher 使用与当前连接的主版本号一致的默认设置运行。

通过 PRAGMA cipher_compatibility 配置,强制指定 SQLCipher 的版本号后,会自动使用该版本默认的配置链接,这样避免我们自行设置那些乱七八糟的配置,将下列配置粘贴到工具中的加密算法配置选项中

PRAGMA cipher_page_size = 1024;
PRAGMA cipher_compatibility = 1;


测试发现, OK~

使用 3.2.1 版本的 sqlitestudio

参考https://blog.csdn.net/nbvnvnvbn/article/details/97903456https://cloud.tencent.com/developer/article/2093693文章使用 3.2.1 版本的 sqlitestudio

  • 数据类型选择 SQLCipher
  • Cipher 为默认的 aes-256-cbc
  • KDF iterations 为 4000
  • Cihper page size 为默认的 1024
  • 1.1 compatibility 勾选上

    然后点击测试连接,出现对勾则表示连接成功

导出聊天记录

message 表里有所有的聊天记录,具体的 sql 语句不做赘述。当然不管用什么软件,可读性都很差,需要有程序把它们按照聊天群组/人分开展示。

参考https://zhuanlan.zhihu.com/p/123942610文章推荐wechat-dump库是一个很好的从数据库中提取消息并分类导出的库,需要在 linux + python 2 环境下运行,具体配置参见项目 README 。 列出所有联系人:

./list-chats.py decrypted.db

导出所有聊天记录为文本文件:

./count-message.sh output_dir

将某个对话渲染为 html 文件:

./dump-html.py "<contact_display_name>"

导出的 html 文件可以用浏览器打开,也可以进一步打印成 pdf 。

后话

用户产生的数据不属于用户自己,说来也是可笑,应用的设计并不是以用户体验为中心,而是以用户的钱包为中心。 如此严格的限制聊天数据可以极大的提升微信用户的迁移成本,因为用户无法将聊天记录导入其它的软件。 但是这样做对用户来说就极为不友好,聊天记录漫游的功能需要付费,而且最高级别的漫游也不能保存全部聊天记录,这样用户根本无法在手机之外备份数据,手机出问题数据就全没了。 我一直对 QQ 和微信这样的行为深恶痛绝,奈何上一个手机已经用了很久,想要 root 会失去全部数据,想要通过安卓模拟器暗度陈仓又问题频出。 因此,换手机之后我的第一件事就是 root ,冒着设备安全性的风险,不为了各类插件,只为取回自己的数据。

感谢

https://www.jianshu.com/p/eb7f96c0c36f
https://blog.csdn.net/nbvnvnvbn/article/details/97903456
https://cloud.tencent.com/developer/article/2093693
https://zhuanlan.zhihu.com/p/123942610
wechat-dump