网络安全 频道

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

  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
相关文章