• 题目地址
  • 下载解压后得到一个keli.dat文件
  • 利用winhex打开文件,并没有发现有价值的信息。然后通过该后缀名为jpg、avi等格式也行不通。
  • 重新读题,题目是 FileStoragedat, FileStorage是微信存储数据的一个文件夹,该文件加下存放的是经过加密后微信中发送、接受的图片而形成的文件后缀为dat的文件。就是微信dat文件。想要做出这到题来,就得先弄懂微信dat文件形成的原因。

  • 微信的dat文件,将微信图片的每个字节通过异或运算后,保存为dat后缀名存储方式。以这到题为例,我们进行讲解。首先我们用winhex等二进制查看工具打开该图片。图片左边的字节为17CE。
  • 这个17CE是重点,我们现在知道图片经过异或运算后,得到的结果是17CE,那么我们这里使用常见的几种图片格式进行逆推。
    • 大概公式:文件头 XOR 17CE = 两个相同的字节
  • 常见文件头
    • JPG:FF D8 FF
    • PNG:89 50 4E 47
    • BMP:42 4D
    • GIF:47 49 46 38
    • ZIP:50 4B 03 04
    • RAR:52 61 72 21
    • AVI:41 56 49 20
  • png文件头为8950,dat文件头为17CE。经过异或运算后,得到的结果是9E9E。说明原图的每一个字节同9E进行异或运算后得到的字节保存后,就是dat文件。
  • 已知dat文件所有字节,已知异或运算字节为9E,所以将这个dat文件的每个字节和9E进行异或运算后,就会得到一张PNG的图片
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
import os
import binascii

title_flags = {"JPG":b"\xff\xd8\xff",
                "PNG":b"\x89\x50\x4e\x47",
                "BMP":b"\x42\x4d",
                "GIF":b"\x47\x49\x46\x38",
                "ZIP":b"\x50\x4b\x03\x04",
                "RAR":b"\x52\x61\x72\x21",
                "AVI":b"\x41\x56\x49\x20"}

def image_decode(in_path,out_path):
    """
    解密dat文件
    param:
        in_path: 输入文件路径 + 文件名
        out_path: 输出路径 + 输入文件名
    ret:
        None
    """
    dat_read = open(in_path, "rb")
    out_file= out_path + ".png"
    png_write = open(out_file, "wb")
    flag = 1 # 标记第一行数据
    xor_flag = 0 # 存储等下参与 xor 的值
    for now in dat_read:
        if flag == 1:
            file_flag = int.from_bytes(now[0:2],byteorder="big",signed=False) # dat文件的前2字节
            for k in title_flags.keys():
                t_f = title_flags[k][0:2] # title_flags的前2字节
                t_f = int.from_bytes(t_f,byteorder="big",signed=False)
                f_type0 = t_f ^ file_flag # 进行xor
                f_type = hex(f_type0) # 转成hex str
                f_type1 = f_type[2:4]
                f_type2 = f_type[4:6]
                if f_type1 == f_type2: # 对比相邻两字节是否相同
                    xor_flag = f_type0 % 256 # 取出f_type0的后两位,用于xor
            flag = 0
        for nowByte in now:
            newByte = nowByte ^ xor_flag
            png_write.write(bytes([newByte]))
    dat_read.close()
    png_write.close()
           
def main():
    in_path = r"C:\Users\Public\temp\keli.dat"
    file_name = in_path.split("\\")[-1:][0]
    out_path = "C:\\Users\\Public\\" + file_name
    image_decode(in_path, out_path)
   
if __name__ == "__main__":
    main()