xue5hen 发表于 2022-11-17 22:07

自己动手写个微信DAT文件解密工具

【原理简介】

[*]首先,微信DAT文件是将图片数据的每个字节经过和密钥做异或运算来得到的。
[*]异或运算法则:如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。
[*]异或运算有个可交换的特点,即:如果a和b异或运算后得到了c,那么在a、b、c三者中,任意两者进行异或运算会得到它们中的第三者。


基于上面三条来梳理一下工具编写的前提条件,就变成了下面表格描述的这样。问题变得简单了,我们只需要通过循环,将图片的文件头数据的第1、2字节与DAT数据的第1、2字节相应做异或运算,那么就可以得到两个值,如果这两个值相等,那么就是我们要找的密码。然后用得到的密码与DAT的所有字节做异或运算,便可以还原出原始的图片文件。

图片 密码 DAT

可有限枚举,已知文件头数据
jpg:
png:
gif:
... 未知 已知

   
【工具编写】
基于上述原理,代码实现起来并不难。我用JS写了两个版本,一个Electron版本的,一个是Web版本的。相对而言,Electron打包后体积较大,对于一个功能单一的小工具来讲太鸡肋;而Web版本比较轻量,而且可以挂到网上,随时随地方便地使用,性价比更优。
如下图所示,工具的界面设计比较简单,Web版本只有一个主区域,可以将DAT文件拖拽进去还原出图片,因为文件头枚举数量很少,所以速度很快,基本是瞬间的;下方设置了两个按钮“全部删除”和“全部下载”,可以快速清空主体区域和下载所有还原出来的图片。


代码逻辑并不复杂,这里贴两处比较关键的代码片段(Web版),文后会附上Web版的下载地址,另外也做了个视频(两个版本的工具展示+代码解释),可以视自己口味选择下载和观看。
// 拖拽添加文件drop (e) {
const fileList = e.dataTransfer.files
if (!fileList) return
// 取文件后缀名,必须是dat文件
let taskList = []
let indexList = []
for (let i = 0; i < fileList.length; i++) {
    const file = fileList
    if (!/.dat$/i.test(file.name)) {
      return this.$toast('请选择DAT文件!')
    }
    let fStat = fs.statSync(file.path)
    if (fStat.isDirectory()) {
      return this.$toast('请选择DAT文件!')
    }
    taskList.push(this.getFileInfo(file.path))
    indexList.push(i)
}
Promise.all(taskList).then((infos) => {
    if (!infos || !infos.length) return
    infos.forEach((v, i) => {
      let file = fileList]
      this.filesList.push({
      name: file.name, path: file.path, size: file.size, ...v
      })
    })
})
}
// 获取单个文件的信息(包括密码和数据解密)getFileInfo (filePath) {
let result = {name: '', type: '未知', password: '', data: '', url: ''}
let _arr = path.basename(filePath).split('.')
result.name = _arr.slice(0, _arr.length - 1).join('.')
return new Promise((resolve, reject) => {
    if (!fs.existsSync(filePath)) {
      reject('文件不存在')
    }
    fs.readFile(filePath, (err, data) => {
      if (err || !data) reject('读取文件错误')
      result.data = data
      for (let key in this.fileHeaderMarks) {
      let val = this.fileHeaderMarks || []
      let pwd1 = (val || 0) ^ data
      let pwd2 = (val || 0) ^ data
      if (pwd1 === pwd2) {
          result.type = key
          result.password = pwd1
          break
      }
      }
      if (result.password) {
      let mimeType = this.fileMimeType || `image/${result.type}`
      result.data = result.data.map(v => (v ^ result.password))
      result.url = `data:${mimeType};base64,${result.data.toString('base64')}`
      }
      resolve(result)
    })
})
}
视频展示:https://www.bilibili.com/video/BV1f841187tm/
Web版工具源码:https://pan.baidu.com/s/1_KIqd0h_3T2vcR87GlUJYg?pwd=3m4h 提取码: 3m4h

已经好晕了 发表于 2022-11-18 11:40

思路清晰,出个聊天记录版吧大佬

xue5hen 发表于 2022-11-18 20:54

nuxingxp 发表于 2022-11-18 20:19
楼主,达到您的水平,得学哪些课程?

前端开发相关的课程:html、css、js、jQuery、vue全家桶(或React)、nodejs、electron这些

wxq_hz 发表于 2022-11-18 12:22

感谢分享,好用

Q17 发表于 2022-11-18 12:49

估计出个聊天记录会更火

baohe 发表于 2022-11-18 11:54

看不懂多多学习谢谢

shf8799 发表于 2022-11-18 12:12

暂时还看不明白,努力!

chen0jay 发表于 2022-11-18 12:17

大佬大佬{:1_893:}

Michael_Yang 发表于 2022-11-18 12:34

{:1_921:}请收下膝盖

faith9527 发表于 2022-11-18 12:42

学习学习,谢谢楼主

诗木 发表于 2022-11-18 12:52

{:301_973:}好强,感谢大佬分享
页: [1] 2 3 4 5 6 7 8 9 10
查看完整版本: 自己动手写个微信DAT文件解密工具