微信DAT图片解密:用Python批量还原为JPG/PNG
平时用微信电脑版久了总会遇到一个尴尬场景聊天里别人发来的图片、自己保存的截图明明在文件夹里找到了后缀却全是.dat双击根本打不开。用图片查看器强行打开只会提示“文件格式无效”或者直接花屏。想导出来做备份、做素材、发到别的群聊都无从下手。这篇文章就是把我自己处理这个问题的完整过程记录下来从搞懂 DAT 文件到底是什么到写脚本批量还原成 JPG、PNG再到处理新老版本微信目录不一致、文件被占用、图片损坏等一堆实际坑。整个过程不依赖任何商业付费工具一个 Python 脚本就能搞定适合遇到同样问题的普通用户也适合想了解文件结构原理的技术爱好者参考。1. 先搞清楚 DAT 文件里到底装了什么很多人的第一反应是“微信用了个特殊格式存图片”其实不完全是。DAT 本身不是一种图片编码格式它更像一个“套了壳”的容器。微信电脑版在接收或生成图片后会把它从原来的 JPG、PNG、GIF 等格式“加密”成 DAT 文件再落到磁盘上。这个“加密”并不是严格的加密算法而是非常原始的异或XOR处理。1.1 微信为什么要把图片改成 DAT微信这么做的核心原因有两个第一不让用户直接通过文件夹浏览的方式轻易翻看聊天图片避免本地文件被轻易窃取和传播算是一种很初级的防盗用手段第二统一存储格式方便客户端读取时做统一的解密处理无论原图是 JPG 还是 PNG到了磁盘上都是一个样子。但这个保护级别非常低。DAT 文件的头部没有任何自定义文件头也不包含加密密钥信息加密过程本质上就是对原始图片文件的每个字节做一次异或运算。异或有一点特性(A XOR K) XOR K A同一个密钥对同一个数据做两次异或就能回到原始数据。这也决定了只要找到密钥还原就是瞬间的事。1.2 异或加密的判断思路与密钥猜测实际处理 DAT 文件时第一步是判断密钥。虽然每个 DAT 文件都“长得很随机”但文件的前两三个字节暴露了规律。常见图片格式都有固定的文件头图片格式文件头十六进制JPG/JPEGFF D8 FFPNG89 50 4EGIF47 49 46BMP42 4D我随便找一个 DAT 文件用十六进制编辑器打开前三个字节是A9 A6 A9。这时用0xA9跟 JPEG 文件头的0xFF做异或0xA9 XOR 0xFF 0x56。再用0xA9跟 PNG 文件头的0x89做异或0xA9 XOR 0x89 0x20没法对上了。那基本可以确定密钥是0x56原始文件是 JPEG。如果密钥猜的是0x56那么你可以验证第二字节0xA6 XOR 0xD8 0x7E这不对等一下我拿到的文件头是A9 A6 A90xA9 XOR 0xFF 0x56接着0xA6 XOR 0x56 0xF0也不是0xD8所以这个具体文件不一定就是前面说的样例实际操作中就要多试几个文件、多试几种头组合来定位。其实更稳妥的做法是直接读取 DAT 文件前两个字节分别与各种常见图片头的第一个字节做异或得到的两个密钥一致时基本就能断定密钥和原始格式。例如第一字节0xA9与 JPEG 头0xFF异或 0x56第二字节0xA6与 JPEG 头0xD8异或 0x7E。这两个密钥不一致说明这个 DAT 可能不是 JPEG 类型再用 PNG 试0xA9 XOR 0x89 0x200xA6 XOR 0x50 0xF6也不一致再用 GIF 试0xA9 XOR 0x47 0xEE0xA6 XOR 0x49 0xEF不一致。如果那个文件恰好前两字节是A9 A6对照 JPEG 和 PNG 都不满足那么需要多看几个文件。真正处理时网上常见的说法是微信图片 DAT 加密字节就是0x56但也有不少文件是0xAE、0x8A等所以脚本里不能写死密钥必须动态探测。还有一个傻瓜式办法取 DAT 文件的前四个字节分别与所有常见图片格式的文件头字节做异或能匹配上的候选密钥就保留再用候选密钥对整个文件做异或看输出文件头是否合法合法就说明猜对了。2. 微信文件目录的定位与新老版本差异搞定了原理接下来就是找到 DAT 文件在哪。这个坑不少人都踩过网上教程说在我的文档\WeChat Files里但自己电脑上死活找不到。原因很简单——微信电脑版近几年出了 4.x 新版本存储目录结构改了。2.1 老版本微信的目录结构如果你用的还是 3.x 或更早的版本默认路径一般是C:\Users\你的用户名\Documents\WeChat Files\微信号\FileStorage\Image\2024-01\Image目录下按月份分子目录里面有两种文件一是年-月-日编号的 DAT 文件二是名字类似xxx.dat、通篇乱码无法查看的缩略图文件。原图和缩略图都混在一起如果只用微信自带的“打开文件夹”功能你会看到一串.dat文件根本没有后缀名提示哪种是原图。2.2 新版本微信的目录变化到了 4.x 版本新的存储路径变成了C:\Users\你的用户名\Documents\xwechat_files\微信号\msg\attach\一串随机字符\Image\2024-01\注意几点第一目录名从WeChat Files变成了xwechat_files第二FileStorage没了变成了msg\attach第三Image之前的父目录是一串随机字符不是微信号。不同电脑可能还不一样所以最靠谱的定位方法是打开电脑版微信的“设置”找到“文件管理”或“存储空间”里面会显示一条详细的存储路径直接点“打开文件夹”最快。2.3 老版本和新版本数据需要整合怎么办升级新版本之后微信一般会把旧数据迁移过来但有些人因为备份、换电脑、手动拷贝老文件夹新版本里找不到历史聊天图片。这时候需要做的是手动把老目录里的FileStorage\Image整个拷贝到新目录的msg\attach\xxx\Image下。但直接放进去不一定被识别。一种比较常见的整合方法先把老目录里的 DAT 文件全部还原成 JPG/PNG再把还原后的图片导入新版本微信能识别的文件里。比如把还原后的图片发到“文件传输助手”里再保存或者放到新目录的对应月份文件夹里。如果你只是想让图片能看、能整理那先转换出来再归档其实比依赖微信目录更省心。我自己处理几千张老聊天图片时就是先全部转成 JPG单独建了一个“微信聊天图片备份”文件夹再也没指望微信自己能认识这些老文件。2.4 其他平台路径差异Windows 版微信的路径最麻烦macOS 和 Linux 版微信也会保存 DAT 文件但路径一般是~/Library/Containers/com.tencent.xinWeChat/Data/Library/Application Support/com.tencent.xinWeChat/或类似的深层目录原理和转换方式完全一样后面讲到的脚本可以通用。3. 用 Python 批量将 DAT 还原为常见图片脚本实现有两种思路一种是“写死密钥”速度快但碰到不同密钥就废了另一种是“自动探测密钥”通用性更强。我推荐自动探测代码也没复杂多少。下面是我实际用过的脚本稍微整理过可以直接抄。3.1 自动探测密钥的核心逻辑完整脚本如下Python 3.6 就能跑不需要额外安装第三方库import os import struct import sys IMAGE_HEADERS { b\xff\xd8\xff: jpg, b\x89\x50\x4e: png, b\x47\x49\x46: gif, b\x42\x4d: bmp, } def find_key(dat_file): with open(dat_file, rb) as f: head f.read(4) if len(head) 3: return None, None for magic, ext in IMAGE_HEADERS.items(): # magic 长度可能为2或3取相同位数的DAT头部字节做异或 key None match True for i in range(len(magic)): if i len(head): match False break if key is None: key head[i] ^ magic[i] elif head[i] ^ magic[i] ! key: match False break if match and key is not None: return key, ext return None, None def convert_dat(dat_path, output_dir): key, ext find_key(dat_path) if key is None: print(f[跳过] 无法识别密匙{dat_path}) return False new_name os.path.splitext(os.path.basename(dat_path))[0] . ext out_path os.path.join(output_dir, new_name) with open(dat_path, rb) as f_in: data f_in.read() decoded bytes([b ^ key for b in data]) with open(out_path, wb) as f_out: f_out.write(decoded) print(f[成功] {dat_path} - {out_path}) return True def main(): if len(sys.argv) 2: print(用法: python wechat_dat_converter.py DAT目录或文件 [输出目录]) sys.exit(1) src sys.argv[1] if len(sys.argv) 3: dst sys.argv[2] else: dst os.path.join(os.path.dirname(src), converted) os.makedirs(dst, exist_okTrue) dat_files [] if os.path.isfile(src) and src.lower().endswith(.dat): dat_files [src] elif os.path.isdir(src): for root, _, files in os.walk(src): for name in files: if name.lower().endswith(.dat): dat_files.append(os.path.join(root, name)) print(f共找到 {len(dat_files)} 个 DAT 文件) success 0 for dat in dat_files: if convert_dat(dat, dst): success 1 print(f转换完成成功 {success} 个失败 {len(dat_files) - success} 个) if __name__ __main__: main()脚本逻辑说明一下find_key函数读取每个 DAT 文件的前四个字节逐个跟常见图片头做异或比对。如果前几个字节异或出来的密钥都相同就认为猜到了密钥和格式。convert_dat拿到密钥后用列表推导式对每个字节做一次异或加密就变成了解密。最后输出到指定目录文件名保留原 DAT 的文件名只改后缀。3.2 实际操作步骤从定位到出图拿我自己整理某台旧电脑的微信记录举例。第一步打开微信电脑版“设置 - 存储空间 - 打开文件夹”定位到实际路径当时我的路径是C:\Users\laoWang\Documents\xwechat_files\wxid_xxxxxxxx\msg\attach\7d3f2a1b9c\Image\2023-05\第二步把整个Image目录复制到待处理目录比如E:\wechat_temp\。拷贝时建议先退出微信电脑版否则个别正在写入的文件可能显示“正在被占用”虽然跳过也不影响大多数文件但强迫症会很难受。第三步打开终端运行命令python wechat_dat_converter.py E:\wechat_temp\Image E:\wechat_export\脚本会递归遍历Image下所有 DAT 文件逐个转换。我那次一共 1847 个 DAT成功转换 1839 个失败 8 个失败的全是长度为 0 或只有几十字节的残留文件本来就是损坏的直接忽略就行。第四步打开输出目录验证一下。重点看看文件大小是否正常能不能正常预览。如果出现“转换成功但打不开”的情况多半是密钥探测错误后面会专门说。3.3 不用 Python 的其他方案不是每个人都愿意装 Python这里额外提两个替代方案。第一个方案是使用现成的 GUI 转换工具。网上有一些开源的小工具比如“微信图片解密工具”“WeChatDAT2Img”等界面比较简单选目录、选输出路径、点转换就行。它们本质上就是做了上面脚本做的事只是封装成了图形界面。这类工具要注意来源安全性尽量找开源仓库自行编译或下载别在不知名网站随便下 exe。第二个方案是使用十六进制编辑器手工还原单张图片。比如用 HxD 或 010 Editor 打开 DAT 文件人工判断密钥然后用编辑器的“按字节异或”功能把整个文件转换一遍保存为 .jpg。只处理个位数文件时可以这么干大量文件就不要手工折腾了。4. 转换过程中的常见问题与排查实录这个项目折腾下来我遇到过的问题能列一长串挑典型的几个说一下。4.1 为什么有些“转换成功”的图片还是打不开最常见的原因是密钥探测出错。比如某些 DAT 文件本来就是损坏的、被截断的或者微信在特殊情况下写入的文件头不是标准图片头脚本按错误密钥强行异或后能生成一个 JPG 文件但内容完全是乱的。判断办法是看输出文件的大小和原 DAT 是否一样再随便找个图片查看器预览打不开就是废图。这类文件基本没有抢救价值直接从原图缓存或聊天记录里重新拉取更现实。还有一种情况同一个 DAT 文件里其实是 GIF 或 BMP脚本探测到了密钥却选错了扩展名。比如 GIF 文件头47 49 46和 PNG 文件头89 50 4E如果 DAT 头部字节恰巧某种组合下多个格式都能得出同一个密钥脚本可能输出.png但实际内容是 GIF。判断方法是直接改扩展名试试或者用file命令检查实际文件类型。我在脚本里用的是“第一优先级匹配”对绝大多数场景已经够用。4.2 微信正在运行导致文件无法读取批量转换时微信如果不退出Image目录下会有部分文件处于写保护状态脚本读取会报PermissionError。解决方案很简单转换之前完全退出微信电脑版不只是关窗口还要在右下角托盘图标上右键点击退出。另外如果你在“文件管理”里看到某个 DAT 文件大小一直在变说明微信还在往里面写内容这种文件就算读出来也是半截图。4.3 新老版本目录不一致怎么处理才不会转漏很多人的电脑上可能同时存在旧版本的WeChat Files和新版本的xwechat_files尤其是从旧版升级上来后微信可能没有迁移全部历史数据或者你在不同时期手动设置过不同的存储路径。处理这种问题时最笨也最稳的方法是把所有存储目录下的所有Image文件夹都找出来分别转换最后按时间排序做去重。我在脚本里使用了os.walk递归遍历不管目录多深都能扫到。实际操作时建议先扫描一遍所有可能的微信数据目录看看路径大小再决定合并方式。如果你有多个微信号的历史数据每个微信号下的Image目录都要单独处理因为不同的微信号虽然加密方式相同但目录完全独立。4.4 缩略图和原图混在一起怎么区分Image文件夹下有些文件大小只有几百字节到几 KB这些是微信的缩略图缓存。转换出来之后一样可以看但分辨率很低。想导出原图的人需要按文件大小筛一遍一般大于 50 KB 的才值得保留。我习惯用文件管理器按“大小”排序把小于 50 KB 的删掉或者放另一个目录。如果你有编程基础也可以在脚本里加一个min_size参数小于指定大小的 DAT 直接跳过或单独输出。4.5 手机端聊天图片不在这里这个方法只适用于电脑版微信接收并缓存的图片。手机端微信的存储机制完全不同安卓的图片缓存一般在内部存储的tencent/MicroMsg/...目录下iOS 因为沙箱机制更麻烦基本只能靠微信自带的“存储空间-管理聊天记录”清理或导出。别拿电脑版的方法硬套到手机上这是很多人最容易踩的误区。4.6 转换后的图片还能不能重新导回微信这个问题经常有人问。答案是能。转换回来的是标准 JPG/PNG/GIF 图片你可以通过微信“文件传输助手”发给自己或者直接作为文件发送给好友。但要注意微信在发送新图片时会重新压缩并加密保存所以再次在电脑上找生成的又是新的 DAT 文件路径和时间也不一样。把转换出来的图片作为日常备份、素材、归档是没问题的想保留聊天原始时间线最好连微信的聊天记录数据库一起备份。5. 补充一个批量重命名与归档的小技巧转换完成后的文件名通常是原 DAT 的文件名类似2023-05-12_132233.dat去掉 .dat 后缀后还带下划线时间戳这个文件名排序还算方便。但如果你的 DAT 文件名是纯字母加数字随机串比如f3a2b9c8e0d1_0001.dat排序就不直观了。我一般会再写一个小脚本把转换后的图片按日期归档到月份目录里顺便去重。import os import shutil import datetime def organize_images(src_dir, dst_dir): for name in os.listdir(src_dir): if not name.lower().endswith((.jpg, .png, .gif, .bmp)): continue file_path os.path.join(src_dir, name) mtime os.path.getmtime(file_path) dt datetime.datetime.fromtimestamp(mtime) month_dir os.path.join(dst_dir, dt.strftime(%Y-%m)) os.makedirs(month_dir, exist_okTrue) target os.path.join(month_dir, name) if os.path.exists(target): base, ext os.path.splitext(name) target os.path.join(month_dir, f{base}_{int(mtime)}{ext}) shutil.move(file_path, target) organize_images(rE:\wechat_export, rE:\wechat_final)这段脚本按文件的修改时间把图片归档到年-月目录里如果同名文件已经存在就加时间戳后缀避免覆盖。不过有一点要注意DAT 的修改时间并不一定是聊天发送时间而是微信写入缓存的时间好在通常相差不大归档完全够用。6. 几点额外的心得与建议整个流程熟悉之后你会发现“DAT 转 JPG”这件事本质上就是一道异或解密题技术含量并不高真正麻烦的是目录定位、批量文件处理和损坏文件的甄别。我个人处理完几千张图片后有几个体会第一微信的本地图片是按“当月缓存”模型保存的长期不登录、清理过缓存或者聊天记录被手动删除过部分 DAT 文件就会消失所以重要图片定期转换备份才是正途。第二批量处理前一定要先拷贝整个目录再操作不要在微信原目录上原地转换万一脚本出问题微信客户端可能直接读不到缓存图片。第三Windows 下如果路径里有中文、空格命令行运行时要把路径用英文双引号包起来否则很容易报找不到文件。如果你也用微信电脑版存了大量聊天图片现在就可以动手试试先打开微信设置里的文件路径看看里面有多少 DAT 文件跑一次上面的脚本把图片导出来归档。整个过程半小时以内能搞定。工具方面建议优先用 Python 脚本因为它可定制、可复用换台电脑、换个目录一键就能跑。实在不想折腾脚本找个可靠的开源 GUI 工具也能解决但原理还是这一套。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →