1、 xxxx接收到图片后,不会明文存储在磁盘,因为不安全,都是加密后存储在特定目录的,截图如下(请忽略两个jpg的文件,这是我为了做测试人为添加的,xxxx原始是不会存这些图片的):
可以看到图片都是以dat格式存储的。用010editor打开:全是没意义的数据,图片的头信息完全找不到!
既然都是加密存储的,在xxxx软件中是怎么看到图片的了? 换句话说,xxxx软件都是怎么解密这些图片的了?
2、正式介绍解密之前,先做个位运算知识的铺垫:异或 XOR
(1)两个bit做XOR,如果不同那么结果为1;如果相同结果为0; 打个比方:男女在一起才能生娃,同性在一起是不行的!也就是:1^1=0, 0^0=0, 但是1^0=1;
(2)XOR最大的作用: 对称加密! 比如明文是0xA=1010, 密钥是0xB=1011,那么密文=A^B=0x1; 解密时,用密钥^密文即可,这里便是0x1^B=A,成功得到明文;
(3)XOR最大的特性:明文、密钥、密文三个的关系像个三角形,其中任意两个异或,都能得到第三个!比如上面用加密的算法是A^B=0x1;解密的算法是B^0x1=A; 但是用明文A^密文0x1也能得到密钥B; 这个特性有啥用了:
- 明文、密钥、密文只能对外公布一个,一般公开密文(这不废话么?)
- 曾经有人利用该特性找到了windwos PG保护的密钥(用IDA静态分析找到明文,windbg动态分析找到密文,两个异或就找到了密钥)
- 也有人利用这个特性做PE文件保护(原理和PG保护类似),PE文件的代码和数据都加密存储,直到执行前才在内存解密得到真正的代码
- 密文和明文大小是一样的(后面会根据这个猜图片的加密方式)
(4)XOR对称加密的另一大特点:计算方式简单! XOR本质是位运算,CPU内部的硬件电路是可以直接实现的,一条XOR的汇编指令就能完成计算,理论上只需要1ns的时间(这里扩展一下:其实CPU内部的加减乘除都是通过XOR实现的);只要key的长度足够,短时间内想要通过暴力穷举是不可能的。比如key的长度是1024bit,那么key就有2的1024次方个。和同为对称加密的AES算法比,效率高太多了!所以用XOR加密是非常广泛的!
3、 之前找过xxxx接受消息的call,这里继续下断点,然后再手机上通过文件助手发条消息,断下来了:
这里已经能看到消息的部分内容了,但OD显示的长度有限,看不全,所以这里需要CE辅助:注意地址的配置,这里就要选Unicode了
下面就是图片的数据格式:是xml的;从字段的名称看,有AES密钥、cdn的密钥、cdn的url、md5等信息;图片还有大图和midimg(从字面猜测应该是中等大小的图片,大概率是在聊天窗展示的那种);可惜的是没有找到图片保存的名字和位置;
<?xml version="1.0"?> <msg> <img aeskey="7a40664635a1aac64816c8deff4a39b0" encryver="0" cdnthumbaeskey="7a40664635a1aac64816c8deff4a39b0" cdnthumburl="304f020100044830460201000204513ea50e02033d14ba02047851fb3a020460376bb60421777875706c6f61645f66696c6568656c7065723730375f31363134323434373838020401090a020201000400" cdnthumblength="3967" cdnthumbheight="90" cdnthumbwidth="120" cdnmidheight="0" cdnmidwidth="0" cdnhdheight="0" cdnhdwidth="0" cdnmidimgurl="304f020100044830460201000204513ea50e02033d14ba02047851fb3a020460376bb60421777875706c6f61645f66696c6568656c7065723730375f31363134323434373838020401090a020201000400" length="1" md5="5733041f60a14ce9f4d75be1bb49a213" hevc_mid_size="176859" /> </msg>
继续往下,终于找到了图片存放的位置和名字,如下:
用同样的方法再CE里面能看到图片加密后bat文件的全称和存放路径(就是刚才说的那个目录):
根据bat文件的名字和路径,把加密前后的图片都放进010editor中对比:加密后的文件已经面目全非,连图片头信息都没了,不过加密后文件有个最大的特征:大小和加密前完全一样!
那么有没有可能用XOR来加密的了? 怎么验证了?
4、这里就要用到刚才提到的XOR特点:密文、密钥、明文三者像三角形的关系其中任意两个异或,都能得到第三个!明文图片的第一个字节是FF,密文第一个字节是B3,FF^B3=4C,那么4C是不是key了? 为了逻辑严密,需要交叉验证:第二个明文是D8,这时已经知道key=4C了,D8^4C=0x94,居然刚好等于第二个密文,4C就是key看来没错了!为了谨慎,我们再用密文交叉验证试试:第三个密文是B3,那么解密算法就是B3^4C=0xFF,刚好等于第三个明文!此时,通过三次明文、密文、密钥的交叉验证,实锤了加密算法是XOR、密钥是4C!
#include <stdio.h> #include <string.h> #include <fstream> #include <iostream> using namespace std; const char* filename = "decryptPic\\07a00a9454f983ca808cd1a6028d581c.dat"; int main(int argc, char** argv) { std::ifstream streamReader(filename, std::ios::binary); //以二进制的形式读取文件 streamReader.seekg(0, std::ios::end);//跳转到尾部 unsigned filesize = streamReader.tellg();//得到文件大小 char* _data = new char[filesize]; char* _decrypt = new char[filesize]; printf("length is:%d\n", filesize); streamReader.seekg(0, std::ios::beg);//跳转到开始 streamReader.read(_data, filesize); streamReader.close(); for (int i=0;i< filesize;i++) { //std::cout << _data[i]; /* //https://www.coder.work/article/2223646 参考这里,打印的时候必须转成(unsigned char),否则默认会以4字节、也就是unsinged int打印 */ //printf("%1x",(unsigned char)_data[i]); _decrypt[i] = _data[i] ^ 0x4c;//解密 //printf("%1x", (unsigned char)_decrypt[i]);//从010editor看是对的 } std::ofstream ofs; ofs.open("decryptPic\\decript.jpg", ios::out | ios::app | ios::binary, _SH_DENYNO); ofs.write(_decrypt, filesize); ofs.close(); return 0;
效果:成功解密,生成decrypt.jpg图片!