对解密某国产聊天软件聊天数据库的分析

Posted on Jul 14, 2022

最近这段时间研究了一下怎么解密微信的加密数据库。我们知道,微信在各个平台都是加密保存用户聊天记录的,并且没有提供导出明文记录的功能,这给我们窃取自己的聊天记录带来了非常大的麻烦。为了在能够控制自己的 Windows 电脑的前提下(普通用户权限)获取微信的聊天记录,我这两个星期对微信进行了简单的逆向,并且实现了一个简单的工具进行自动化抓取和解密。

微信版本:(截至 2022.7 为止的)最新版 3.7.0.30。

总体思路:字符串入手 => 找到数据库操作所在库 => 发现使用了开源加密库 => 研究开源库的加密函数位置和加密结构体 => 手动恢复所需函数 => debug back trace 查看 key 的生成逻辑 => key 生成可能在的位置加壳了 => 放弃 => 想办法通过别的办法获取 key => 实现 debugger 直接扣出来 => 直接调用 dll 函数解密数据库

db 加密

搞之前先看看网络上有没有参考资料,找到看雪上这篇 19 年的文章PC版微信数据库解密详细教程。当然,由于微信在这几年变化很大,文中的方法已经失效了,不过有一定的参考价值,我们可以根据文章猜测出数据库操作仍然是在 WeChatWin.dll 中做的(当然还有一种方法,就是直接 strings 微信所有的文件,grep 一下 sql,也能确定)。

这个 dll 比较大,拖到 ida 里面让他分析一会,我大概等了一两个小时。

首先字符串入手,搜一下 sql,sqlite,mysql 这些串,最后可以确定使用的是 sqlite3。sqlite3 能使用的加密库不多,字符串再一个个搜过去,能够确定的是它大概率使用了 sqlcipher

下一步,确定 sqlcipher 的版本。由于 sqlite3 有许多错误处理,我们随便找一个,比如 misuse 的情况,搜一下这个字符串,随便找个引用位置

很容易判断这个就是 sqlite3_log 函数,这个函数会带上 sqlite3 的版本 id

根据该 id 能够判断出 sqlite 版本为 3.28.0。然后我们再依此去找使用这个版本的 sqlcipher,根据 release log 就可以找到这个 commit

不过当然,这个版本不一定就是微信用的,但是总是大差不差。之后就可以对着源码还原符号了。

另外,根据 sqlcipher 的文档,得知设置 key 的函数为 sqlite3_key 函数,这个函数实际上就是调用了 sqlite3_key_v2,在 WeChatWin.dll 中似乎直接展开了。

那么如何找到 dll 中的这个函数呢,我的做法比较朴素,先找到 dll 中一个比较好找的函数,比如 sqlite3_exec,然后自己编译一个 sqlcipher 出来,断在 sqlite3_key 上,bt 一下看看调用链,一路下去就能找到这个函数。这个过程比较体力活,这里不讲细节了,反正找到之后,就可以开始调微信了。

最自然的想法是 windbg attach 上去,断 sqlite3_key,然后 k 一下看回溯,然后我就发现,调这个函数的居然在壳里面,似乎是 vmp 壳,我立马放弃,最简单的逆向我都不会还整脱壳,告辞告辞。

换一个思路,debugger 直接扣出来。具体方法为:

  1. windbg attach,在 off 0x13D2710 处(sqlite3_key_v2 函数)下断点。
  2. 点击登陆,断下后 esp + 0x4 处指向的内存部分即存储了 key 长度 0x20。

db 解密

这里我才不去分析他怎么加密然后再搞解密,谁知道tx有没有魔改过加密流程,再者整个 sqlcipher 的加密算法名字我都不认识,更别提反向解密了,所以选择了最无痛的方法:直接调用微信的 dll 中的函数解!管他魔改不魔改,都给他解了。

解密工具

我放在 GitHub 上了 Decrypt-WX-DB (这个仓库还没 public)。手动实现了一个简单的 debugger 来抓 key。这里的抓的 key 和前面的不一样,我是直接抓取的 sqlcipher_page_cipher 的第一个参数 ctx,这个是 codec_ctx 结构体,是 sqlcipher 加密的核心结构体,获取里面的 read_ctx 即可获取 derive 之后的 key 了。

要注意的是,虽然唯一的加密 key 是一个 64bit 的 key,但是在加解密时会 kdf derive 到真正的加密 key,这个时候似乎有根据数据库加盐还是什么的,会存在多种 read_ctx,所以拿到的 ctx 只能解密一部分数据库。就会存在解密失败的情况。多抓几次就能解密所有的数据库了。

为什么不抓 sqlite3_key 呢,因为这个函数只会在登录的时候才会调用。不能假设自己会配合自己重新登录微信。

郑重声明:

此文章仅为个人研究学习记录,任何人使用与本文章中任何相关的技术做出任何非法的操作,都与本人无关!