前置知识:微信使用 SQLite 数据库在本地保存聊天记录,为了保证聊天记录不被轻易窃取,微信基于 SQLCipher 封装了腾讯自己的 WCDB 数据库框架。为了能够导出微信聊天记录,就需要通过技术手段获取数据库的加密密钥,这就是本小结需要达成的目标。

获取微信密钥

安装lldb

安装 lldb:lldb 是 Xcode 内置的开发者工具,可以用来调试 C/OC/C++/Swift 程序的调试器。为了能够使用 lldb,需要先安装一下开发者工具。在终端中执行 lldb 命令,弹出如下所示的提示框,那就是说明没有安装过 lldb,根据指示进行安装即可。如果以前执行过 xcode-select –install 或者已经安装过 Homebrew 的话,电脑上应该已经有了这个工具。

关闭SIP

临时关闭系统的 SIP(SystemIntegrityProtection)即系统完整性保护,默认情况下 lldb 是无法调试微信,需要关闭 SIP。在 macOS 上关闭 SIP 需要进入恢复模式的终端里去执行命令。Intel MacBook 按下开机键后按住 Command-R 组合键进入恢复模式,arm MacBook 按住开机键不放直到出现选择界面,进入恢复模式进行操作。

得到微信秘钥

正常进入系统之后,就可以使用 lldb 程序调试工具调试微信了。先运行微信,但是不要登录,让它保持在登陆窗口。然后打开终端输入 lldb -p $(pgrep WeChat) 获取微信的进程 ID,指定 lldb 通过进程 ID 挂载 debug 程序。成功挂载微信程序之后,会显示出类似如下的界面:

接下来就是打断点了,在微信里的 sqlite3_key 函数上打一个断点,当程序运行到这个函数的时候就会暂停下来,等待输入调试命令。

输入命令 br set -n sqlite3_key 即可,lldb 回显:Breakpoint 1: 2 locations.,说明 lldb 已经成功在这两个地方打上了断点。

然后继续输入命令 c 回车即可,lldb 回显:Process 59241 resuming,此处的 c 即为 continue,执行完这条命令之后,程序就能正常继续向下执行,直到触发断点。

(lldb) br set -n sqlite3_key  
Breakpoint 1: 2 locations.  
(lldb) c  
Process 58802 resuming

那么如何触发断点呢?现在微信已经恢复正常运行了,只需要点击登陆或者扫码登陆微信即可。点击完登陆或者扫码确认之后,lldb 就会拦截到这个断点,让微信再次暂停运行,这时候微信会卡住,这是正常现象。

切换回终端查看,可以看到 lldb 已经正确地把微信在 sqlite3_key 函数的入口处断点了。

最后一步,输出内存里的密钥值。在日常生活中,大家可能听说过:「电脑上临时存储数据,经常会说把数据存在内存里,因为这样比较快等类似的话」。但是很少有人会直接跟内存去打交道。但是现在在 lldb 的帮助下,就可以直接读取到内存的值,此处要读取的就是数据库的密钥,通过以下命令直接获取到数据库秘钥

Intel CPU 构架命令:memory read –size 1 –format x –count 32 $rsi

arm CPU 架构命令:memory read –size 1 –format x –count 32 $x1

以 Intel CPU 架构为例,最后得到的结果如下所示,复制四行以十六进制表示的内存数据,后续使用 Python 处理即可获取到正确的密钥。最后输入 exit 并再次输入 y 确认退出 lldb 调试,微信即可继续正常运行。

(lldb) memory read --size 1 --format x --count 32 $rsi
0x60000181d720: 0xe5 0x16 0xc0 0x2a 0x53 0xe3 0x44 0x58
0x60000181d728: 0x97 0x4a 0xbf 0x59 0x22 0xf1 0x8a 0x59
0x60000181d730: 0x4b 0x2a 0xe2 0x3e 0x44 0x8b 0x4e 0x55
0x60000181d738: 0x9c 0x40 0xd8 0xb6 0x74 0xf9 0xdc 0xd4
(lldb) exit
Quitting LLDB will detach from one or more processes. Do you really want to proceed: [Y/n] y

使用 Python 将内存中读取的密钥进行处理,去掉开头的 0x 并把四行合并为一行,即可获得可以使用的密钥,代码如下:

#!/usr/bin/env python3  
  
source = '''  
0x60000181d720: 0xe5 0x16 0xc0 0x2a 0x53 0xe3 0x44 0x58
0x60000181d728: 0x97 0x4a 0xbf 0x59 0x22 0xf1 0x8a 0x59
0x60000181d730: 0x4b 0x2a 0xe2 0x3e 0x44 0x8b 0x4e 0x55
0x60000181d738: 0x9c 0x40 0xd8 0xb6 0x74 0xf9 0xdc 0xd4 
'''  
  
key = '0x' + ''.join(i.partition(':')[2].replace('0x', '').replace(' ', '') for i in source.split('\n')[1:5])  
print(key)

最后输出密钥:0xe516c02a53e34458974abf5922f18a594b2ae23e448b4e559c40d8b674f9dcd4

导出聊天记录文件

为了能够打开数据库文件进行导出操作,需要下载 DB Browser for SQLite 进行操作。下载并安装完成之后,就该去寻找微信的数据库文件了。此处就不用通过 Finder 一层层地去找了,有一个简单的办法可快速找到数据库文件位置:打开任意聊天记录,选择图片或者文件,直接右键点击「在 Finder 中显示」即可。

为了避免在操作过程中因为错误操作损坏数据库文件,建议先退出微信。将 msg 数据库文件从 msg_0.db 到 msg_9.db 十个数据库文件单独拷贝出来操作。此处使用命令实现,如果读者对 Unix 命令比较陌生,也可以按照注释操作手动创建文件夹,复制数据库文件。

# 在桌面上创建 WeChatDB 目录  
mkdir ~/Desktop/WeChatDB  
  
# 切换到数据库文件所在的目录,不要直接复制此处的路径,直接从 Finder 拉到终端里  
cd /Users/james/Library/Containers/com.tencent.xinWeChat/Data/Library/Application\ Support/com.tencent.xinWeChat/2.0b4.0.9/5a22781f14219edfffa333cb38aa92cf/Message  
  
# 把所有的 msg 数据库文件拷贝到 WeChatDB 目录  
cp msg*.db ~/Desktop/WeChatDB  
  
# 在 WeChatDB 目录里创建空文件夹,从 db0 到 db9  
mkdir ~/Desktop/WeChatDB/db{0..9}

最终效果如下图所示,把所有的 db 数据库文件都拷贝到新建的 WeChatDB 目录下,并创建了从 db0 到 db9 十个空文件夹。
使用 DB Browser for SQLite 任意打开一个数据库文件,此处有三个注意点:

  • 密码类型:选择「原始密钥」

  • 密码,第一种使用 ptrsx-dumper 获取到的密码前面没有 0x 字符,需要自己手动加上,第二种 Python 解析出来的密码可以直接使用,例如此处作者填写的密码就是:0xe516c02a53e34458974abf5922f18a594b2ae23e448b4e559c40d8b674f9dcd4

  • 加密设置:选择「SQLCipher 3 默认」

正确设置三个值以后,就可以回车解密微信聊天记录了,进入之后看到如下的界面:

切换到「浏览数据」选项,通过选择不同表就可以查看和不同好友之间的聊天记录,如下所示就是一份聊天记录。其中模糊部分就是聊天信息的具体内容。

数据表字段含义

每一个Table代表你与一个人/群的聊天记录。

  • mesLocalID:primary key,

  • mesMesSvrID:服务端消息ID,

  • msgCreateTime:消息创建时间(Unix time)

  • msgContent:消息内容(格式为普通文本或XML)

  • msgStatus:消息状态(3表示发送出去的消息,4表示收到的消息)

  • msgImgStatus:图片状态

  • messgaeType:消息类型(1表示普通文本,3表示图片,34表示语音,43表示视频,47表示表情包,48表示位置,49是分享消息)

  • msgSource:消息来源(仅针对收到的消息)

查找与指定好友聊天数据

根据前面的分析已经知道,每一个Table Name中的ID代表的就是聊天对象(人/群/讨论组)。这个ID是通过MD5编码得到的。在聊天记录文件的上一级目录可以找到Contact文件夹,这个文件夹中存储的数据库是我们微信号中的好友信息,在我的电脑中这个文件的名字是wccontact_new2.db

用DB Browser打开这个数据库文件,密钥和之前获得的相同。得到的数据库如下图所示(隐藏了敏感信息):

  • m_nsUsrName: MD5加密前的ID(gh表示公众号,wxid表示,qq表示)

  • nickname: 好友昵称

  • m_nsFullPY: 好友昵称拼音

  • m_nsRemark: 好友备注

  • m_nsRemarkPYFull: 好友备注拼音

  • m_nsRemarkPYFullShort: 好友备注拼音缩写

  • m_ui_Sex: 好友性别 (1为男,2为女)

  • m_nsAliasName: 微信号

找到特定好友的MD5编码,只需要执行一个简单query:

# 根据微信号获取User Name
SELECT m_nsUsrName AS UserName
FROM WCContact       
WHERE m_nsAliasName = '<好友的微信号>'

将得到的m_nsUsrName进行MD5编码,可以使用Python的hashlib库进行编码,或者直接百度MD5编码找一些在线网站。编码出来的结果就是每一个Table Name中的ID了。

import hashlib 

str2hash = "<m_nsUsrName>"
  

result = hashlib.md5(str2hash.encode()) 
  
print("The hexadecimal equivalent of hash is : ", end ="") 
print(result.hexdigest()) 

发表回复

后才能评论

评论(1)