0x00

今天上python课听到老师中途提起说 有很多微信接收的dat文件,但是暂时不清楚如何解密成图片,所以回来准备自己研究研究(折腾折腾),帮老师解决一下问题~

image-20201023111429240

顺便减轻一下上课不听课的愧疚感

0x01 分析

首先找一下微信存储文件的地方在哪里,一通(百度)研究发现存储的路径如下C:\Users\用户\Documents\WeChat Files\wxid_kxxxxxxx\FileStorage\Image

image-20201023112157525

根据文件夹名字也能发现这些文件应该就是加密后的图片文件了,16进制编辑器看一看

image-20201023112329854

image-20201023112358370

发现大部分文件开头都是7D5A, 众所周知jpg格式开头几个字节为0xFFD8, 不如做个异或看看

image-20201023112806409

dat文件和正常jpg文件前两个字节异或结果为0x8282, 推测是不是dat文件所有字节都异或了0x82, 随便挑一个dat文件,把其中所有的字节挨个异或0x82

image-20201023113121771

成功恢复成了图片! 推测是正确的

image-20201023113422257

0x02 发现问题

不过经过测试有时候脚本会失效,Why?

前面还提到有些文件接收后开头不是7D5A,这是非Jpg格式图片加密后的存储,经过研究发现密钥依然是Jpg格式加密的密钥。如果脚本第一次检测的不是Jpg格式的图片的话,就拿不到正确的密钥,自然就失效了

改进函数

根据规律改进一下自动检测密钥的函数,找到一个dat文件后依次与jpg,png,gif的头部做异或,如果异或的前两个字节一样则就确定了密钥

image-20201024030446785

如果脚本失效则手动解决

如果脚本依然失效的话就手动解决,方法就是找一个Jpg格式的图片通过微信传输过去,然后在微信存储图片的那个目录下找到刚刚新增加的dat文件,把这个文件拿去用脚本跑一次,脚本会显示出正确的密钥

image-20201023124546404

然后把这个值填写进脚本的secretKey中即可

image-20201023125004225

0x03 Talk is cheap ,Show the code

使用的时候只需要改inpathout_path两个变量就好了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# @Time    : 2020/10/23 21:54
# @Author : LYC
# @File : 微信Dat文件转图片

# jpg FFD8 xor 7D5A = 8282
#

import os

inpath = r"D:/CTF文件/微信dat文件/"
out_path = r"D:/CTF文件/微信dat文件/"


jpg = 0xFFD8
png = 0x8950
gif = 0x4749

secretKey = 0x00 # 改为 0x00 程序运行时将自动检测秘钥,自动检测如果失效需要手动修改这个值


def autoCheck(path):
global secretKey
if secretKey != 0x00:
pass
else:
print("[*] autoCheck:")
file_List = os.listdir(path)
for file_Name in file_List:
file_WithPath = os.path.join(path, file_Name)
if file_WithPath.endswith("dat"):
print(f"[*] 检测dat文件: {file_Name}")
with open(file_WithPath, "rb") as raw_DatFile:
#head2Byte = raw_DatFile.read(2)
head2Byte = int.from_bytes(raw_DatFile.read(2), byteorder='big') # 获取前两个字节
for i in [jpg,png,gif]: # 分别和各种格式做异或
LowByte = (head2Byte ^ i) >> 8
HighByte = (head2Byte ^ i) & 0x00FF
if LowByte == HighByte : # 找到秘钥
secretKey = LowByte
print(f"[*] SecretKey: {hex(secretKey)}")
break
break
else:
pass
if secretKey == 0x00: # 检测不到秘钥手动输入
while True:
try:
secretKey = int(input("[#] 未找到秘钥,可手动输入(例如0x82): "),16)
except:
print("格式错误,正确格式如: 0x82")
else:
break

# 检查一共有多少种类型的文件
def checkFileTypes(path):
print(f"[*] 当前目录: {path}")
fileTypes = set() # 统计有几种文件类型
file_List = os.listdir(path)
for file_Name in file_List:
file_WithPath = os.path.join(path, file_Name)
if file_WithPath.endswith("dat"):
print(f"[*] dat文件: {file_Name}")
with open(file_WithPath, "rb") as raw_DatFile:
# head2Byte = raw_DatFile.read(2)
head2Byte = int.from_bytes(raw_DatFile.read(2), byteorder='big') # 获取前两个字节
fileTypes.add(hex(head2Byte))
else:
pass
print(f"文件类型数量: {fileTypes}")


def imageDecode(file_WithPath, file_Name):
out = out_path+file_Name+".png"
with open(file_WithPath, "rb") as dat_read, open(out, "wb") as png_write:
for now in dat_read: # 逐字节异或解码
for nowByte in now:
newByte = nowByte ^ secretKey
png_write.write(bytes([newByte]))



def findFile(path):
autoCheck(path) # 自动检测秘钥
print(f"[*] 当前目录: {path}")
file_List = os.listdir(path)
for file_Name in file_List:
file_WithPath = os.path.join(path, file_Name)
if file_WithPath.endswith("dat"):
print(f"[*] dat文件: {file_Name}")
imageDecode(file_WithPath,file_Name)
else:
pass


#checkFileTypes(r"C:\Users\hxxx\Documents\WeChat Files\wxxxxx\FileStorage\Image\2020-06")
findFile(inpath)

image-20201023130209388

0x04

解密后发现我微信为什么会悄悄存储了这么多乱七八糟我没见过的图片…

image-20201023130233843

amazing…

image-20201023130249510