PC微信逆向分析之《获取登录二维码》

最近在网上看了下各种相关帖子,都是比较老的版本,这里我将以3.6.0.18版本为例,对其进行分析 【供学术研究,请勿用于非法用途】

先引入一个前言:

  • 所有png图片都是有统一格式的
  • 文件头数据块:89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52
  • 文件尾数据块:00 00 00 00 49 45 4e 44 ae 42 60 82
  • 使用16进制查看器随便打开一张png图片,可以看出文件头确实跟上述一致,那么我们就从这里做切入点
    在这里插入图片描述

一、CE寻址

  • 打开WX,切换到二维码登录页面,打开CE搜索字符串“IHDR”,选择这3个黑色的(绿色的是基址,我们要找的肯定不是基址)
    在这里插入图片描述

  • 智能编辑地址,全部减C,这里很多人都不知道为什么要减C
    在这里插入图片描述

  • 通过16进制编辑器可以看到“IHDR”的首字符所在位置在0xC的位置,所以减去C就可以找到PNG图片的头部了
    在这里插入图片描述

  • 减C之后可以看到有2个数值是“?PNG”,依次查找该地址被谁引用了(找上级指针)
    在这里插入图片描述

二、验证

  • 打开od附加,查找这个地址
  • 可以看出他是一个结构体,第1个是存储图片的指针;第2个猜测他是图片的大小
    在这里插入图片描述
验证方法1
  • 编写脚本,使用od运行脚本,把图片下载下来
    在这里插入图片描述
验证方法2
  • 使用PChunter验证
    在这里插入图片描述
  • 把图片down下来之后,确认无误
    在这里插入图片描述

三、寻找HOOK点

  • 在这个地址下内存写入断点 (这里别看懵了,因为地址是随机的,我写教程的过程中不小心重新启动wx了…所以变了)
    在这里插入图片描述
  • 再次切换到二维码页面,会断在这里,删掉内存断点
    在这里插入图片描述
  • 通过栈回溯的方法,往上找,发现有2个call【其实这里再往上一直找,也能找到我第一篇文章《刷新登录二维码》的call,抛砖引玉多嘴提一句吧,找call并不是那么死板的,找一个call可以有N种方法,只不过是时间快慢以及经验取巧的问题罢了,世上无难事只怕有心人…】
  • 经过验证:
    • 第1个call完成之后,虽然图片数据刷新了,但是down下来的图片是空白的【猜测这个call只是构建了一块空白的画布】
    • 第2个call完成之后,就可以成功down下来,那么我们就对这个地方进行Hook
      在这里插入图片描述

四、编写代码

// 模块基址
DWORD baseAddr = GetBaseAddr();
// 要HOOK的地址
DWORD hookAddr = baseAddr + qrcodeOffser1;
// 要返回的地址
DWORD returnAddr = hookAddr + 5;
// 被覆盖的call的地址
DWORD callAddr = baseAddr + qrcodeOffser2;

void Hook()
{
	//组装跳转数据
	BYTE jmpCode[5] = { 0 };
	jmpCode[0] = 0xE9;

	//计算偏移
	*(DWORD*)&jmpCode[1] = (DWORD)myCall - hookAddr - 5;

	// 往内存中写入自己的数据
	WriteProcessMemory(GetCurrentProcess(), (LPVOID)hookAddr, jmpCode, 5, 0);
}

__declspec(naked) void myCall()
{
	__asm
	{
		// 调用call
		call callAddr;

		//保存环境
		pushad;
		pushf;

		// 下载图片
		push esi;
		call downQrcode;

		//恢复环境
		popf;
		popad;

		//跳转回Hook点的下一条
		jmp returnAddr;
	}
}

void __stdcall downQrcode(DWORD esi)
{
	// 图片大小
	DWORD imgSizeAddr = esi + 0x4;
	size_t imgSize = (size_t)*((LPVOID*)imgSizeAddr);

	// 拷贝图片
	char imgData[0xFFF] = { 0 };
	memcpy(imgData, *((LPVOID*)esi), imgSize);

	// 创建文件句柄
	HANDLE hFile = CreateFileA("C:\\Users\\Administrator\\Desktop\\qrcode666.png", GENERIC_ALL, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hFile == NULL)
	{
		OutputDebugStringA("创建文件句柄失败");
		return;
	}

	// 写文件
	DWORD dwRead = 0;
	if (!WriteFile(hFile, imgData, imgSize, &dwRead, NULL))
	{
		OutputDebugStringA("写入失败");
		return;
	}
	CloseHandle(hFile);
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值