Análisis de virus: Predator 2
Por Fernando Bonsembiante
Hay un virus nuevo que en muy poco tiempo se convirtió en
epidemia en Argentina: el Predator 2. Veremos como
funciona y por qué puede ser que se haya difundido tanto.
El virus Predator fue escrito por Priest, un miembro del
grupo de creación de virus Phalcon/Skism. En el número 11
de la revista 40HEX, de dicho grupo, salió publicado el
código fuente de una versión anterior del virus, un
infector de .com con algunas características ligeramente
stealth y encripción variable. No es polimórfico, aunque
trata de variar levemente la rutina de desencripción en
cada infección. El stealth que usa es simplemente
esconder el aumento en la longitud del programa
infectado. Si se mira el archivo con algún programa o si
se chequea con un testeador de integridad, aún estando el
virus en memoria se vería que el archivo está cambiado.
Predator 2
Esta nueva versión del virus está basada en la primera,
aunque agrega a la anterior una gran cantidad de técnicas
interesantes. Infecta .com, .exe, sectores de boot en
diskettes y tablas de partición en discos rígidos. Esta
característica, que lo convierte en un virus
multipartito, puede explicar por qué se expandió tanto
por el país. También, obviamente, ayudó a eso que se haya
distribuido deliberadamente desde el BBS de intercambio
de virus de Buenos Aires, Satanic Brain. Y también
podemos agregar que la mayoría de los antivirus que se
usan en el país lo detectaban solamente en los archivos,
y no lo buscaban en los sectores de boot.
Además de ser multipartito, tiene una técnica muy
interesante de tunneling, que lo hace invisible a la
mayoría de los chequeadores residentes de comportamiento.
Puede modificar un archivo ejecutable o un boot sector
sin que ningún residente se entere. Por otro lado, la
rutina de encripción variable se mejoró muchísimo con
respecto a la versión anterior. No es polimórfico
todavía, pero el desencriptor es mucho más variable y
utiliza distintos mecanismos de encripción además de usar
distintas claves. A pesar de que la rutina es muy
variable, quedan las suficientes instrucciones constantes
como para detectar el virus con una cadena simple de
identificación.
La rutina de desencripción es así:
PUSH CS ; Copia CS a DS
POP DS
; Desencripta el virus desde el final. CX = 1213 words,
; 2426 bytes + 22 del desencriptor = total de 2448 bytes.
; Clave de encripción (variable) en AX
MOV DI,01A92
MOV AX,01964
MOV CX,04BD
DESENCRIPTAR:
DEC CX
JS BEGIN ; si termina, ejecuta el virus
ROR W[DI],CL ; método de encripción
XOR W[DI],AX ; variable
DEC DI
DEC DI
JMP DESENCRIPTAR
Además de esto, tiene el mismo grado de stealth que su
predecesor.
Funcionamiento
El virus puede haberse cargado en memoria desde un
archivo ejecutable o desde un sector de booteo. Su
funcionamiento no varía en los dos casos, lo que cambia
es su método de carga y de tomar las interrupciones.
Empecemos describiendo su carga y funcionamiento como si
entrara desde un archivo.
Lo primero que hace es poner BP en 0 para saber que está
siendo cargado desde un archivo. Luego va a llamar a la
interrupción 13h con 50FDh en AX. Si el virus está
residente en memoria debe devolver FD50h en AX. Si está
residente, vuelve al programa infectado sin hacer nada.
Si no está residente, busca el final de la memoria libre,
cambia el valor de la memoria disponible para el DOS,
reservando lugar para el virus, y se copia al final de la
memoria. Cuando está copiado, empieza a ejecutar este
código apilando en el stack la dirección a donde fue
copiado, y luego haciendo un return far a este lugar.
Si el virus no estaba residente, recupera el comienzo del
programa original que había modificado, en caso de que
sea un .com, y salta al principio del programa.
En el caso de que Predator no estuviese previamente en
memoria, va a capturar las interrupciones 13h (40h en
caso de que no haya disco rígido) y 21h. Primero guarda
los valores actuales de las interrupciones en variables,
y toma la interrupción 13h, redefiniéndola con su propio
código. En el caso de que no haya disco rígido instalado,
lo hace con la interrupción 40h.
Luego continúa con la interrupción 21h. Pero en este caso
hace algo muy interesante. Antes de hacer apuntar la
interrupción 21h a su propio código, lo que va a hacer es
instalar las rutinas de tunneling.
Tunneling
El virus busca el punto de entrada a las interrupciones
21h, 13h y 40h definidos por el DOS y el BIOS
originalmente. De esta forma el virus evita ser detectado
por controladores residentes de comportamiento. Para
hacer esto, lo que hace es seguir la ejecución de estas
interrupciones paso a paso, usando el trap flag del
procesador, que genera una interrupción 01h cada vez que
procesa una instrucción. El virus busca el segmento del
DOS utilizando la función 52h de la interrupción 21h,
para luego buscar el código original del DOS. Redefine
la interrupción 01h con un código que buscará los puntos
de entrada originales de estas interrupciones. A
continuación, enciende el trap flag del procesador y
llama a las interrupciones 13h, 21h y 40h. El handler de
la interrupción 01h es el que hace todo el trabajo de
tunneling. Compara el segmento desde donde se está
ejecutando cada interrupción con el del DOS en caso de la
21h y con uno comprendido entre C800 y F000 en caso de
las interrupciones 13h y 40h. Cuando el código se empieza
a ejecutar en esos segmentos, guarda el valor del offset
donde empieza el código, apaga el trap flag, y deja de
seguir paso a paso la interrupción. De esta forma obtiene
los puntos de entrada originales.
A partir de este momento, todo lo que haga el virus para
infectar lo hará a través de los vectores originales, de
esta forma ningún programa residente podrá notar sus
intentos de modificar el sector de booteo o archivos.
Ahora, para redireccionar la interrupción 21h a su propio
código, hace otro truco muy interesante. Intercambia los
5 primeros bytes de la interrupción 21h original del DOS
por un jump far a el handler de la interrupción definido
por el virus. Los 5 primeros bytes quedan en el lugar
donde antes estaba almacenado este código. Para esto usa
una rutina que cada vez que se llama intercambia el
código, de esta forma activando o desactivando la
interrupción 21h del virus. De esta forma, cada vez que
se ejecute la interrupción 21h se ejecutará en su lugar
la del virus, pero a partir del código y la dirección de
la interrupción original. Esto lo hace solamente si el
primer byte del código de la interrupción no es un jmp
far o una interrupción 03h (breakpoint), para no tener
conflicto con programas que hagan algo similar a él.
Entonces, la secuencia de llamado de la interrupción 21h
sería como vemos en el gráfico.
Si el código de la interrupción 21h empezaba con un jmp
far o con un breakpoint, simplemente toma la interrupción
21h desde la tabla de interrupciones como si fuese un
residente normal. En ese caso, desactiva la rutina que
intercambia el jump far al virus por el principio de la
int 21h.
Infección del boot
Después de hacer todo esto, ya instalado en memoria, va a
intentar infectar la tabla de particiones. Lee el sector
1, cilindro 0, del primer disco rígido, y compara el
principio con los ocho primeros bytes del código de su
propio boot sector infectado. Si estaba infectado, vuelve
al programa original y termina. Si no está infectado,
encripta la tabla de particiones recién leída y luego lo
hace con todo el virus. Estas encripciones son siempre
iguales, no intenta modificar la clave ni el método. A
partir del sector 2 del cilindro cero, un área no usada
por ninguna partición, guarda la tabla de particiones
original y el virus en seis sectores contiguos. Luego
infecta la tabla de interrupciones, copiando primero un
desencriptor y a continuación el código de boot del
virus, encriptado con una clave al azar. El desencriptor
es siempre igual, sólo cambia el valor de la clave. Una
vez que la tabla de particiones está infectada,
simplemente la escribe en el disco rígido en el lugar de
la anterior.
Interrupción 13h
La interrupción instalada por el virus tiene dos puntos
de entrada, según si el virus se instaló desde boot o
desde un archivo. Vamos a ver por ahora lo que hace si el
virus entró desde un archivo, para más adelante ver qué
pasa si entró desde el boot sector.
El handler instalado por el virus en la interrupción 13h
(o 40h si no había disco rígido), cumple tres funciones.
Una es verificar la presencia del virus en memoria,
mediante la función 50FDh. Si recibe ese pedido, devuelve
FD50h en AX.
Si la función llamada es leer el sector 1 del cilindro 0
de cualquier disco, o sea, el sector de booteo, se
activan las otras dos funciones. Para elegir cual de las
dos usar, verifica si el boot leído estaba previamente
infectado. Si es así, se activa la rutina de stealth. Lo
que hace es leer el boot record guardado por el virus en
el disco, desencriptarlo, y copiarlo al buffer donde el
programa que llamó a la interrupción lo espera. De esta
forma, lo que se verá será el sector sin infectar. Si no
está infectado, y se trata de un diskette, se activa la
tercer rutina, con la cual lo infectará. No intenta
infectar discos rígidos, porque ya lo intentó al cargar
el programa infectado por primera vez.
Con los diskettes, lo que hace es redefinir el boot
record para que parezca que tienen una pista menos. Luego
de esto, copia al final del disco, en la pista que
definió como que no existe, el virus encriptado, de la
misma manera que vimos antes, salvando el boot original,
e infectando el nuevo boot al igual que con los discos
rígidos.
Interrupción 21h
Lo primero que hace al entrar a la interrupción 21h
redefinida por el virus es reponer los 5 bytes que
modificó en el DOS, para que funcione normalmente.
El virus chequea si se intenta hacer buscar un archivo,
funciones find first o find next del DOS. Dependiendo si
se está haciendo esta función con handles o con FCB lo
trata de una forma distinta. Lo que intenta hacer es
mostrar el tamaño del archivo donde esté el virus como si
no estuviese infectado, y recuperar la fecha original del
mismo, ya que suma 200 al año del archivo como marca de
su presencia. Aquí hay un gran bug. La rutina de manejo
de FCB tiene los offsets del FCB mal definidos. No
entendemos como le pudo pasar esto al autor del virus, ya
que la versión anterior manejaba esto bien. En el caso de
handles lo maneja bien. Lo que hace es llamar a la int
21h original. Con lo que retorna, si el año del archivo
es mayor a 200, le resta su longitud al campo tamaño del
archivo y 200 al campo fecha del bloque de control de
find first o find next. En el caso de que se use FCB, lo
hace mal, y modificaría otros campos que pueden causar
desde nada en absoluto hasta corrupción de datos en el
disco, dependiendo de lo que haga el programa que use
esos datos. Luego de hacerlo, vuelve de la interrupción
después de volver a reemplazar los primeros 5 bytes de la
interrupción 21h.
Otras funciones que chequea son open (abrir archivo),
exec (ejecutar programa) o extended open or create (abrir
o crear archivo). En el caso de esta última, lo único que
hace es mover SI a DX para que el formato de llamada sea
igual a la función open normal, y luego sigue con la
rutina que trata open. Si exec no es load and execute
(cargar y ejecutar), no hace nada, y vuelve.
A continuación, entra en la rutina de infección de
archivos. Redefine la interrupción 24h para que siempre
retorne fail en los errores críticos. Antes de infectar,
se fija si el archivo al que se hace referencia es algún
antivirus de los que tiene en una tabla encriptada. La
tabla contiene lo siguiente:
PROT
SCAN
CLEA
VSAF
CPAV
NAV.
DECO
Obviamente se trata de F-Prot, Scan de McAfee, Clean de
McAfee, Vsafe de McAfee, CPAV (Central Point Anti Virus),
NAV (Norton Anti Virus) y otro que no conocemos que
contiene las letras DECO dentro de su nombre. La misma
rutina que hace esto pone en DI 0 si el archivo es .com.
Si es un anti virus de estos no lo infecta. Si no lo es,
se fija si el archivo tiene el atributo de system. Si es
así, no lo infecta. Si va a infectarlo, borra todos los
atributos del archivo (para evitar que esté como read
only), y lo abre. Verifica con la fecha si está
infectado, y si no lo está procede con la infección.
Infectando los archivos
Lee 24 bytes del principio del archivo, y chequea que los
dos primeros bytes sean 'MZ' o 'ZM'. En esos casos supone
que se trata de un archivo .EXE. Si el archivo es .COM, o
sea DI estaba en 0 de la rutina que verificaba los anti
virus, verifica la longitud del mismo. Si está entre
62088 y 1000 bytes, salva los tres primeros bytes del
programa, agrega en ese lugar un jump al final (donde irá
el virus) y procede a infectarlo. En el caso de que sea
un .EXE, modifica el header de forma en que el punto de
entrada apunte al final (donde irá el virus). También
cambia la longitud del archivo en el header como para que
cargue el virus junto con el programa, y modifica los
requerimientos de memoria declarados por el programa para
que el virus pueda funcionar. Si la longitud del archivo
es mayor a la declarada en el header, supone que hay
overlays adosados al programa o que hay algo agregado al
mismo, y no lo infecta.
Luego de modificar los headers, infecta al archivo.
El encriptor
Antes de infectar el archivo, el virus tiene que generar
una versión encriptada de sí mismo y una rutina para
desencriptarse al ejecutar el programa. Cada vez que
infecta el archivo elige al azar una rutina diferente de
encripción. Para esto va a utilizar una zona de trabajo,
donde primero va a copiar un desencriptador que tiene
como modelo. Luego lo va a modificar, poniendo una clave
al azar. Elige de una tabla de siete posibles una
instrucción que va a ser la operación que se le aplicará
al código junto a la clave que ya eligió al azar, y luego
elige otra de la misma u otra tabla, 14 posibilidades
distintas. Esas dos instrucciones son copiadas al
desencriptador, y las complementarias a la rutina de
encripción que luego generará el código del virus
encriptado. Una vez generado el desencriptador, copia a
continuación todo el código del virus encriptado. El
desencriptador es variable, pero tiene una gran parte que
es constante en todas las infecciones. Por este pequeño
detalle el virus no puede considerarse polimórfico. Una
vez generado todo esto, copia el virus de la zona de
trabajo al final del archivo.
Cuando infectó el archivo, lo cierra, vuelve a ponerle
los atributos que tenía previamente, recupera la
interrupción 24h original, y sigue con la interrupción
21h original, con un jump far. Pero como debe cambiar los
5 primeros bytes para que vuelvan a apuntar al virus, lo
que hace es volver a prender el trap flag, y utilizar una
rutina instalada en la interrupción 01 que cuenta 5
instrucciones y vuelve a modificar el código de entrada a
la interrupción 21h. Con esto se ejecuta la interrupción
21h del DOS normalmente y luego el virus recupera el
control.
Cargando desde boot
Si se carga del boot sector, lo que hace es primero
desencriptar el resto del boot sector recién cargado, que
como vimos antes estaba encriptado. Luego disminuye la
cantidad de memoria declarada por el BIOS en 6k, y lee el
virus a esa zona de memoria. En este punto usa una
estrategia que no es muy inteligente. Si en algún momento
que está leyendo un sector recibe un error, en vez de
reintentar llama a la interrupción 18h, que llamaría al
Basic en una IBM PC, pero que causa un reboot en la
mayoría de los clones. Como muchas veces que se lee un
diskette hay que hacer un par de reintentos antes de
lograr leer bien, muchas veces falla la carga del virus
desde diskette.
Después de cargar el virus en memoria, copia una rutina
inmediatamente antes de la posición donde se cargó el
boot sector (0:7C00h), y salta a ese punto. Esta rutina
carga el boot sector original guardado por el virus en el
disco sobre el infectado, lo desencripta, y hace un call
al virus en memoria. El virus hace lo que ya vimos antes:
toma la interrupción 13h y trata de infectar el sector de
arranque del disco rígido. Cuando termina ejecuta el
sector de booteo cargado previamente.
El detalle a tener en cuenta es que sólo tomó la
interrupción 13h, y no la 21h. Obviamente, en este punto
el DOS no está cargado, así que no tiene sentido tratar
de tomar la interrupción 21h. Lo que hace es activar una
rutina dentro del handler de la interrupción 13h
instalada por el virus que espera que se instale el DOS
para tomar la interrupción 21h. Para esto espera que el
vector cambie a un offset superior a 0800h, donde se
cargará seguramente el DOS. Una vez que lo detecta,
desactiva esta rutina de la int 13h, hace apuntar el
vector al virus, y sigue con la interrupción 13h
original. Notemos que en este caso no activa la rutina
que modifica la interrupción 21h, y que la toma como si
fuera un programa residente normal. Como en el punto
donde tomó la interrupción 21h no hay cargado ningún
residente, el virus no tiene que preocuparse por hacer
tunneling ni redireccionar la entrada de la interrupción.
Código muerto
Dentro del virus, luego de desensamblarlo completamente,
notamos que hay tres trozos nunca referenciados. Dos de
ellos contienen mensajes encriptados: 'Here comes the
Predator!' y 'THE PREDATOR'. El tercero todavía no
sabemos que significa, aunque parece una rutina nunca
usada:
MOV SP,09C9B
XCHG AX,DI
POPF
LAHF
MOV W[BP+DI+0E09C],DS
MOV W[BX+DI+0BFE0],SS
SCASB
MOV BP,0D2AA
RCL DL,CL
RETF
Conclusión
Este virus es, como diría Borges, 'más complicado que
complejo'. Tiene muchos mecanismos muy interesantes de
ocultamiento, pero por momentos la implementación es muy
confusa y difícil de seguir. Esto explicaría por qué los
anti virus tuvieron tantos problemas en detectarlo
correctamente. De todas formas, usa algunos conceptos ya
conocidos pero en una forma muy creativa e inteligente, y
funciona lo suficientemente bien como para ser un
problema. Si el polimorfismo estuviese mejor hecho y
tuviese un stealth más completo, sería casi un virus
perfecto.
Fernando Bonsembiante es jefe de redacción de Virus
Report y está estudiando los virus informáticos dese hace
varios años. Es consultor de seguridad informática de
varias empresas. Tambien es miembro de la comisión
directiva del Círculo Argentino de Ciencia Ficción,
(CACyF) y participa como columnista de varias revistas
sobre informática. Puede ser contactado por Fido en
4:901/303 o en Internet en ubik@ubik.to