Loading... <div class="tip share">请注意,本文编写于 254 天前,最后修改于 235 天前,其中某些信息可能已经过时。</div> 最近这段时间研究了一下怎么解密微信的加密数据库。我们知道,微信在各个平台都是加密保存用户聊天记录的,并且没有提供导出明文记录的功能,这给我们窃取自己的聊天记录带来了非常大的麻烦。为了在能够控制自己的 Windows 电脑的前提下(普通用户权限)获取微信的聊天记录,我这两个星期对微信进行了简单的逆向,并且实现了一个简单的工具进行自动化抓取和解密。 微信版本:(截至 2022.7 为止的)最新版 3.7.0.30。 总体思路:字符串入手 => 找到数据库操作所在库 => 发现使用了开源加密库 => 研究开源库的加密函数位置和加密结构体 => 手动恢复所需函数 => debug back trace 查看 key 的生成逻辑 => key 生成可能在的位置加壳了 => 放弃 => 想办法通过别的办法获取 key => 实现 debugger 直接扣出来 => 直接调用 dll 函数解密数据库 ### db 加密 搞之前先看看网络上有没有参考资料,找到看雪上这篇 19 年的文章[PC版微信数据库解密详细教程](https://bbs.pediy.com/thread-251303.htm)。当然,由于微信在这几年变化很大,文中的方法已经失效了,不过有一定的参考价值,我们可以根据文章猜测出数据库操作仍然是在 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](https://github.com/chujDK/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 呢,因为这个函数只会在登录的时候才会调用。不能假设自己会配合自己重新登录微信。 # 郑重声明: **此文章仅为个人研究学习记录,任何人使用与本文章中任何相关的技术做出任何非法的操作,都与本人无关!** 最后修改:2022 年 08 月 02 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 9 如果觉得我的文章对你有用,那听听上面我喜欢的歌吧