☰
WechatDecrypt 微信数据库解密实战:从编译部署到 SQLite 加密页 AES-256-CBC 解密原理
2026/10/16 1:30:56 网站建设 项目流程
  • 逆向工程
  • 密码学

【免费下载链接】WechatDecrypt

微信消息解密工具

项目地址:https://gitcode.com/gh_mirrors/we/WechatDecrypt
点击查看免费下载

导读:本文围绕开源仓库 WechatDecrypt(微信消息解密工具)的 README.md 使用教程展开,完整讲解如何编译该工具、将其部署到微信数据目录,并借助dewechat ChatMsg.db一条命令把加密的微信数据库(如 ChatMsg.db)还原为可用 sqlite 直接打开的明文数据库。同时,文章将深入 wechat.cpp 源码,逐层剖析其背后的 SQLite 逐页解密、PBKDF2-HMAC-SHA1 密钥派生、HMAC-SHA1 完整性校验与 AES-256-CBC 解密实现,让读者既能照章操作,也能读懂底层原理。

一、项目概览与仓库结构

WechatDecrypt 是一个基于 Windows + OpenSSL 的单文件 C++ 工具,用于解密微信 PC 客户端本地保存的加密 SQLite 数据库。微信把聊天记录存放在以微信 ID 命名的目录下,数据库文件(如ChatMsg.db)本身是加密的,无法直接打开;本工具读取加密文件后,按页还原出明文 SQLite 数据库,输出为dec_前缀的新文件。

仓库结构非常精简,全部源码与文档仅三个文件:

文件说明
README.md使用教程:编译、部署路径与解密命令
wechat.cpp核心实现:单文件 C++ 解密程序(约 150 行)
LICENSEMIT 开源协议

整个解密逻辑全部集中在 wechat.cpp 中,主流程由main()与Decryptdb()两个函数承担,没有额外的工程文件或构建脚本,属于典型的“拿到源码直接编译”风格的小工具。

二、环境准备与编译

2.1 依赖条件

从 wechat.cpp 的头部包含可以看出,程序依赖两类组件:

  • Windows 运行环境:#include <Windows.h>,且代码中大量使用fopen_s、strcpy_s、sprintf_s等 MSVC 安全函数,因此它面向 Windows 平台编译运行。
  • OpenSSL 加密库:使用了openssl/evp.h(AES 加解密、PBKDF2)、openssl/hmac.h(HMAC-SHA1)、openssl/aes.h、openssl/rand.h。编译时需要链接 OpenSSL 的libcrypto。

2.2 编译示例

仓库没有附带 Makefile 或 CMakeLists,需要手动调用编译器。以 MinGW-w64 + 已安装 OpenSSL 的环境为例,可参考如下命令(实际请根据本机 OpenSSL 的 include/lib 路径调整-I、-L参数):

g++ wechat.cpp -o dewechat.exe -I<openssl/include> -L<openssl/lib> -lcrypto -lssl

在 Visual Studio 环境下,则用cl编译并链接 OpenSSL 库即可。编译成功后得到可执行文件,按 README 的使用方式,二进制名称应为dewechat(Windows 下即dewechat.exe)。

三、部署:把工具拷贝到微信数据库目录

编译完成后,README 给出的部署方式是:把这个可执行文件拷贝到微信数据库目录。该目录通常在:

C:\Users\Administrator\Documents\WeChat Files\********\Msg

其中路径里的星号********处就是需要解密的微信 ID——每个微信账号在WeChat Files下都有一个以自身 ID 命名的文件夹,聊天数据库就存放在该文件夹下的Msg子目录中。

把dewechat.exe放到Msg目录后,后续只需在该目录下打开 CMD 执行解密命令即可。如果不想拷贝,也可以把可执行文件放在任意位置,运行命令时直接传入数据库文件的完整路径——从源码结构看,main() 会把argv[1]原样作为文件名打开(见 Decryptdb() 中的fopen_s(&fpdb, dbfilename, "rb+")),因此传入相对路径或绝对路径均被支持。

四、解密实战:CMD 命令与输出结果

4.1 一条命令完成解密

在Msg目录的 CMD 中执行:

dewechat ChatMsg.db

即可解密当前目录下的ChatMsg.db。README 特别说明,ChatMsg.db就是需要解密的微信数据库文件之一(聊天消息数据库)。

4.2 解密成功后的输出

解密成功后,程序会在当前目录输出:

dec_ChatMsg.db

即原文件名加上dec_前缀。README 明确说明:用 sqlite 打开dec_ChatMsg.db即可查看解密后的明文数据。常见的打开方式包括 SQLiteStudio、DB Browser for SQLite 等 GUI 工具,或sqlite3 dec_ChatMsg.db命令行工具。

4.3 运行期交互与提示信息

从 main() 可以看到,程序支持两种调用形态:

  • 带参数:dewechat ChatMsg.db,直接使用argv[1]作为文件名;
  • 不带参数:程序会提示请输入文件名:,等待用户在命令行手工输入数据库文件名后再开始解密。

解密过程中,程序会逐页打印进度。结合 wechat.cpp 的源码,可以观察到这些关键提示:

提示信息触发场景
打开文件错!文件不存在或无法以rb+方式打开
解密数据页:x/y每解密一页打印一次进度
哈希值错误!当前页 HMAC-SHA1 完整性校验失败(密钥不匹配或文件损坏)
解密成功!全部页面解密完成

注意:任一页面的哈希校验失败都会直接终止程序并等待按键退出,说明工具对“密钥与文件不匹配”的情况有内置的防御性检查。

五、源码级解密原理(wechat.cpp 逐层拆解)

解密不是简单地用一把钥匙打开文件,而是遵循一套 SQLite 逐页加密方案。下面按 Decryptdb() 的执行顺序拆解。

5.1 整库读入与盐(Salt)提取

程序先把整个加密文件读入内存缓冲区:

fseek(fpdb, 0, SEEK_END); long nFileSize = ftell(fpdb); fseek(fpdb, 0, SEEK_SET); unsigned char* pDbBuffer = new unsigned char[nFileSize]; fread(pDbBuffer, 1, nFileSize, fpdb);

随后取文件前 16 字节作为派生密钥用的盐:

unsigned char salt[16] = { 0 }; memcpy(salt, pDbBuffer, 16);

也就是说,加密库文件的头部 16 字节以明文形式存放盐,而解密时这 16 字节并不会被解密——首页解密会跳过它们,并在输出文件中将其还原为 SQLite 文件头(详见 5.6)。

同时,程序还会生成一份用于 HMAC 密钥派生的mac_salt,规则是对盐逐字节异或0x3a:

mac_salt[i] ^= 0x3a;

5.2 密钥派生:PBKDF2-HMAC-SHA1

工具没有直接使用一个静态密钥,而是通过 PBKDF2-HMAC-SHA1 从“主密码 + 盐”派生出 32 字节的 AES 密钥:

PKCS5_PBKDF2_HMAC_SHA1((const char*)pass, sizeof(pass), salt, sizeof(salt), DEFAULT_ITER, sizeof(key), key);

其中pass[]是源码中硬编码的 32 字节主密码数组(wechat.cpp),源码注释明确写道:“PC 端密码是经过 OllyDbg 得到的 32 位 pass”——即该密码来自对微信 PC 客户端进程的动态调试/逆向分析,而非可自行配置的明文口令。

用于页面校验的 HMAC 密钥则进一步从主密钥派生,迭代次数仅为 2:

PKCS5_PBKDF2_HMAC_SHA1((const char*)key, sizeof(key), mac_salt, sizeof(mac_salt), 2, sizeof(mac_key), mac_key);

5.3 页面结构与“保留区”(reserve)

加密库按固定大小页面组织数据。PC 端每页 4096 字节,源码注释给出了页面内的布局:

//4048数据 + 16IV + 20 HMAC + 12

即每页由 4048 字节密文数据、16 字节 IV、20 字节 HMAC-SHA1 摘要,以及 12 字节余量构成,合计 4096。程序用以下逻辑计算尾部保留区大小:

int reserve = IV_SIZE; // 16 reserve += HMAC_SHA1_SIZE; // +20 = 36 reserve = ((reserve % AES_BLOCK_SIZE) == 0) ? reserve : ((reserve / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE; // 对齐到 16 的倍数 → 48

因此每页尾部 48 字节为保留区,其中:

  • [4048, 4064):16 字节 AES-CBC IV;
  • [4064, 4084):20 字节 HMAC-SHA1 校验值;
  • [4084, 4096):12 字节余量。

5.4 逐页 HMAC-SHA1 完整性校验

在解密每一页之前,程序先用mac_key对该页的密文数据(从当前偏移到 4064 字节处)连同页码计算 HMAC-SHA1,并与页面尾部存储的 20 字节校验值比对:

HMAC_Init_ex(&hctx, mac_key, sizeof(mac_key), EVP_sha1(), NULL); HMAC_Update(&hctx, pTemp + offset, DEFAULT_PAGESIZE - reserve - offset + IV_SIZE); HMAC_Update(&hctx, (const unsigned char*)&nPage, sizeof(nPage)); HMAC_Final(&hctx, hash_mac, &hash_len); if (0 != memcmp(hash_mac, pTemp + DEFAULT_PAGESIZE - reserve + IV_SIZE, sizeof(hash_mac)))

将页码纳入 HMAC 计算意味着各页之间的校验值相互绑定,任何一页内容被替换或篡改都会导致校验失败,这正是防止“页序调换攻击”的标准做法。校验失败时程序打印哈希值错误!并终止。

5.5 AES-256-CBC 解密

通过校验后,程序使用 32 字节主密钥key和本页尾部存储的 IV,对页面数据执行 AES-256-CBC 解密,并显式关闭填充(EVP_CIPHER_CTX_set_padding(ectx, 0)),因为密文长度正好是 16 字节 AES 块大小的整数倍:

EVP_CipherInit_ex(ectx, EVP_get_cipherbyname("aes-256-cbc"), NULL, NULL, NULL, 0); EVP_CIPHER_CTX_set_padding(ectx, 0); EVP_CipherInit_ex(ectx, NULL, NULL, key, pTemp + (DEFAULT_PAGESIZE - reserve), 0); EVP_CipherUpdate(ectx, pDecryptPerPageBuffer + offset, &nDecryptLen, pTemp + offset, DEFAULT_PAGESIZE - reserve - offset);

解密长度与起始偏移因页而异:首页从偏移 16 开始解密 4032 字节,其余页从偏移 0 开始解密 4048 字节。

5.6 首页 SQLite 文件头恢复与输出落盘

SQLite 数据库文件的标准头是 16 字节的"SQLite format 3",而加密库把这 16 字节位置用作明文盐。因此解密首页时,程序把解密缓冲区的前 16 字节替换回标准 SQLite 头:

if (nPage == 1) { memcpy(pDecryptPerPageBuffer, SQLITE_FILE_HEADER, offset); }

每页解密完成后,页面尾部 48 字节保留区(IV + HMAC + 余量)被原样拷贝到输出缓冲区的相同位置,随后整页 4096 字节追加写入以dec_前缀命名的输出文件:

sprintf_s(decFile, "dec_%s", dbfilename); fopen_s(&fp, decFile, "ab+"); fwrite(pDecryptPerPageBuffer, 1, DEFAULT_PAGESIZE, fp);

也就是说,输出的dec_ChatMsg.db在每页尾部仍保留 48 字节的 IV/HMAC 痕迹,但这部分字节落在 SQLite 页面数据区内,不影响 SQLite 正常读取整库,因此可以放心用 sqlite 工具直接打开。

六、核心常量与参数速查表

以下常量均直接来自 wechat.cpp,是理解与移植该算法时的关键数值:

常量 / 参数值含义
SQLITE_FILE_HEADER"SQLite format 3"SQLite 标准文件头(16 字节)
IV_SIZE16AES-CBC 初始化向量长度
HMAC_SHA1_SIZE20HMAC-SHA1 摘要长度
KEY_SIZE32派生出的 AES 密钥长度(即 AES-256)
AES_BLOCK_SIZE16AES 分组大小(用于保留区对齐)
DEFAULT_PAGESIZE4096PC 端每页字节数(4048 数据 + 48 保留区)
DEFAULT_ITER64000PBKDF2-HMAC-SHA1 主密钥迭代次数
reserve48每页尾部保留区(16 IV + 20 HMAC + 12 余量,对齐到 48)
pass[]32 字节硬编码主密码(逆向自 PC 端)
输出文件命名dec_+ 原文件名如dec_ChatMsg.db

七、平台差异分支:源码中预留的 Android 配置

wechat.cpp 中通过条件编译宏ANDROID_WECHAT预留了一套移动端参数分支:

#ifndef ANDROID_WECHAT #define DEFAULT_PAGESIZE 4096 //4048数据 + 16IV + 20 HMAC + 12 #define DEFAULT_ITER 64000 #else #define NO_USE_HMAC_SHA1 #define DEFAULT_PAGESIZE 1024 #define DEFAULT_ITER 4000 #endif

从源码结构看,Android 分支定义了三个差异点:页面大小降为 1024 字节、PBKDF2 迭代次数降为 4000,并通过NO_USE_HMAC_SHA1关闭 HMAC 校验。不过需要说明的是:本仓库中没有在任何构建入口定义ANDROID_WECHAT,且整个源文件依赖<Windows.h>与 MSVC 安全函数,实际可编译运行的场景仍是 Windows 桌面端;Android 分支更接近源码中预留的算法参数说明,而非本仓库现成可用的 Android 构建。

八、局限性与注意事项

  1. 主密码硬编码、依赖特定版本:32 字节主密码直接内嵌在源码中,且注释表明它来自对特定微信 PC 客户端版本的逆向调试(OllyDbg)。因此该工具的有效性绑定于对应微信版本的密钥与页面加密布局——微信升级、更换版本或数据格式调整后,使用旧密钥解密新库可能导致哈希值错误!或解密失败。这是从 wechat.cpp 源码事实可以确认的边界条件。
  2. 仅适用于本人数据:工具用途是解密本机微信数据目录下的数据库,应仅在合法、授权的场景下使用(如数据迁移、本地存档分析),不应用于未授权访问他人数据。
  3. 代码中存在未实现的辅助函数:源文件开头声明了CheckKey()与CheckAESKey()两个函数(wechat.cpp),但在当前版本中既未定义也未调用,可推断为早期设计遗留,不影响实际解密主流程。
  4. 输出文件保留每页尾部 48 字节:dec_输出文件每页末尾会原样保留 IV/HMAC 保留区,虽然不影响 sqlite 读取,但若追求“纯净”的 SQLite 文件,可在此基础上自行剥离。

九、相关文件索引

想深入验证本文所述内容,可直接阅读仓库中的以下文件:

  • README.md:官方使用教程(编译、部署路径、解密命令与输出文件说明);
  • wechat.cpp:全部解密实现,重点阅读main()(第 32-43 行)与Decryptdb()(第 45-149 行);
  • LICENSE:MIT 开源协议,注明版权归属。

整体来看,WechatDecrypt 以极简的单文件实现演示了一条完整的微信数据库解密链路:明文盐 → PBKDF2 派生主密钥与 HMAC 密钥 → 逐页 HMAC-SHA1 校验 → AES-256-CBC 解密 → SQLite 文件头还原。无论你是只想解密自己的聊天记录,还是想研究微信本地数据库的加密方案,这份代码都是值得对照阅读的入门级参考。

  • 逆向工程
  • 密码学

【免费下载链接】WechatDecrypt

微信消息解密工具

项目地址:https://gitcode.com/gh_mirrors/we/WechatDecrypt
点击查看免费下载

相关推荐

上一篇:从零开始打造专业级媒体播放体验:mpv PlayKit 完全指南
下一篇:5个关键步骤彻底解锁mpv播放器:从零到精通的专业配置指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询