Analisis de virus: polimorfismo
Por Fernando Bonsembiante
Con el tiempo los virus se fueron complicando. Las
técnicas de encriptación originales se convirtieron en
'mutating engines', con lo cual un virus es distinto cada
vez que contagia un archivo nuevo.
Uno de los más primitivos y efectivos medios de detección
de virus, por lo menos el más usado, es la identificación
por medio de strings. Esta técnica es usada por los anti
virus más famosos, como el Scan, el F-Prot o el Dr.
Solomon Toolkit. Básicamente, lo que hace es buscar una
determinada secuencia de bytes que son características
del virus y aparecen en todos los archivos o discos
infectados por él. Este método es a primera vista
infalible para detectar un virus conocido, aunque es
inútil contra los nuevos. El primer mecanismo que usaron
los autores de virus para enfrentar esto fue el
'stealth', que consistía en 'engañar' al sistema
operativo para que cada vez que se leía un disco o
archivo infectado éste pareciera estar limpio. De esta
forma, los anti virus no podían verlo en un archivo
cuando el virus estaba activo en memoria y en control del
sistema operativo. Los antivirus solucionaron ésto
buscando el virus en memoria por si estaba activo, y en
disco por si no lo estaba. Esta técnica fue usada desde
hace mucho tiempo, uno de los virus stealth clásicos es
el 512, escrito por el búlgaro Dark Avenger. Como el
stealth no basta para hacer indetectable a un virus, se
dió un paso más. La idea es que si el virus es distinto
cada vez que infecta un archivo, el scanner no puede
buscar una secuencia de bytes constante. Para esto
algunos autores de virus pensaron en encriptar el virus
cada vez de una manera distinta, y el primer virus famoso
que utiliza esta técnica, llamada polimorfismo, fue
escrito también por Dark Avenger. No solo es uno de los
primeros en utilizar esta técnica, sino que es el primero
en el mundo en crear un toolkit para ayudar a la creación
de virus, justamente con un módulo que permite agregar a
casi cualquier virus que infecte archivos la capacidad de
ser polimórfico. Este módulo se llama MtE, o Mutating
Engine, y se distribuye en los BBS de virus en forma de
un .obj con todo el código necesario, la documentación
necesariam y la fuente de un virus en assembler, el
'dedicated', para usarlo como ejemplo. Después de este
toolkit, aparecieron varios más, como ser el TridenT
Polimorphic Engine, escrito por Masud Khafir del TridenT
virus research group, el Dark Angel Multiple Encryptor o
DAME, escrito por Dark Angel de Phalcon/Skism, y el
Visible Mutation Engine escrito por Mark Ludwig de Virus
Development Quarterly. Todos ellos funcionan de manera
similar.
Funcionamiento del polimorfismo
En principio, el polimorfismo parece ser una técnica
infalible. Simplemente hay que encriptar el código de
maneras distintas, por ejemplo, obteniendo una clave al
azar cada vez que se quiera encriptar, para que siempre
sea distinta. Pero no todo es tan fácil como parece. En
principio, el código encriptado no es ejecutable
directamente. Hay que agregar un desencriptor que antes
de que se ejecute el virus en sí lo convierta en algo
ejecutable. El problema es que el desencriptor es siempre
básicamente el mismo código y sería trivial para un anti
virus buscar los bytes que lo componen para detectar el
virus fácilmente. Obviamente, la cosa no es tan sencilla,
porque si fuera así, los virus polimórficos no diferirían
de los normales en la dificultad para ser detectados. El
truco se basa en que hay más de una manera de hacer el
mismo algoritmo en assembler. Por ejemplo, las
instrucciones
mov ax, 0
xor ax, ax
mov ax, 1
dec ax
etcétera, tienen básicamente los mismos resultados. De
esta forma es posible lograr una rutina que haga una
determinada acción y escribirla de muchas maneras
distintas. Por lo tanto, para crear una mutating engine
hay que incorporar al virus un mini generador de código
que cree un desencriptor distinto cada vez que se
encripte el virus. Ahora si, el virus puede ser
completamente distinto en cada archivo que infecte, y es
imposible de detectar utilizando técnicas tradicionales
de búsqueda de secuencias de bytes. De todas formas,
todavía es posible detectar uno de estor virus,
utilizando técnicas algorítmicas.
Funcionamiento de un mutating engine
El polimorfismo, a diferencia del stealth, es algo que se
le puede agregar a un virus sin cambiar su funcionamiento
básico. Para hacer un virus stealth, hay que hacerlo
stealth desde el principio, todo el virus debe estar
planeado para ser stealth. Un virus polimórfico, en
cambio, puede ser cualquier virus de archivo al que
simplemente se le agregue esta característica, por eso es
posible la creación de kits que ayudan a la creación de
virus polimórficos. Hay una sola consideración a tener en
cuenta: el método con el que el virus detecta los
archivos infectados, para no reinfectarlos. El método
normal es buscar una secuencia de bytes en la posible
víctima, y si esa secuencia está presente, no infectarla.
El método es el mismo, en principio, que usan los anti
virus para encontrar los virus conocidos. En un virus
polimórfico este método es incompatible con el mismo
propósito de la técnica usada. Para auto detectarse debe
utilizar un método que no dependa del contenido del
archivo. Una posibilidad es marcar los ejecutables
infectados cambiando la fecha a una determinada, o mejor,
modificando el campo de los segundos (algo a lo que nunca
se le presta atención) para que tengan un valor
determinado que indique al virus que ese archivo no debe
infectarse. Esta 'marca' no puede utilizarse para
detectar el virus ya que programas normales podrían tener
ese valor en el campo de los segundos, y el antivirus
reportaría un virus donde no hay ninguno.
Una rutina de polimofismo, o 'mutating engine',
normalmente consta de tres partes: un generador de
números aleatorios, para generar las claves de
encripción, una rutina de encripción, y un generador de
código para crear una rutina de desencripción distinta
cada vez que se encripte un virus. Es obvio que la parte
realmente importante de esta rutina es el generador de
código. Es fácil hacer un generador de números pseudo
aleatorios lo suficientemente poderoso como para
encriptar el cuerpo de virus de miles de formas
distintas. La rutina de encripción es sencilla, por
ejemplo puede ser así:
ENCRIPTA:
mov bl,0 ; numero aleatorio 1
hagoLoop:
xor [si],bl
inc si
add bl,0 ; numero aleatorio 2
loop hagoLoop
retn
En este caso, en esos ceros que se mueven al registro bl,
hay que agregar el numero aleatorio que se use como
clave, en este caso, dos distintos. Para eso la rutina
debe modificarse a si misma, cambiando el valor del dato
según la clave que se use en el momento. Esto podría
hacerse usando variables, pero de esta forma la rutina es
más corta y más difícil de desensamblar. Como dijimos
antes, la parte realmente importante de toda esta rutina
es el generador de desencriptores. Si se usara un mismo
desencriptor todo el tiempo el virus tendría siempre una
parte constante y sería fácilmente detectable. Las
técnicas que se usan normalmente son varias, y cuantas
más se usen más variable será el código. Una es agregar
instrucciones que no hagan nada entre las que realmente
sirven para desencriptar. Un caso obvio es agregar la
instrución NOP (no operation, o sea, no hacer nada), pero
analizando el desencriptor se puede ver que si se usan
por ejemplo sólo los registros AX y CX, cualquier
instrucción que modifique únicamente BX no tendrá efecto
en el código. Tambien pares de instrucciones que se
anulen mutuamente sirven. Si tomamos el caso anterior
podemos ver que:
ENCRIPTA:
mov bl,0 ; numero aleatorio 1
hagoLoop:
xor [si],bl
inc si
add bl,0 ; numero aleatorio 2
loop hagoLoop
retn
es totalmente equivalente a
ENCRIPTA:
mov bl,0 ; numero aleatorio 1
mov ax, 10
hagoLoop:
xor [si],bl
dec ax
inc si
inc ax
add bl,0 ; numero aleatorio 2
add ax, cx
loop hagoLoop
retn
En este caso se juega con el registro ax, que no modifica
en absoluto el resultado. Agregando instucciones de este
tipo se pueden obtener miles de variantes de la misma
rutina. Otra técnica que se utiliza es, dado que el
desencriptor es un algoritmo, y que los algoritmos pueden
ser implementados de distintas maneras, es variar la
implementación, por ejemplo usar al en vez de bl para
manejar los datos. Otra posibilidad es utilizar más de un
par encriptor-desencriptor, usar algoritmos distintos y
elegirlos aleatoriamente.
Todo esto puede complicarse de muchas formas, pero estos
son los procedimientos básicos que usan los virus
polimórficos que ya existen.