VR9: Analisis de virus: Darth Vader
Por Fernando Bonsembiante
Analizamos un virus búlgaro muy especial. No se diferencia de los demas por usar técnicas muy sofisticadas ni es demasiado complejo, pero utiliza un par de técnicas que pueden dejar a un antivirus genérico muy mal parado.
El problema de los virus suele ser el decidir el lugar en donde ocultarse, tanto en memoria como en el disco. Algunos, que infectan archivos, lo solucionan mediante el simple procedimiento de no ocultarse, quedando como residentes en memoria y agregando su código al programa infectado. Otros toman acciones más complejas, como buscar áreas de memoria que puedan usurpar al DOS, por ejemplo, el 512 se mete en un buffer de disco. Para ocultarse en los archivos, las tecnicas utilizadas pueden ser, por ejemplo la stealth, que hace a los virus completamente invisibles cuando están en memoria. El problema de los stealth es que cuando no están activos en memoria se nota en seguida que algo raro pasa en el disco, porque los archivos tienen errores, faltan cosas, o hay clusters cruzados cuando se hace un chkdsk. Por otro lado, la infección de un archivo puede detectarse fácilmente con un chequeador de integridad, y si el ejecutable fue modificado, de alguna forma podemos detectar el cambio con un programa y notar que hubo algo raro. La forma que tiene el Darth Vader de evitar todo esto es lo que lo diferencia de los demás virus.
Un virus distinto
Este virus fue escrito en Bulgaria, en la ciudad de Sofía, por Waleri Todorov (no confundir con Todor Todorov, sysop del Virus eXchange BBS), a principios de 1991. Como ya explicó Vesselin Bontchev en su artículo (ver Virus Report 5), lo hizo para probar una nueva idea, y para acceder al BBS de intercambio de virus. Como lo hizo específicamente para este BBS, dejó a disposición de quien lo quisiera el código fuente del mismo. Este empieza con un cartel indicando quién es el autor y cómo funciona el virus. Según este mensaje, el mismo fue escrito en CICTT-Sofia. CICTT significa "Central Institute for Computer Technic and Technology". Está escrito para Tasmb, un assembler integrado con editor y linker que se usa mucho en Bulgaria para la creación de virus, porque requiere de muy poca memoria o espacio en disco para funcionar. Por esto mismo, el código es imposible de compilar con un assembler normal sin hacerle bastantes modificaciones. Para nombrar algunos de las diferencias de este lenguaje, basta con mostrar el principio del código del virus según su fuente original:
org 0 ; Comenzar en offset 0
nop ; NOPs inútiles. No sacarlos.
nop
nop
call NextLine ; Llamar a la siguiente
instrucción
NextLine
pop bx ; Para calcular su propia dirección
sub bx,6 ; Dirección guardada en BX
Es claro que esto es incompilable con cualquier assembler, ya que empieza en el offset 0 (para hacer un .COM, como es el caso de este virus, hay que empezar con offset 100h). Los labels, como por ejemplo NextLine, no terminan con el carácter ':', y hay varias incompatibilidades más que hacen difícil ensamblarlo con otro compilador que no sea Tasmb. Para poder estudiar este virus a partir de su fuente hubo que modificarlo, con lo cual conseguimos un virus funcionalmente idéntico pero con algunas diferencias mínimas en el programa ejecutable. Estas se deben a la diferencia con el código que genera el Tasmb con el que genera el Tasm de Borland que usamos para estudiarlo. De todas formas, estas diferencias no influyen en nada en su funcionalidad ni en el largo del archivo.
El virus no es destructivo en ninguna forma, y solamente puede causar algun problema en algunas versiones del DOS y afectar algunos de los archivos infectados en formas extrañas si es que usan el área en la cual se mete el virus para variables inicializadas. Lo mas interesante del virus es que busca áreas de memoria del DOS o de un archivo que contengan los suficientes ceros como para ocultarse dentro de ellas. Infecta sólo a los archivos .COM que contengan más de 255 ceros consecutivos como para contenerlo. Supone que esos ceros son simplemente espacio de variables no inicializadas y que no va a a afectar el funcionamiento del programa metiéndose en ese lugar.
Para ocultase en memoria busca el segmento que ocupa el DOS y tambien busca una zona de 255 ceros consecutivos para copiarse allí. De esta forma, no aparece en ningún listado de memoria hecho con ningun programa. Simplemente utiliza una parte libre de la memoria correspondiente al DOS. Para infectar archivos, tambien utiliza una técnica especial. No modifica ningun archivo en el disco, lo que sería fácilmente detectable si usamos un verificador de integridad. Lo que hace es esperar que el DOS vaya a grabar en el disco un archivo .COM para agregarle al buffer de memoria el virus si encuentra un espacio de ceros lo suficientemente grande. Por esto, modifica solamente la memoria y no los archivos en el disco. Como no toca los ejecutables del disco, un verificador de integridad no notaría nada raro, y no detectaría el virus. Cuando se copia un ejecutable, el verificador de integridad recién en ese momento crea los datos necesarios como para calcular su integridad en el futuro y considera que está sano. Ya que el virus ni siquiera modifica la longitud del archivo, no es fácil detectar la infección. Por eso nunca hay que confiar en un solo tipo de protección antivirus, ya que siempre hay una forma de engañarla. Tambien este método de copiado, hay que reconocerlo, no es demasiado efectivo, y es algo lento, aunque no es imposible pensar en métodos más efectivos. A esta técnica se le dio el nombre de Slow Infection, o infección lenta, y se puede considerar a la par de otras como stealth en peligrosidad.
Para dar una idea de lo peligrosa que puede ser esta técnica, Vesselin Bontchev, en un artículo aparecido en Virus News International del mes de Junio de 1993, imagina un virus extremadamente difícil de detectar usando técnicas convencionales de detección por comportamiento o por comprobadores de integridad. Este virus imaginario, llamado Kuang (por el virus 'lento' descripto por William Gibson en su novela Neuromante), combina las técnicas de stealth con las de slow infector, más algunas otras, para que sea extremadamente difícil de detectar.
Funcionamiento
Darth Vader empieza con tres instrucciones NOP, que no hacen nada. Luego de eso, hace un CALL a la siguiente instrucción, para que en el stack aparezca la dirección de retorno. Esa dirección de retorno menos 6 es el offset del virus dentro del segmento. Esto es necesario, ya que como el virus se copia a los espacios de ceros dentro de los ejecutables, nunca va a estar en el mismo lugar del archivo, por lo tanto usa ese método para calcularlo. Ese CALL no retorna nunca, porque saca la dirección de retorno del stack y con eso anula el efecto de la instrucción. Lo siguiente que hace es guardar el valor de AX con que fue llamado el programa huésped para poder pasarle el control más tarde con ese valor. Para ocultarse dentro de la memoria, empieza a buscar un área de ceros lo suficientemente grande dentro del segmento del DOS. Para esto busca el vector de la interrupción 2Bh. Esta apunta a un IRET, no es usada para nada, y por lo tanto es muy probable que apunte al segmento del DOS en memoria. En el segmento al que apunta esta interrupción empieza a buscar, desde el offset cero, en los primeros 4096 bytes, el área de ceros que necesita. Para esto, llama a la siguiente subrutina con 1000h (4096 decimal) en CX.
SearchZero:
xor ax,ax ; Poner 0 en AX para buscar
; ceros
Again:
inc di ; incrementar el puntero ES:DI
push cx ; Guardar CX
push di ; Guardar DI
mov cx,LastByte_offs ; CX = tamaño del virus
repe scasb ; Buscar hasta que sea igual
pop di ; Restaurar DI
jcxz FoundPlace ; Si CX es igual a 0
; entonces ES:DI apunta
; a ceros
pop cx ; Si no, restaurar CX
loop Again ; y seguir con el loop
; hasta que CX sea distinto a 0
stc ; Si CX es igual a 0, no
encontró
ret ; Encender CF (carry) y volver
FoundPlace:
pop cx ; Restaurar CX
clc ; Apagar CF (ES:DI apunta a
; un área de ceros)
ret ; Volver
Esta rutina devuelve un puntero al area de ceros adecuada en ES:DI, si la encuentra. En caso de no encontrarla, pone el flag de carry en 1. Si no puede instalarse en memoria, en el caso de no encontrar espacio libre suficiente, le pasa el control al programa huésped y no intenta instalarse. Esta es la única comprobación que hace de si está previamente instalado en memoria: supone que si no encuentra lugar es porque el virus ya está instalado. En el caso muy poco probable de que hubiese lugar para copiarse en memoria dos veces, la segunda vez que se ejecute un programa infectado quedaría residente duplicado en la memoria.
Una vez que encontró el lugar adecuado, el virus procede a modificar la interrupción 21h para instalar su rutina de infección. Lo que hace es algo muy poco estándar y muy interesante. Para entender lo que hace, debemos explicar como funciona la interrupción 21h, la que maneja casi todos las funciones del DOS. Para diferenciar entre función y función del DOS, hay que llamar a la interrupción 21h con distintos valores en el registro AH. El DOS tiene una tabla interna que apunta a cada rutina que maneja cada función, y llama a cada función con un CALL indexado según esa tabla. Como el DOS reside todo en el mismo segmento, esa tabla tiene solamente el offset dentro de ese segmento, o sea, dos bytes por rutina. Todo esto es cierto para el DOS en sus versiones anteriores a la 5 y posteriores a la 3. La forma de hacer un CALL indexado es la siguiente:
mov bx, cs:[bx+offset_tabla]
call [bx]
En offset_tabla tenemos el offset en donde empieza la tabla en el segmento del DOS, y luego el CALL le pasa el control a la rutina deseada. En BX, antes de ejecutar estas dos instrucciones, tenemos el número de función del DOS multiplicado por dos, ya que cada offset ocupa dos bytes, y las funciones están ordenadas por número. Lo que hace el virus es modificar la tabla para que la función 40h del DOS, la que se usa para escribir archivos en el disco, apunte a su propio código. Como el virus tambien reside en el segmento del DOS, esto no presenta ningún problema. Con este método, el virus toma control y se ejecuta cada vez que se copia un archivo sin haber modificado para nada la tabla de interrupciones, y está residente sin que ningun programa pueda detectarlo. Para encontrar esta tabla, el virus busca ese mov bx, cs:[bx+offset_tabla], buscando los códigos hexadecimales de esa instrucción: 2E 8B 9F. Los dos bytes siguientes son el offset de la tabla. Toda esta información es muy difícil de conseguir; nosotros la conseguimos gracias a la ayuda de Vesselin Bontchev que muy amablemente nos dió toda la información necesaria como para comprender esta estructura no documentada del DOS. Esto habla muy bien de los conocimientos de los programadores búlgaros de virus (tambien de los expertos búlgaros en virus, como Bontchev), que conocen estos secretos del DOS tan bien. Lamentablemente estos conocimientos fueron usados, en este caso, para hacer un virus.
Como vemos, esta forma de tomar la interrupción 21h función 40h funciona sólo en algunas versiones de DOS. Es mas, el loop que implementa la busqueda no tiene condición de salida, así que en el caso de no encontrar esos tres bytes en todo el segmento el virus quedaria colgado, colgando la maquina. Más aún, el método de esconderse en los ceros no funciona en DR-DOS porque usa para otras cosas el área de ceros y el virus termina siendo sobreescrito. En algunas circunstancias, tampoco anda muy bien bajo algunas versiones de DOS, porque parte del virus termina siendo sobreescrita. El fuente del virus aclara que funciona de DOS 2 en adelante, y en versiones menores que 5.0.
Despues de instalar el handler de la interrupción 21h función 40h, el virus se copia a la zona de ceros elegida, restaura los tres primeros bytes del programa huésped (los que había modificado como veremos más adelante), y vuelve al programa original que se ejecuta normalmente, como si no estuviese infectado.
Contagio
El virus en memoria se activa cada vez que se intenta escribir un archivo en disco. En el momento en que se llama al handler de la función 40h del DOS el virus toma el control y verifica si el archivo que se va a escribir tiene la extensión .?OM. Este comportamiento puede ser peligroso, ya que usando este método puede corromper archivos cuya extensión termine con OM y no sean .COM. Para buscar el nombre del archivo, utiliza algunas funciones no documentadas de la interrupción 2Fh. Si el archivo no es un .COM, vuelve al handler original del DOS. Si es .?OM, toma los tres primeros bytes del buffer, que supone que son los tres primeros bytes del programa, por donde se empieza a ejecutar un .COM, y los guarda en un área de variables del virus. Luego busca un área de ceros lo suficientemente grande como para ocultarse, usando la rutina que ya describimos. En el caso de no encontrarla, vuelve al handler original sin infectar el archivo. Si hay lugar, se copia al buffer del archivo en memoria, modifica los tres primeros bytes del buffer para que apunten al virus, así se ejecuta cuando se carga el programa, y vuelve al handler original del DOS. Esta rutina del mismo DOS es la que se encarga de escribir el virus en el disco, en el archivo modificado por el DOS. Notaremos que no chequea en ningun momento si el archivo estaba previamente infectado, por lo que si se copia dos veces consecutivas un archivo con suficientes ceros como para contener dos veces al virus, el archivo va a quedar doblemente infectado. Esto en principio no sería demasiado problema porque lo más probable es que no pueda quedar residente en memoria dos veces.
Conclusión
Como vimos, este virus es muy pequeño (sólo 255 bytes) pero utiliza una técnica muy novedosa para pasar inadvertido, y debe servirnos de advertencia contra quienes pretenden controlar con un programa genérico todos los virus existentes, ya que este virus es extremadamente difícil de detectar con métodos convencionales.