首页
社区
课程
招聘
[原创]PC微信发送消息研究
发表于: 2018-3-6 14:09 17138

[原创]PC微信发送消息研究

2018-3-6 14:09
17138

最近因为需要要挂机发送消息,所以要在监控的基础上做模拟发送,发送的基本效果就是给定一个wxid,给定消息内容,进行发送。

之前论坛有人已经就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<LPTSTR>(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<LPTSTR>(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了。

通过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发消息了。
再补充一下消息拦截可以在插入的地方拦截,做记录大概这么个位置,直接附加然后搜字符串就能搜到了,下个断点啥都明白了。


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<LPTSTR>(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<LPTSTR>(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);

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2018-3-6 14:14 被大魔头编辑 ,原因:
收藏
免费 1
支持
分享
最新回复 (22)
雪    币: 7860
活跃值: (2259)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2018-3-6 22:33
0
雪    币: 15
活跃值: (230)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
感谢分享
2018-3-7 15:59
0
雪    币: 243
活跃值: (86)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
厉害,学习了
2018-3-25 11:30
0
雪    币: 121
活跃值: (271)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
你好我可以加你qq吗
2018-3-29 14:08
0
雪    币: 206
活跃值: (634)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
感谢分享
2018-3-30 10:53
0
雪    币: 2375
活跃值: (433)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
挂机发送消息,楼主是做公众号的么
2018-3-30 21:23
0
雪    币: 3
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
2018-3-30 22:00
0
雪    币: 289
活跃值: (77)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
谢谢分享
2018-4-1 10:29
0
雪    币: 1224
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
感谢分享思路,
2018-4-12 09:11
0
雪    币: 208
活跃值: (51)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
感谢分享思路.
2018-4-12 09:37
0
雪    币: 80
活跃值: (157)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
12
感谢分享思路
2018-4-23 08:53
0
雪    币: 58
活跃值: (56)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
厉害
2018-4-23 14:15
0
雪    币: 219
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
厉害
2018-4-24 21:46
0
雪    币: 182
活跃值: (21)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
非常感谢您的赐教,受益匪浅啊!
最后我还是想请教您,发图片和发表情,自定义表情      这些怎么弄
2018-6-19 03:45
0
雪    币: 2694
活跃值: (80)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
16
学习
2018-6-19 11:11
0
雪    币: 49
活跃值: (261)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
留下脚印,以后回来!
2018-7-7 07:51
0
雪    币: 2359
活跃值: (288)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
非常感谢,正是我想要的。
2018-7-7 19:25
0
雪    币: 256
活跃值: (71)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
请问是版本的问题吗,版本6.2.7我没找到Duilib上面有关于文件和和文件名的函数,只看到load资源文件类型为zipres的功能部分
2019-2-28 16:01
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
20
您好!能加个好友吗
2020-4-14 13:11
0
雪    币: 2249
活跃值: (3778)
能力值: ( LV6,RANK:81 )
在线值:
发帖
回帖
粉丝
21
牛啤,收藏
2020-4-17 16:28
0
雪    币: 2249
活跃值: (3778)
能力值: ( LV6,RANK:81 )
在线值:
发帖
回帖
粉丝
22
2.8.0.133 dump 成功
2020-4-18 05:07
0
雪    币: 10
活跃值: (10)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
23
厉害厉害mark
2020-4-18 05:18
0
游客
登录 | 注册 方可回帖
返回
//