解码解密微信电脑版image文件夹下缓存的用户图片 dat文件解码解密查看方法
微wx笑 2021-07-28【图形图像】 6 0关键字: 解码 解密 微信 image 图片 dat java
在使用微信Mac版的时候,接收到的图片可以直接右键》打开文件所在位置就能查看图片,但是Windows版本的就不行了,虽然文件已经接收保存到本地了,但是却以“.dat”格式进行保存并且进行了加密处理,用图片浏览器打开也提示无法查看。这里就介绍一下使用Java语言对其进行批量解密的方法。
在使用微信Mac版的时候,接收到的图片可以直接右键》打开文件所在位置就能查看图片,但是Windows版本的就不行了,虽然文件已经接收保存到本地了,但是却以“.dat”格式进行保存并且进行了加密处理,用图片浏览器打开也提示无法查看。这里就介绍一下使用Java语言对其进行批量解密的方法。
一、找到图片
Windows版本想到找到微信聊天记录中的图片,需要以下步骤:
1、设置
2、文件管理,打开文件夹
3、打开 FileStorage》Image 文件夹
二、解密原理
1. 原理描述
原理很简单,就是按字节对接收到的图片文件进行了异或处理保存为dat文件,查看时再解码,并且使用的加密代码几乎是一样的,只要我们弄到了加密的字节码,使用其对dat文件进行异或操作保存为png文件便可以查看了。
2. 获取加密字节码
16进制编辑器 HEdit下载
链接: https://pan.baidu.com/s/1lcaXiWyL31oYhxMAMGAOiA 提取码: bqx6 复制这段内容后打开百度网盘手机App,操作更方便哦
将其中一个文件夹的dat文件通过16进制编辑器打开,记录其开头两个16进制的值,随机挑选一部分dat文件打开,查看开头两个16进制的值并对比,一般来说是一样的,这两个值是解密的关键。
3、文件头对比
加密的文件头部
解密后的文件头部
我这里开头的两个值几乎都是8C AB,同时我们了解到网络中传输的图片多为jpeg格式,而jpeg格式的图片开头两个16进制的值通常为FF D8,我们打开计算器,将这两个值异或一下,得到两个16进制的值,通常来说应该是一样的,那么这个16进制的值就是解码的关键了。
4、使用计算器计算加密字节码
打开计算器,查看菜单选中程序员、基本
鼠标点击输入 8CAB,点击Xor
再输入FFD8,点击=号,就可以等到结果了
本机的结果是73,那么我们只需要将dat文件的所有数据都与73异或便可以得到解密数据了,同时把数据保存为png格式便可以使用看图软件直接查看了。
注意:每个人得到的值可能不一样。
注意:这里只是教大家怎么手动计算,后面代码里面已经可以通过程序自动计算了。
三、批量执行解密
处理逻辑
1、 获取指定路径下的所有dat文件,进入for循环处理
2、按次序读入dat文件,获取加密字节码及扩展名,然后按byte对其数据与加密字节码进行异或
3、将异或后的数据保存下来,后缀改为对应的扩展名,输出到指定文件夹
解密代码:decode.java
import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FilenameFilter; import java.util.Date; /** * 微信电脑版image文件夹下缓存的用户图片dat文件解码解密类 * @author lipw * @email admin@ivu4e.com * @site https://ivu4e.com/ */ class decode { public static void main(String[] args) { System.out.println("hello"); // 使用时修改这里的路径就可以了 BatchDecodeFileContent("D:/Documents/WeChat Files/wxid_/FileStorage/Image/2021-07", "D:/Documents/WeChat Files/wxid_/FileStorage/Image/decodeimg5"); } /** * 批量对文件进行解密处理 * @param inputFileDir 要解密的文件夹 * @param outputFileDir 解密后保存在哪个文件夹 */ public static void BatchDecodeFileContent(String inputFileDir, String outputFileDir){ File f = new File(inputFileDir); if (!f.exists() || !f.isDirectory()){ System.out.println("要解密的文件夹不存在!"); } if (!outputFileDir.endsWith("/")){ outputFileDir = outputFileDir.concat("/"); } File o = new File(outputFileDir); if (!o.exists()){ try { System.out.println("解密后保存的文件夹不存在,尝试创建..."); o.mkdirs(); } catch (Exception e) { System.out.println("创建解密后保存的文件夹失败,程序终止执行"); return; } } File[] fl = f.listFiles(new FilenameFilter(){ @Override public boolean accept(File dir, String name) { if (name.endsWith(".dat")){ return true; } return false; } }); System.out.println("共找到 " + fl.length + " 个 dat 文件"); if (fl.length == 0){ System.out.println("没有需要解码的文件"); } long begin = new Date().getTime(); System.out.println("====开始解码====time:" + begin); Bom bom; FileInputStream fis; File of; FileOutputStream fos; byte[] bs = new byte[1024 * 1024]; int rl; for (File file : fl){ System.out.println(file.getAbsolutePath()); try { fis = new FileInputStream(file); rl = fis.read(bs); bom = getFileBom(bs); if (bom.getXorVal() == 0x00 || bom.getExtn() == null){ System.out.println("获取加密的字节码失败"); continue; } of = new File(outputFileDir + file.getName() + bom.getExtn()); fos = new FileOutputStream(of); while(rl > 0){ for (int i = 0; i < rl; i++){ bs[i] = (byte)(bs[i] ^ bom.getXorVal()); } fos.write(bs, 0, rl); rl = fis.read(bs); } fis.close(); fos.close(); } catch (Exception e) { } } long end = new Date().getTime(); System.out.println("decode2====" + fl.length + " 个dat文件解码完成====用时:" + (end - begin)); } /** * 获取加密的字节码 * @param buff 读取的文件的第一块,包含文件头的部分 * @return */ public static Bom getFileBom(byte[] buff){ Bom bom = new Bom(); if (buff.length < 2){ return bom; } // jpeg if ((byte)(buff[0] ^ 0xFF) == (byte)(buff[1] ^ 0xD8)){ bom.setXorVal((byte)(buff[0] ^ 0xFF)); bom.setExtn(".jpeg"); return bom; } // png if ((byte)(buff[0] ^ 0x89) == (byte)(buff[1] ^ 0x50)){ // Xor计算之后需要加上强制类型转换(byte),否则比较的时候会出现不相等的情况 bom.setXorVal((byte)(buff[0] ^ 0x89)); bom.setExtn(".png"); return bom; } // bmp if ((byte)(buff[0] ^ 0x42) == (byte)(buff[1] ^ 0x4D)){ bom.setXorVal((byte)(buff[0] ^ 0x42)); bom.setExtn(".bmp"); return bom; } // gif if ((byte)(buff[0] ^ 0x47) == (byte)(buff[1] ^ 0x49)){ bom.setXorVal((byte)(buff[0] ^ 0x47)); bom.setExtn(".gif"); return bom; } // tif if ((byte)(buff[0] ^ 0x49) == (byte)(buff[1] ^ 0x49)){ bom.setXorVal((byte)(buff[0] ^ 0x49)); bom.setExtn(".tif"); return bom; } System.out.printf("%x%x==%x%x", buff[0], buff[1],(buff[0] ^ 0x89),(buff[1] ^ 0x50)); return bom; } // 文件头 static class Bom { // 对文件加密解密使用的字节码 byte xorVal = 0x00; // 文件扩展名 String extn = null; public Bom() { } public byte getXorVal() { return xorVal; } public void setXorVal(byte xorVal) { this.xorVal = xorVal; } public String getExtn() { return extn; } public void setExtn(String extn) { this.extn = extn; } } }
使用时注意:
1、输入输出目录的替换
2、0x73是对 dat 文件中的字节与 FF、D8 进行异或运算得到的数字,具体计算方法参考下面的链接。
其它语言版本:
参考:https://blog.csdn.net/a386115360/article/details/103215560/
本文由 微wx笑 创作,采用 署名-非商业性使用-相同方式共享 4.0 许可协议,转载请附上原文出处链接及本声明。
原文链接:https://www.ivu4e.cn/blog/image/2021-07-28/707.html