PC微信逆向--看看哪些好友删除了自己

写在前面

搞微信逆向也有一段时间了,实现了发送文本、图片、文件、名片、xml文章消息,以及获取好友列表,查询好友信息
上面这些功能足够做一个发单机器人。但对我来讲,并没有什么实质的用处,所以,又查了点无痕清粉的资料,配合通讯录就可以看看哪些好友偷摸把自己删了。
将不会介绍自动删除好友的东西,想做无痕清粉的自己研究哈(ps:被封不关我事)

微信版本

微信电脑版3.6.0.18

资料

两篇资料都来自看雪论坛:
Dump微信PC端的界面Duilib文件
微信无痕清粉分析过程-附源码地址
感谢KongKong20大佬

Duilib界面

思路仍然适用于微信电脑版3.6.0.18版本,IDA如果搜不到字符串,请在字符串窗口右键-Setup,勾选Unicode-16风格。
不过builder.Create的位置有所变化,在找到的Duilib字符串上面一个Call,追进去多观察下就能找到。
结论:
3.6.0.18版本添加好友时的确认按钮名字是“primary_button”

定位发送CALL

思路可以参考第二篇资料,这里主要说一下IDA怎么用吧,在字符串窗口搜索字符串,然后双击定位到数据段,在鼠标移动到字符串变量名上,按下x,查看交叉引用
在弹出的地址中双击,跳转到对应的地址,如果此处IDA已经处理完毕,可以在sub函数上按F5查看伪代码,如果没有反应则要等待IDA处理完毕。
放一段根据AddFriendHelper::eventproc定位到的伪代码:

switch ( a2 )
        {
          case 176:
            ......
            break;
          case 177:
            if ( *(_BYTE *)(this + 56) )
     		......
            break;
          case 178:
            if ( *(_BYTE *)(this + 56) )
            ......
            break;
          case 181:
            v15 = *(_BYTE *)(this + 48);
            ......
            break;
          default:
            return;
        }

这里的176-181指示几种好友状态:
176(0xB0):被对方删除
177(0xB1):好友
178(0xB2):未知
181(0xB5):被对方拉黑
接着在IDA搜索opCode : %d,这个字符串只有一处引用,找到以后根据偏移在OD中定位、下断,然后加好友,弹出窗口之前的放过去,弹出窗口之后,点击确定按钮,再次断下
接着在堆栈翻一翻,找到下面这个CALL:

Executable modules, 条目 126
 基址=02E20000
 大小=02680000 (40370176.)
 入口=04767B60 WeChatWi.<模块入口点>
 名称=WeChatWi
 文件版本=3.6.0.18
 路径=D:\Tencent\WeChat\[3.6.0.18]\WeChatWin.dll

0311A8DB    83EC 14             sub     esp, 14                          ; begin
0311A8DE    8BCC                mov     ecx, esp
0311A8E0    6A FF               push    -1
0311A8E2    50                  push    eax                              ; Unicode类型请求信息
0311A8E3    E8 E8734000         call    03521CD0                         ; 返回请求信息结构体
0311A8E8    FFB5 1CFFFFFF       push    dword ptr [ebp-E4]               ; opcode的值,1:请求好友状态,2:添加好友
0311A8EE    8D83 AC030000       lea     eax, dword ptr [ebx+3AC]         ; 好友的wxid
0311A8F4    83EC 14             sub     esp, 14
0311A8F7    8BCC                mov     ecx, esp
0311A8F9    50                  push    eax
0311A8FA    E8 C1744000         call    03521DC0                         ; 返回好友信息结构,末尾是opcode
0311A8FF    8B8D 20FFFFFF       mov     ecx, dword ptr [ebp-E0]          ; 句柄
0311A905    C645 FC 03          mov     byte ptr [ebp-4], 3
0311A909    E8 82521000         call    0321FB90                         ; 请求好友状态

前面还有一个完善堆栈的CALL要执行,具体参考下面的汇编代码。
这块坑不多,需要提一嘴,mov byte ptr [ebp-4], 3这种修改ebp-0x4值的就不要执行了
不然所有的CALL都正常执行了,却会因为__security_cookie崩溃,不了解编译机制的话,容易卡半天。

具体原理

刚才定位到了一个switch-case的伪代码,当调用请求好友状态的CALL时,会调用这段代码所在的函数,找一个合适的地方Hook到状态码即可,尽量找一个0xB0-0xB5只断一次的地方。

关键代码

调用

VOID __stdcall CheckFriendStatus(wchar_t* wxid) {
	LocalFriendStatus = 0x0;
	DWORD WeChatWinBase = GetWeChatWinBase();
	DWORD CheckFriendStatusCall1 = WeChatWinBase + CheckFriendStatusCall1Offset;
	DWORD CheckFriendStatusCall2 = WeChatWinBase + CheckFriendStatusCall2Offset;
	DWORD CheckFriendStatusCall3 = WeChatWinBase + CheckFriendStatusCall3Offset;
	DWORD CheckFriendStatusCall4 = WeChatWinBase + CheckFriendStatusCall4Offset;
	DWORD CheckFriendStatusParam = WeChatWinBase + CheckFriendStatusParamOffset;

	WxBaseStruct pwxid(wxid);
	FriendStatusParamStruct FriendStatusParam;

	char* swxid = new char[wcslen(wxid) + 1];
	ZeroMemory(swxid, wcslen(wxid) + 1);
	WideCharToMultiByte(CP_ACP, 0, wxid, -1, swxid, wcslen(wxid), NULL, NULL);
	pwxid.fill1 = (DWORD)swxid;
	pwxid.fill2 = wcslen(wxid);

	wchar_t* message = (WCHAR*)L"我是";

	__asm {
		pushad;
		pushfd;
		mov edi, 0x6;
		mov esi, 0x0;
		sub esp, 0x18;
		mov eax, esp;
		mov dword ptr[eax], 0x0;
		mov dword ptr[eax + 0x14], 0xF;
		mov dword ptr[eax + 0x10], 0x0;
		sub esp, 0x18;
		lea eax, FriendStatusParam;
		mov ecx, esp;
		push eax;
		call CheckFriendStatusCall1;
		push esi;
		push edi;
		mov edi, message;
		sub esp, 0x14;
		mov ecx, esp;
		push -0x1;
		mov eax, edi;
		push eax;
		call CheckFriendStatusCall2;
		// 这里改成0x2就是添加好友,0x1是请求好友状态
		push 0x1;
		lea eax, pwxid;
		sub esp, 0x14;
		mov ecx, esp;
		push eax;
		call CheckFriendStatusCall3;
		mov eax, [CheckFriendStatusParam];
		mov eax, [eax];
		mov ecx, eax;
		call CheckFriendStatusCall4;
		popfd;
		popad;
	}
	while (!LocalFriendStatus && CheckFriendStatusHooked) {
		Sleep(10);
	}
#ifdef _DEBUG
	printf("wxid:%ws,status:0x%02X\n", wxid,LocalFriendStatus);
#endif
	delete[] swxid;
	swxid = NULL;
	return;
}

Hook

__declspec(naked) void doHookVerifyUserResult() {
	__asm {
		pushfd;
		pushad;
		mov eax, [esi];
		push eax;
		call dealVerifyUserResult;
		add esp, 0x4;
		popad;
		popfd;
		call CheckFriendStatusNextCallAddress;
		jmp CheckFriendStatusHookJmpBackAddress;
	}
}

VOID HookFriendStatusCode(){
	if (CheckFriendStatusHooked)
		return;
	DWORD WeChatWinBase = GetWeChatWinBase();
	DWORD dwHookAddress = WeChatWinBase + CheckFriendStatusHookOffset;
	HookAnyAddress(dwHookAddress, doHookVerifyUserResult, OldAsmCode);
	CheckFriendStatusHooked = true;
}

写在后面

测完后发现有20个好友删了我,多数还是妹子,然后就emo了半天。
完整代码参考Github:ComWeChatRobot
有用请给个star,感谢感谢~
最后还是老一套,请勿用于非法用途,不然轻轻松松就能吃上几年牢饭。
需要图文教程留言就好,over~

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值