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.