|
1、前言
直至QQ推出了2007版本,QQ尾巴还是会出现.QQ的源程序没有加过壳,通过反汇编可以得到源码,这给想修改QQ的人提
供了方便,例如珊瑚虫。我在参考了网上的一些资料后自己做了一个qq尾巴友好版程序,模拟了QQ尾巴中把文字黏贴到
QQ的输入框中的效果.
本人才疏学浅,本文肯定会有说得不对的地方,欢迎大家指出!
2、实现原理
a、找到QQ的对话窗口(前提肯定是要先打开一个聊天窗口拉!),QQ聊天窗口的布局是这样的:
*“#32770”(QQ聊天窗口的第一层窗口)
|
|——*“#32770”(QQ聊天窗口的第二层,“发送”“聊天模式”等按钮都在这层里面,这两个按钮很重要!)
|
|——*“AfxWnd42” (真正的输入框是在这一层!)
最终我们是要找到“AfxWnd42”所在的窗口,然后找到RichEdit控件,找到就可以@##¥了!
b、把文本粘结进RichEdit中,首先把文字复制到剪切版,因为QQ的RichEdit控件控件是做了保护的,不能直接发送
WM_PASTE消息过去(这个让我郁闷了很久,最后终于找到解决办法!),不能直接黏贴就只能模拟按键信息了
(QQ再厉害也不可能禁止我按ctrl+v吧?),现在就是要模拟 ctrl+v的按键效果!我的做法就是找到QQ对话窗口后
把它置顶,然后模拟 ctrl+v!这样文字就可以粘进RichEdit里面了。(真正的QQ尾巴是在用户按下“发送”
按钮后才把文本粘进去的,那时焦点是落在QQ对话窗口里的,但是我 这里QQ对话窗口不一定能获得焦点,所以
黏贴时必须让它获得焦点!)
3、具体实现
a、寻找QQ窗口
这里主要是用到FindWindowEx,GetWindowText,FindWindow函数(这些函数的具体使用请上网查查)
HWND getTheFirst_window()
{
HWND temp_handle = 0;
char *flag="no";
TCHAR szText[500];
szText[0] = '\0';
CString temp_str;
CString temp_str1;
TCHAR szText_8[500];
int str_length=0;
while((temp_handle = FindWindowEx(0,temp_handle,"#32770",NULL))!=NULL)
{
::GetWindowText(temp_handle,szText,sizeof(szText));
//AfxMessageBox(szText);
//使用CString截取以适用所有窗口
temp_str = szText;
temp_str1 = szText;
str_length = strlen(szText);
temp_str = temp_str.Mid(str_length-6,str_length);
lstrcpy(szText, temp_str.GetBuffer(6));
temp_str.ReleaseBuffer();
temp_str1 = temp_str1.Mid(str_length-8,str_length);
lstrcpy(szText_8, temp_str1.GetBuffer(8));
temp_str1.ReleaseBuffer();
//AfxMessageBox(szText_8);
if(strcmp(szText_8,"发送消息")==0||strcmp(szText,"聊天中")==0)
{
//AfxMessageBox(szText);
break;
}
}
return temp_handle;
}
说明:试过了几种寻找QQ聊天窗口的方式,最后选用了这种,用FindWindowEx寻找Class Name是#32770的窗口,你会发
现竟然不止一个!!(真奇怪,不过对窗口不熟,不知道为什么),因为会有很多个#32770,所以要筛选一下,“发送
消息”,“聊天中”,熟悉吧?对拉,就是QQ聊天窗口顶部的文字啊!(好像没什么技术含量。。。。),好,成功!
终于完成了一小步!接下来就要找输入框了!
下面这个函数是网上找的,直接用好了!
/*---------------------------------------------------------------------
递归枚举hFatherWindow指定的窗口下的所有子窗口和兄弟窗口,
返回和lstyle样式相同的窗口句柄,如果没有找到,返回NULL
---------------------------------------------------------------------*/
HWND GetStyleWindow(HWND hFatherWindow, const long lstyle)
{
//如果这个窗口符合查找条件,返回此句柄
if (GetWindowLong(hFatherWindow, GWL_STYLE) == lstyle)
{
return hFatherWindow;
}
HWND hNextWindow, hDestWindow;
//得到子窗口句柄
if ((hNextWindow = GetWindow(hFatherWindow, GW_CHILD))!= NULL)
{
//递归查找子窗口
if ((hDestWindow = GetStyleWindow(hNextWindow, lstyle)) != NULL)
{
return hDestWindow;
}
}
//递归查找兄弟窗口
if ((hNextWindow = GetWindow(hFatherWindow, GW_HWNDNEXT)) != NULL)
{
return GetStyleWindow(hNextWindow, lstyle);
}
//没有匹配的则返回NULL
return NULL;
}
说明:这里的lstyle参数其实就是窗口的风格(QQ第二层窗口的样式是0x50000044,好像一直都是这个值不知道为什
么,可能是系统定义好的!所以每次都不会变!)
通过以上两步,终于找到了QQ输入框所在的窗口!(year!)下面就要寻找传说中的RichEdit了!
//获得输入框的句柄 RichEdit RichEdit20A RICHEDIT
HWND get_RichEdit_handle(HWND hChildWnd)
{
HWND hAfxWnd = 0;
HWND hRichEditWnd = 0;
while((hAfxWnd=FindWindowEx(hChildWnd,hAfxWnd,"AfxWnd42",NULL))!=NULL)
{
if((hRichEditWnd=FindWindowEx(hAfxWnd,0,"RichEdit20A",NULL))!=NULL)
{
//AfxMessageBox("找到RichEdit");
break;
}
}
return hRichEditWnd;
}
谢天谢地!终于找到RichEdit的句柄了!下面可以开始粘一段文字进去了!(兴奋吧?)
把QQ尾巴文字粘到剪切版中
::OpenClipboard(NULL);
EmptyClipboard();
// 分配内存空间
hMem = GlobalAlloc(GMEM_DDESHARE,sizeof(g_str));
pStr = (char*)GlobalLock(hMem);
lstrcpy(pStr, LPCSTR(g_str));
GlobalUnlock(hMem);
// 设置剪贴板文本
SetClipboardData(CF_TEXT, hMem);
CloseClipboard();
// 释放内存空间
GlobalFree(hMem);
//获得对话窗口的坐标 getwindowrect,因为把QQ窗口置顶的时候位置要和它缩小的时候一样。
::GetWindowRect(NodeWindow,&rect);
//把窗口置顶
::SetWindowPos(NodeWindow,HWND_TOPMOST,rect.left,rect.top,0,0,SWP_SHOWWINDOW||SWP_NOMOVE||SWP_NOSIZE);
//模拟ctrl+v按键
keybd_event(VK_CONTROL,(BYTE)0,0,0);
keybd_event('V',BYTE(0),0,0);
keybd_event('V',BYTE(0),KEYEVENTF_KEYUP,0);
keybd_event(VK_CONTROL,MapVirtualKey(VK_CONTROL,0),KEYEVENTF_KEYUP,0);
黏贴完给“发送”按钮发个BM_CLICK消息,尾巴就送出去了。
到此,我的QQ尾巴就完成了。
4、总结
我的QQ尾巴技术含量不高,而且还有很多东西没实现,例如,把这个程序做成dll然后用hock拦截QQ窗口的发送消
息,然后执行QQ尾巴程序等等。。。。。(这些难度较大)整个制作的过程遇到很多问题,但是最终还是得以解决。这个发现问题-
-解决问题的过程让我很快乐!
感谢大家花时间阅读本文章。 |
|