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