异想之旅:本人原创博客完全手敲,绝对非搬运,全网不可能有重复;本人无团队,仅为技术爱好者进行分享,所有内容不牵扯广告。本人所有文章仅在CSDN、掘金和个人博客(一定是异想之旅域名)发布,除此之外全部是盗文!


相关内容:

  • 微信PC端数据库文件解密_微信电脑版db文件解密_异想之旅的博客-CSDN博客
  • 微信PC端各个数据库文件结构与功能简述 - 根目录_微信用了哪些数据库_异想之旅的博客-CSDN博客

Multi文件夹中的文件解码和之前的其它数据库操作相同。

该文件夹中文件结构比较简单,只有三种:FTSMSGMediaMSGMSG。这里说是三种不是三个,是因为这里的数据库达到一定大小后会拆分。

FTSMSG

看过《总述》一文的应该很熟悉 FTS 这一前缀了——这代表的是搜索时所需的索引。

其内主要的内容是这样的两张表:

  • FTSChatMsg2_content:内有三个字段

    • docid:从1开始递增的数字,相当于当前条目的 ID
    • c0content:搜索关键字(在微信搜索框输入的关键字被这个字段包含的内容可以被搜索到)
    • c1entityId:尚不明确用途,可能是校验相关
  • FTSChatMsg2_MetaData
    • docid:与FTSChatMsg2_content表中的 docid 对应
    • msgId:与MSG数据库中的内容对应
    • entityId:与FTSChatMsg2_content表中的 c1entityId 对应
    • type:可能是该消息的类型
    • 其余字段尚不明确

特别地,表名中的这个数字2,个人猜测可能是当前数据库格式的版本号。

MediaMSG

这里存储了所有的语音消息。数据库中有且仅有Media一张表,内含三个有效字段:

  • Key
  • Reserved0
  • Buf

其中Reserved0字段MSG数据库中消息的MsgSvrID一一对应

第三项即语音的二进制数据,观察头部即可发现这些文件是以 SILK 格式存储的。这是一种微软为 Skype 开发并开源的语音格式,具体可以自行 Google。

下面是将 Buf 字段中的数据导出为文件的代码:

import sqlite3def writeTofile(data, filename):with open(filename, 'wb') as file:file.write(data)print("Stored blob data into: ", filename, "\n")def readBlobData(key):try:sqliteConnection = sqlite3.connect('dbs/decoded_MediaMSG0.db')cursor = sqliteConnection.cursor()print("Connected to SQLite")sql_fetch_blob_query = """SELECT * from Media where Key = ?"""cursor.execute(sql_fetch_blob_query, (key, ))record = cursor.fetchall()for row in record:print("Key = ", row[0], "Reserved0 = ", row[1])file = row[2]print("Storing on disk \n")path = f'{row[0]}.silk'writeTofile(file, path)cursor.close()except sqlite3.Error as error:print("Failed to read blob data from sqlite table", error)finally:if sqliteConnection:sqliteConnection.close()print("sqlite connection is closed")readBlobData(1099511630953)

如果需要通过MSG数据库中的MsgSvrID找文件,则改一下 SQL 查询语句,再遍历所有数据库即可。

下面是将 silk 文件转为 wav 的代码(实现思路是先转为 pcm 再转 wav;wav 的采样率数据是个人试出来的):

KEY = 1099511630953import wave
from pathlib import Pathimport pilkdef pcm2wav(pcm_file, wav_file, channels=1, bits=16, sample_rate=24000):pcmf = open(pcm_file, 'rb')pcmdata = pcmf.read()pcmf.close()if bits % 8 != 0:raise ValueError("bits % 8 must == 0. now bits:" + str(bits))wavfile = wave.open(wav_file, 'wb')wavfile.setnchannels(channels)wavfile.setsampwidth(bits // 8)wavfile.setframerate(sample_rate)wavfile.writeframes(pcmdata)wavfile.close()duration = pilk.decode(f"{KEY}.silk", f"{KEY}.pcm")
# print("语音时间为:", duration)
Path(f"{KEY}.silk").unlink()pcm2wav(f"{KEY}.pcm", f"{KEY}.wav")
Path(f"{KEY}.pcm").unlink()

这两个代码没有加详细解释,自己读一下吧。

MSG

终于到了整个文件,不,整个工程最重要的位置了——聊天记录核心数据库

内部主要的两个表是MSGName2ID

其中Name2ID这张表只有一列,内容格式是微信号群聊ID@chatroom,作用是使MSG中的某些字段与之对应。虽然表中没有 ID 这一列,但事实上微信默认了第几行 ID 就是几(从1开始编号)。

下面主要来说MSG这张表(加粗是用于提醒自己内容待补充,并非是重要信息):

  • localId:字面意思消息在本地的 ID,暂未发现其功用
  • TalkerId:消息所在房间的 ID(该信息为猜测,猜测原因见 StrTalker 字段),与Name2ID对应。
  • MsgSvrID:猜测 Srv 可能是 Server 的缩写,代指服务器端存储的消息 ID
  • Type:消息类型,具体对照见表1
  • SubType:消息类型子分类,暂时未见其实际用途
  • IsSender:是否是自己发出的消息,也就是标记消息展示在对话页左边还是右边,取值0或1
  • CreateTime:消息创建时间的秒级时间戳。此处需要进一步实验来确认该时间具体标记的是哪个时间节点,个人猜测的规则如下:
    • 从这台电脑上发出的消息:标记代表的是每个消息点下发送按钮的那一刻
    • 从其它设备上发出的/收到的来自其它用户的消息:标记的是本地从服务器接收到这一消息的时间
  • Sequence:次序,虽然看起来像一个毫秒级时间戳但其实不是。这是 CreateTime 字段末尾接上三位数字组成的,通常情况下为000,如果在出现两条 CreateTime 相同的消息则最后三位依次递增。需要进一步确认不重复范围是在一个会话内还是所有会话
  • StatusEx、FlagEx、Status、MsgServerSeq、MsgSequence:这五个字段个人暂时没有分析出有效信息
  • StrTalker:消息发送者的微信号。特别说明,从这里来看的话,上面的 TalkerId 字段大概率是指的消息所在的房间ID,而非发送者ID,当然也可能和 TalkerId 属于重复内容,这一点待确认
  • StrContent:字符串格式的数据。特别说明的是,除了文本类型的消息外,别的大多类型这一字段都会是一段 XML 数据标记一些相关信息。
  • DisplayContent:对于拍一拍,保存拍者和被拍者账号信息
  • Reserved0~6:这些字段也还没有分析出有效信息,也有的字段恒为空
  • CompressContent:字面意思是压缩的数据,实际上也就是微信任性不想存在 StrContent 里的数据在这里(例如带有引用的文本消息等;这里的消息只能根据二进制分辨出包含什么,但是具体格式规范、如何取出数据本人不知)
  • BytesExtra:额外的二进制格式数据
  • BytesTrans:目前看这是一个恒为空的字段

这里面的猜测内容比较多,还有很多标注了应该进一步实验的还没有完成,是因为由于数据库解开后不可能随新收到的消息实时更新,而每次新发送一条消息也不知道它会出现在拆分后的哪个数据库中,因此实验效率极低。

表1:MSG.Type字段数值与含义对照表(可能可以扩展到其它数据库中同样标记消息类型这一信息的字段)

分类 子分类 对应类型
1 0 文本
3 0 图片
34 0 语音
43 0 视频
47 0 动画表情(第三方开发的表情包)
49 1 类似文字消息而不一样的消息,目前只见到一个阿里云盘的邀请注册是这样的。估计和 57 子类的情况一样
49 5 卡片式链接,CompressContent 中有标题、简介等,BytesExtra 中有本地缓存的封面路径
49 6 文件,CompressContent 中有文件名和下载链接(但不会读),BytesExtra 中有本地保存的路径
49 8 用户上传的 GIF 表情,CompressContent 中有 CDN 链接,不过似乎不能直接访问下载
49 19 合并转发的聊天记录,CompressContent 中有详细聊天记录,BytesExtra 中有图片视频等的缓存
49 33/36 分享的小程序,CompressContent 中有卡片信息,BytesExtra 中有封面缓存位置
49 57 带有引用的文本消息(这种类型下 StrContent 为空,发送和引用的内容均在 CompressContent 中)
49 63 视频号直播或直播回放等
49 87 群公告
49 88 视频号直播或直播回放等
49 2000 转账消息(包括发出、接收、主动退还)
49 2003 赠送红包封面
10000 0 系统通知(居中出现的那种灰色文字)
10000 4 拍一拍
10000 8000 系统通知(特别包含你邀请别人加入群聊)

本文参考资料(排名不分先后):

  • python使用技巧(二十七):音频WAV和PCM的互相转换_python pcm转mp3_源代码杀手的博客-CSDN博客
  • foyoux/pilk: python silk codec binding 支持微信语音编解码

微信PC端各个数据库文件结构与功能简述 - Multi文件夹相关推荐

  1. 微信PC端各个数据库文件结构与功能简述 - 根目录

    异想之旅:本人原创博客完全手敲,绝对非搬运,全网不可能有重复:本人无团队,仅为技术爱好者进行分享,所有内容不牵扯广告.本人所有文章仅在CSDN.掘金和个人博客(一定是异想之旅域名)发布,除此之外全部是 ...

  2. 微信PC端数据库文件解密

    异想之旅:本人原创博客完全手敲,绝对非搬运,全网不可能有重复:本人无团队,仅为技术爱好者进行分享,所有内容不牵扯广告.本人所有文章仅在CSDN.掘金和个人博客(一定是异想之旅域名)发布,除此之外全部是 ...

  3. 使用微信PC端的截图dll库实现微信截图功能(C++ Builder实现)

    使用微信PC端的截图dll库实现微信截图功能(C++ Builder实现) 网上有很多文章说"使用微信PC端的截图dll库实现微信截图功能",我用node实现截图也要用一下,于是找 ...

  4. 微信PC端有了新功能,快来看看你知不知道

    你们知道微信PC端更新了吗?它新增了几个功能,有兴趣了解的朋友就接着往下看吧. 1.文件路径更清晰 微信之前的文件存储路径,都是一串乱码的文件夹,不便于我们查找和管理. 微信更新后,现在接收到的文件路 ...

  5. 微信PC端技术研究(2)-拿下语音

    微信PC端技术研究-保存聊天语音 by anhkgg(公众号:汉客儿) 2019年1月31日 2.6.6.28 0x0. 前言 虽然一直知道CE,也用过一段时间,但一直用不好,可能太笨. 最近又学习了 ...

  6. 微信PC端技术研究(2)-保存聊天语音

    微信PC端技术研究-保存聊天语音 转载地址: [原创]微信PC端技术研究(2)-保存聊天语音-软件逆向-看雪论坛-安全社区|安全招聘|bbs.pediy.com 0x0. 前言 最近又学习了某位大佬用 ...

  7. 微信PC端测试版更新:新增视频号直播工具

    你知道的越多,不知道的就越多,业余的像一棵小草! 你来,我们一起精进!你不来,我和你的竞争对手一起精进! 编辑:业余草 推荐:https://www.xttblog.com/?p=5155 明天就开始 ...

  8. win7下搭建小程序服务器,重磅!微信PC端支持小程序直接开启 适配Win7及以上系统...

    原标题:重磅!微信PC端支持小程序直接开启 适配Win7及以上系统 腾讯科技讯 8月9日,腾讯科技在"微信开放社区"发现,微信正在测试"PC端支持打开小程序"能 ...

  9. 调试微信 PC 端的内置浏览器界面

    2021-08-03 最新更新 好久没看,微信也更新了好几版.下面的方法并没有失效,不过上了 3.3.x 后的微信版本已经禁用了右键和查看 chrome://version 的功能了.进过实测,最后一 ...

最新文章

  1. 为什么我可以在Java中抛出null? [重复]
  2. C#里调用带输出参数的存储过程
  3. 一道关于回文的笔试题
  4. 判断是否为二叉排序树的递归算法_左神直通BAT算法笔记(基础篇)
  5. 多元正态分布的后验采样(包含程序)
  6. 深度linux安装make,linux下安装python3完整教程(依赖环境gcc,make,cmake,configure等详细解释)...
  7. 正则表达式---采集总结
  8. 那些自媒体视频剪辑素材是怎么找到的?
  9. 本机ip与外网ip(附带查询方法)
  10. 实际使用Windows 7中的Readyboost功能
  11. 微信小程序开发(7)---协同工作篇
  12. Gitea服务器ip变更项目无法创建、拉取、上传
  13. 再见2021,2022加油
  14. EKS使用AWS EFS CSI
  15. html5横竖条纹背景,CSS制作Web页面条纹背景样式的介绍
  16. shell的几个重要命令,主要参数,循环语句以及变量处理
  17. Redis高性能缓存数据库
  18. 5-TAMRA标记LYS赖氨酸,5-TAMRA-Lysine结构式及光谱图分享
  19. 【RFID实训】公交收费系统详细过程
  20. 【华为OD机试真题 JAVA】跳格子游戏

热门文章

  1. 一个计算机专业女孩的求学之路—七年之痒,痒之感悟
  2. scanf函数的用法
  3. 微分几何笔记(4) —— 二维三维空间中曲线的曲率以及环绕数
  4. 芯片之家一周精选,毛线上拉电阻?电容开花了?
  5. 基于偏振差分成像的图像去雾算法
  6. Joint Learning of Deep Retrieval Model and Product Quantization based Embedding Index
  7. SQL语句大全[基础]
  8. 开薪点惊艳中国HR服务峰会 摘得“2017中国HR服务产品创新”奖
  9. RTT-thread 邮箱的管理方式
  10. VMVare中CentOS图形化界面大屏显示的方法(调节屏幕分辨率)