解码解密微信电脑版image文件夹下缓存的用户图片 dat文件解码解密查看方法
微wx笑
2021-07-28【图形图像】
1708
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
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 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 | 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