解码解密微信电脑版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



