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.