近期有同学问我能不能出一期修改备注的分析思路,他来了他来了!这里我将以3.6.0.18版本为例,对其进行分析 【供学术研究,请勿用于非法用途】
- 我在github上开源了3.6.0.18的源码,有需要学习的可以去看看
- PS:感觉对你有帮助就顺便给个star呗~
- github地址:https://github.com/mrsanshui/WeChatApi
一、通过内存读写做切入点
在修改备注的输入框中先输入“我是备注111”,不要让输入框失去焦点
此时打开CE搜索输入框中的备注(这里我搜索的是unicode)
我们要找的肯定不是基址,所以结果只有2个
尝试过滤一下结果:这次输入“我是备注222”,再次扫描,结果只有一个了!
直接找到它的上级指针(方便后面下断点)
看看是什么访问了他
注意:这里地址变了是因为我做教程的时候中途有事重新开始了…看地址没意义,主要看分析思路!
此时让输入框失去焦点。备注修改成功!
这个地方只访问了1次,那么我们就从这里开始入手
打开dbg附加微信,定位到这个地址,直接下断会不停的断下…
那就先在输入框中输入新的备注,不要让输入框失去焦点,此时在dbg中下断,然后立刻让备注框失去焦点(要拼手速)
因为这里会断下很多次,我们查看eax的值什么时候变成新备注的时候,就可以去追栈了
二、栈回溯追《读取新备注的call》
第1层:压入了备注,说明都已经读完了,那就肯定不是这个
第2层:直接跳转就return了,也不是
第3层:这里有很多call,并且下一个call用到了上一个call的返回值
先下一个断点,防止跟丢了
F4返回到这层,eax就是新的备注,那么这个call就是读取新备注的call
三、寻址《修改备注的call》
既然读取到新备注了,那么接下来就应该要进行修改操作了
F8继续往下分析,第1个call传了一个常量跟新备注,跟进去看看
他只是把把ecx的内容给了eax…
第2个call把备注内容入栈,传了个缓存,执行完之后刚好平栈,并且缓存中有备注的结构体
这个call是组装备注结构的。。。
第3个call不知道是干嘛的,跟进去看到只有这一点内容,并且执行完后,堆栈跟寄存器都没什么太大变化
第4个call应该是最后一个了,再往下就是一个大跳转
F7跟进去看看,这个里面最“丰富”
要从正向的思维去理解逆向,当我们要修改备注的时候,至少要有2个参数
1:被修改人的信息
2:备注
那么我们重点要关注一下,哪个call之前压入了这2个参数
一直往下走到这,发现【esi+0xBA0】的位置有“被修改人的信息”,并且+0x50的位置已经是新备注了
猜测之前所有的call都是为了组装这个结构,这个call里面就要用到这个结构了
F7跟进来,看看哪里用到了“被修改人的信息”
一进来就是一个跳转到尾部…
这里传入了“被修改人的完整信息结构”,并且执行完这个call之后返回了个1
猜测这个call就是修改备注的call?
四、验证寻址是否正确
经过上面的分析,也不能确认这个call就是修改备注的call
那么就来验证一下,他只压入了2个参数,且是内平栈
在这个call下一个断点,再次修改备注,断点断下
我们手动让他平栈,不让这个call执行,F9放过所有断点,看看备注是否还能修改成功
信息页确实是改了,但是移动端中是没改的,PC端再次点击一下这个好友的头像,就会变回去了
那么现在可以确定这个他就是我们要找的修改备注的call
五、分析参数
eax:“被修改人的信息”,通常应该由内部call来构造,但也可以手动构造
ecx:在上面就可以看到他是一个常数指针,那么就可以直接计算偏移进行取址
六、编写代码
void UpdateRemark()
{
DWORD callAddr = GetBaseAddr() + 0x404740;
DWORD paramAddr = GetBaseAddr() + 0x222F3BC;
char buff[0x1024] = { 0 };
WxStruct wxId((wchar_t*)L"wxid_xxx");
WxStruct newRemark((wchar_t*)L"新的备注666");
memcpy(&buff[0x10], &wxId, sizeof(WxStruct));
*(DWORD*)(buff + 0x50) = 0x43;
memcpy(&buff[0x58], &newRemark, sizeof(WxStruct));
*(DWORD*)(buff + 0x230) = 0x43;
__asm
{
mov ecx, paramAddr;
mov ecx, [ecx];
push ecx;
lea eax, buff;
push eax;
call callAddr;
}
OutputDebugStringA("OK");
}