PC微信逆向:实现自动保存加密的聊天图片
2019-10-02 11:19:00 Author: mp.weixin.qq.com(查看原文) 阅读量:53 收藏

本文作者:鬼手56(信安之路病毒分析小组成员 & 信安之路 2019 年度优秀作者)

成员招募:信安之路病毒分析小组寻找志同道合的朋友

本文基于 anhkgg 大佬的文章《微信 PC 端技术研究(2)-拿下语音》,原文链接:

https://bbs.pediy.com/thread-249274.htm

anhkgg 大佬的这篇文章找到了保存语音消息的接口,这里直接给出相关特征码,方便定位(我使用的微信版本依旧是2.6.8.52)

偏移为 0x30E326,下面的特征码

67E3E319    C745 FC 0100000>mov dword ptr ss:[ebp-0x4],0x167E3E320    FF77 34         push dword ptr ds:[edi+0x34]             ; 长度67E3E323    FF77 30         push dword ptr ds:[edi+0x30]             ; 内容67E3E326    E8 85F07300     call WeChatWi.6857D3B067E3E32B    8D85 58FFFFFF   lea eax,dword ptr ss:[ebp-0xA8]67E3E331    50              push eax67E3E332    E8 090E0000     call WeChatWi.67E3F140
C745 FC 01000000 FF77 ?? FF77 ?? E8 ???????? 8D85 ???????? 50 E8 ????????

基于保存语音的相关延伸

其实这个地方不单单有语音消息,还有图片消息,当我们发送一条图片消息时

[edi+0x30] 的内容里面保存有这一次发送图片的相关数据,包括微信 ID 等一系列原始的数据。我们当然可以在这个地方写 HOOK 来保存图片,但是没有必要。因为这里的消息内容过多,处理起来相对会比较麻烦。

图片处理的相关流程

既然这个地方是最原始的消息内容,那么后面肯定会对消息进行相关处理。而且我们已经知道微信的接收的图片会用异或加密的方式保存到本地。那么我们不妨猜测一下图片相关的处理流程。

首先接收到原始的消息后,会对消息进行一系列的处理,其中就包括判断消息是否是图片。那么如果是图片则会取出图片数据,然后在内存中对图片进行加密。加密完成之后调用文件操作的 API,写入加密后的图片到本地。

整个过程如图所示:

自动保存图片相关思路

既然了解图片处理的流程,而且已经有了接收图片消息的 call,那么我们就可以在接收到图片消息之后,在 CreateFileW 创建图片之前,找到对图片进行加密的算法和函数,将未加密前的图片保存出来。

实战保存聊天图片

在 OD 中找到保存语音的 call,发送图片消息让程序断下的同时,对 CreateFileW 进行下断。之后 F9 运行

此时文件路径为 xlog,这个明显不符合我们的要求,继续 F9 运行

一直找到图片路径带有 Image 关键字时,再创建图片

此时我们点击 K 显示堆栈,找到第一层返回地址,右键显示调用

当微信运行到这里的时候,图片加密已经完成,我们要在这个函数之前找到图片的加密算法,其实就在上面一点点的位置,鼠标稍微往上翻一下就能看到

找到这个地方之后清除剩下的所有的断点,只保留这一个

对保存图片 call 的相关分析

再次发送一张图片,程序断下。这段代码首先用循环的方式对图片进行加密,循环的次数即 ecx 的值,也就是图片的大小。其中有两个数据比较重要。

我们先在内存中查看 [ebp-0x14] 的内容,想要知道这段数据是什么其实很简单。先下 CreateFileW 断点

当 CreateFileW 断点断下后,执行到返回,查看打开的文件句柄

此时打开的图片句柄为 0xF80,此时再下 WriteFile 断点

WriteFile 断下后可以看到句柄为 F80,写入的缓冲区地址为 39FE820,而 [ebp-0x14] 的地址正好也是 39FE820。也就是说 [ebp-0x14] 这个位置保存的是加密后的图片数据

回到之前的断点,再次发送一张图片,查看 [ebp-0x4] 的数据

此时 [ebp-0x4] 中保存了接收的图片,而 ecx 保存了图片的大小

这里借用 PCHunter 查看->进程内存,将这一段数据 dump 下来

问题就在于这里只是一张大小为 4KB 的缩略图,回到 OD,再次按 F9 运行

断点断下,但是此时 ecx 的值变成 0x5A140

用同样的方法 dump 下内存,大小为 360KB,这个就是我们需要的原图了。

也就是说这个地方会断下来两次,第一次是缩略图,第二次才是我们要的原图。

代码实现保存聊天图片

示例代码如下:

void HookSaveImages(){  DWORD dwBaseAddress = (DWORD)GetModuleHandle(TEXT("WeChatWin.dll"));  //需要hook的地址  SaveImageAddress = dwBaseAddress + SaveImages;
//跳回的地址 SaveImageAddressBackAddress = SaveImageAddress + 5;
//组装跳转数据 BYTE jmpCode[5] = { 0 }; jmpCode[0] = 0xE9;
//计算偏移 *(DWORD*)& jmpCode[1] = (DWORD)FnSaveImages - SaveImageAddress - 5;
// 保存以前的属性用于还原 DWORD OldProtext = 0;
// 因为要往代码段写入数据,又因为代码段是不可写的,所以需要修改属性 VirtualProtect((LPVOID)SaveImageAddress, 5, PAGE_EXECUTE_READWRITE, &OldProtext);
//写入自己的代码 memcpy((void*)SaveImageAddress, jmpCode, 5);
// 执行完了操作之后需要进行还原 VirtualProtect((LPVOID)SaveImageAddress, 5, OldProtext, &OldProtext);}
__declspec(naked) void FnSaveImages(){  __asm  {    mov ebx, dword ptr ss : [ebp - 0x4];    mov ImageData, ebx;    mov ImageDataLen, ecx;    pushad;    pushfd;  }
//调用接收消息的函数 FnSaveImagesCore();
//恢复现场 __asm { popfd popad //跳回被HOOK指令的下一条指令 jmp SaveImageAddressBackAddress; }}
void FnSaveImagesCore(){  //如果图片长度大于10KB则保存  if (ImageDataLen >= 10240)  {
//获取临时文件夹目录 char temppath[MAX_PATH] = { 0 }; GetTempPathA(MAX_PATH, temppath); char imagedir[20] = { "WeChatRecordImages" };
//拼接目录 char WeChatExpressionsPath[MAX_PATH] = { 0 }; sprintf_s(WeChatExpressionsPath, "%s%s\\", temppath, imagedir); //创建目录存放图片 CreateDir(WeChatExpressionsPath);
//保存图片 CreateFileWithCurrentTime(WeChatExpressionsPath, (char*)".jpg", ImageData, ImageDataLen); }}

实际效果

项目地址

最后附上我的微信机器人项目地址(点击阅读原文直达):

https://github.com/TonyChen56/WeChatRobot

推荐阅读

PC 端微信技术研究之保存聊天语言

微信PC端技术研究(3)-如何找到消息发送接口

PC微信逆向:发送与接收消息的分析与代码实现

PC微信逆向:分析发送xml名片call

PC微信逆向:两种姿势教你解密数据库文件

PC微信逆向:使用HOOK拦截二维码

PC微信逆向:实现自动添加好友分享名片

WeTool逆向:借用别人的成果 打造自己的程序


文章来源: http://mp.weixin.qq.com/s?__biz=MzI5MDQ2NjExOQ==&mid=2247491620&idx=1&sn=76e6a77451afd39bb027de625a4ab20f&chksm=ec1dd00cdb6a591a9502623a9fa12043bfdaf8548c57ea52618893b9f07c792309b93b44bf30#rd
如有侵权请联系:admin#unsafe.sh