目前全网最全的微信4.x版本.dat格式图片解密(包含WxAM解密)
免责声明:本文仅供学习使用,请遵守相关法律法规。
本文章仅适用于微信4.x版本。
零、背景
女朋友发了张照片光速撤回导致我没看见。
(后注:4.x的微信在撤回消息后缓存文件会立即删除,因此无法还原)
最近tx封杀的好像很严,有关的资料越来越少,所以就想写一篇讲的比较全面文章从头到尾分析一遍。
本篇文章仅讨论如何解密 .dat 文件,不涉及包含聊天记录的数据库解密。
一、文件结构
4.x的微信的用户数据(聊天图片)可以在 %userprofile%/xwechat_files/wxid_xxx/msg/attach 里找到。
attach 文件夹是按照聊天对象(用户)去分类的,每个子文件夹里 Img 文件夹内存的就是缓存图片,后缀是 .dat。一个图片可能会有2个(或3个)对应的 .dat,其中文件名带 _t 的是缩略图。
二、第一层加密
2.1 加密方式
目前微信在不同版本对 .dat 的加密方式是不同的。
旧版本是纯xor,后来是xor+固定aes进行加密,而4.x是xor+动态aes加密(.dat 文件头将此加密称为V2)。
关于纯xor,就是把图片的二进制数据按位异或上一个特定值(一般是0x51或0x50,并非硬编码,可能有差异)。解密也相当容易,只需要把 .dat 再异或一次就可以。
2.2 key的获取
xor_key 的获取,在纯xor时代可以通过 png 或者 jpeg 的文件头特征码在 .dat 里反推得到,因为xor运算是可逆的。
V2不能再通过文件头,而是通过文件尾特征码反推,因为头是AES加密的。
(请注意一定要使用缩略图(文件名带 _t)反推xor,因为原图是经 WxAM 压缩过的,导致文件尾无特征码。)
aes_key 目前不清楚,应该可以靠暴力扫内存得到。
这两个key都可以用现有还存活着的(截止至2026.01.23)ycccccccy/wx_key 获取,具体方法不过多赘述。后续可能会在这里补充。
2.3 V2解密 & Approaching
根据找到现有的逆向代码分析,V2应该是通过aes、明文、xor三者拼接的方式完成加密的。用一个图直观的表示长这样:

文件头会定义一个 aes_size 和 xor_size,也就是aes和xor分别加密的长度(字节)。然后分段解密并拼接就可以得到原文件的二进制。
前15(0x00-0x0e)字节是头,其中:
- 0x00-0x05是V2标识符:
0x07 08 56 32 08 07(\x07\x08V2\x08\x07); - 0x06-0x09是
aes_size(unsigned long); - 0x0A-0x0D是
xor_size(unsigned long); - 0x0E为占位符。

from Crypto.Cipher import AES
from Crypto.Util import Padding
def aesDecrypt(data):
header, body = data[:0xF], data[0xF:]
_, aes_size, xor_size = struct.unpack("<6sLLx", header)
# Decrypt AES
aes_size += AES.block_size - aes_size % AES.block_size # 此处需要补一下 padding
cipher = AES.new(AES_KEY, AES.MODE_ECB)
aesData = Padding.unpad(cipher.decrypt(body[:aes_size]), AES.block_size)
# Decrypt XOR
if xor_size:
rawData = body[aes_size:-xor_size]
unXORData = bytes(i ^ XOR_KEY for i in body[-xor_size:])
else:
rawData = body[aes_size:]
unXORData = b""
return aesData + rawData + unXORData
2.4 限制
解密后的文件,一般来说如果是缩略图,那就可以直接查看了。
而如果是原图,你会发现这个文件是打不开的,看它的二进制数据也没有图片格式的特征头。这是因为微信使用 WxAM 对其进行了压缩,此时就需要进行第二层解密,也就是下文所说的内容。
三、第二层加密(WxAM)
3.1 关于WxAM(wxgf)
目前网络上对其的介绍极少,应该是微信内部的文件格式。其旨在对文件进行极限压缩。
从结果来看确实是的,有些图片的压缩率甚至能达到50%以上。
3.2 关于逆向
微信的 WxAM 实现在根目录下一个名为 VoipEngine 的 dll 文件中。本人不会逆向,详细的逆向过程可以去看 WXAM(WXGF)图片格式解析。
总之可以找到一个入口点 wxam_dec_wxam2pic_5(),然后用 ctypes 去调用 dll 就可以了。
3.3 文件头
wxgf 格式有也有自己的文件头,为 77 78 67 66(wxgf)。

因此如果想要检验第一层解密后的文件是不是 wxgf 格式,可以通过 startswith() 判断。
3.4 Approaching
wxam_dec_wxam2pic_5() 入口点接受5个参数,分别是(描述可能有误):
wxgf二进制数据(int64)wxgf字节长度(int)- 解析后的二进制输出(
int64) - 解析后的字节长度(
pointer->int) - 配置项(
Config)(int64)
返回一个 int64。
关于 Config:
mode 代表解析格式,0 为 jpeg,1/2 为 png,3 为 gif。
部分代码实现来自 LifeArchiveProject/WeChatDataAnalysis。
from ctypes import *
voip = WinDLL(DLL_PATH).wxam_dec_wxam2pic_5
class Config(Structure):
_fields_ = [
("mode", c_int),
]
def wxgf2byte(data):
maxSize = 64 * 1024 * 1024
for i in [1, 2, 0, 3]:
try:
config = Config()
config.mode = i
inputBuffer = create_string_buffer(data, len(data))
outputBuffer = create_string_buffer(maxSize)
outputSize = c_int(maxSize)
result = voip(
addressof(inputBuffer),
int(len(data)),
addressof(outputBuffer),
byref(outputSize),
addressof(config),
)
if result != 0 or outputSize.value <= 0:
continue
output = outputBuffer.raw[:int(outputSize.value)]
return output
except Exception as e:
continue
return False
四、格式检查
很容易,可以通过文件头(或文件尾)检查。附注一些常用的格式:
png:89 50 4E 47/AE 42 60 82jpeg:FF D8 FF/FF D9gif:47 49 46 38/00 3B
五、尾声
由于加密算法具有时效性,此种方法在后续版本中可能不再可用。
本文的一些细节还有待完善,可能会不定期更新。
再次免责声明:本文仅供学习使用,请遵守相关法律法规。
Reference / 参考
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)