最近因为需要要挂机发送消息,所以要在监控的基础上做模拟发送,发送的基本效果就是给定一个,给定消息内容,进行发送。
之前有人已经就duilib和发送消息进行了研究,我也只是在看了他们以后完成的。
因为历史原因,微信版本是1.0.25。本教程仅作为学习研究。
1.Hook CDialogBUilder::Create
这里主要是为了拿到解密的xml以及获取控件的指针地址。
如何找到这个函数的地址,通过搜索字符串“加载资源失败“,“Duilib”。找到以后,上面的两个函数就是了。然后进行hook。
获取文件名和文件,我hook了两个地方。

void __declspec(naked) MyDumpDuilibXml() 
 { 
 __asm{ 
 pushfd 
 pushad 
 push [esp+0x30] 
 push [esp+0x30] 
 push [esp+0x30] 
 push ecx //拿到文件名 
 call CLoadXmlFromMem_Ret 
 popad 
 popfd 
 jmp[g_dumpDuilibXml] 
 } 
 } 
 unsigned g_dumpxmlGetFileName = 0;void __declspec(naked) MyDumpDuilibXmlGetFileName() 
 { 
 __asm{ 
 pushfd 
 pushad 
 push [esp+0x28] 
 call CDumpDuilibXmlGetFileName 
 popad 
 popfd 
 jmp[g_dumpxmlGetFileName] 
 } 
 } 
 WCHAR * g_currentXmlFileName = NULL;VOID WINAPI CDumpDuilibXmlGetFileName(WCHAR* currentXmlFileName) 
 { 
 g_currentXmlFileName = currentXmlFileName; 
 } 
 VOID WINAPI CLoadXmlFromMem_Ret(void* cmakeup ,BYTE* pByte,int dwSize,int encoding) 
 { 
 LPTSTR m_pstrXML; 
 if( dwSize >= 3 && pByte[0] == 0xEF && pByte[1] == 0xBB && pByte[2] == 0xBF ) 
 { 
 pByte += 3; dwSize -= 3; 
 DWORD nWide = ::MultiByteToWideChar( CP_UTF8, 0, (LPCSTR)pByte, dwSize, NULL, 0 ); 
 m_pstrXML = static_cast(malloc((nWide + 1)*sizeof(TCHAR))); 
 ::MultiByteToWideChar( CP_UTF8, 0, (LPCSTR)pByte, dwSize, m_pstrXML, nWide ); 
 m_pstrXML[nWide] = _T(‘\0’); 
 }else 
 { 
 DWORD nWide = ::MultiByteToWideChar( CP_ACP, 0, (LPCSTR)pByte, dwSize, NULL, 0 ); 
 m_pstrXML = static_cast(malloc((nWide + 1)*sizeof(TCHAR))); 
 ::MultiByteToWideChar( CP_ACP, 0, (LPCSTR)pByte, dwSize, m_pstrXML, nWide ); 
 m_pstrXML[nWide] = _T(‘\0’); 
 } 
 if (g_currentXmlFileName) 
 { 
 TCHAR szPath[MAX_PATH] = {0}; 
 TCHAR szDrive[MAX_PATH] = {0}; 
 TCHAR szDir[MAX_PATH] = {0}; 
 TCHAR szFileName[MAX_PATH] = {0}; 
 TCHAR szExt[MAX_PATH] = {0}; 
 wstring filepath = L”D:\tempxml\”;filepath.append(g_currentXmlFileName); 
 wcscpy(szPath, filepath.c_str()); 
 split_path(szPath, szDrive, szDir, szFileName, szExt); 
 filepath = L”D:\tempxml\”; 
 filepath.append(szFileName); 
 filepath.append(szExt); 
 //_cwprintf_s(_T(“filepath %ws\r\n”), filepath.c_str()); 
 HANDLE hFile = CreateFile(filepath.c_str(), 
 GENERIC_WRITE, 0, NULL, 
 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0); 
 DWORD dwBytesWriten = 0; 
 int nRet = WriteFile(hFile, pByte, dwSize, &dwBytesWriten, NULL); 
 CloseHandle(hFile);g_currentXmlFileName = NULL; 
 }}

大概这样hook一下以后就能得到所有的完整的Xml了。

微信开发发送消息 微信发起_WXID爆粉

通过xml我们可以得到微信的duilib的布局以及控件名称,为之后我们进内存搜代码提供方便。
并且在创建完成之后我们需要拿到input_richedit的控件地址,因为之后要做setText操作。
2.hook Notify 同样看论坛的hook代码基本不需要改,就行。
其实hook了Notify函数以后,我们可以模拟发送消息如何发送呢?

void * g_CHookNotify_base = 0; 
 void Notify(TNotifyUI& msg) 
 { 
 extern CHookNotify::pfn_Notify g_pfn_oldnotify; 
 if (!g_CHookNotify_base) 
 { 
 g_CHookNotify_base = this; 
 _cwprintf_s(L”g_CHookNotify_base %p\r\n”, g_CHookNotify_base); 
 } 
 return (this->*g_pfn_oldnotify)(msg); 
 }


这里提前保存一下ecx的指针。
然后调用:

CHookNotify * pthis = (CHookNotify*)g_CHookNotify_base; 
 TNotifyUI * mewmsg =new TNotifyUI; 
 mewmsg->sType = CDuiString(_T(“click”)); 
 mewmsg->sVirtualWnd = CDuiString(_T(“”)); 
 mewmsg->pSender = g_profileSendBtn; 
 mewmsg->dwTimestamp = ::GetTickCount(); 
 mewmsg->ptMouse.x = 0; 
 mewmsg->ptMouse.y = 0; 
 mewmsg->wParam = NULL; 
 mewmsg->lParam =NULL;
int * p = (int*)((int)pthis+0xDE0);
wstring aaa( pwxid); 
 VString * pstring = new VString; 
 pstring->pstting = (WCHAR*)aaa.c_str(); 
 pstring->size = aaa.size(); 
 memcpy(p,pstring,sizeof(pstring)); 
 pthis->Notify(*mewmsg);

当然这里用到了g_profileSendBtn,这个在获取input_richedit的时候同步获取的。这里模拟的就是选择某个联系人然后点击发消息。
联系人的wxid 保存在偏移0xDE0的地方了,这个偏移如何找,主要是通过跟踪点击事件的处理函数。其实所有的消息处理都在
g_pfn_oldnotify这里进行的,找到profileSendBtn的字符串就能找到处理函数。
这一步进行了以后,你要发送的wxid就会被至于session_list的顶端,这样就算session_list本身没有也会自动添加。

__asm{ 
 pushfd 
 pushad 
 mov eax ,writestring 
 push eax 
 mov ecx,g_input_richedit 
 mov eax,[g_input_richedit] 
 mov eax,[eax] 
 call [eax+0x2C] 
 popad 
 popfd 
 }


然后调用settext把文本加入进去,0x2C可以根据调用一下getText得到,在它的下一个函数就是了。
最后点击发送

__asm{ 
 pushfd 
 pushad 
 mov ecx,pWinImplBase 
 call g_sendText 
 popad 
 popfd 
 }


可以采用模拟点击的调用,也可以直接这样。随便那种都行,这样就能对任意wxid发消息了。
再补充一下消息拦截可以在插入的地方拦截,做记录大概这么个位置,直接附加然后搜字符串就能搜到了,下个断点啥都明白了。

微信开发发送消息 微信发起_微信WXID爆粉_02