|
Desensamblando el código de una aplicación infectada
podemos ver claramente cómo está estructurado Girigat,
ya que el autor del virus, Mister Sandman, fiel a su
trayectoria, no ha implementado en este espécimen tipo
alguno de encriptación.
El inicio del código consiste, como de costumbre, en
la típica rutina de call+pop+sub, empleada con
el fin de obtener el desplazamiento relativo o delta
offset. En este caso Girigat emplea un pequeño truco
de optimización, moviendo el valor sacado de la pila
al registro EBX, para la posterior obtención de la
dirección base del programa huésped o host.
El paso siguiente consiste en obtener la dirección
real o VA (Virtual Address) del punto de entrada o
entry point del host. Tanto este paso como el
anterior (la obtención de la dirección base) están
basados en valores guardados por el propio virus en
su código, en variables dinámicas, durante el momento
de la infección; estos valores los obtiene gracias a
la información proporcionada al respecto por la
cabecera PE de las aplicaciones que infecta. Su
formato es el conocido como RVA (Relative Virtual
Address), que necesita como complemento vital la
dirección base del programa en ejecución de cara a
conseguir la dirección real (VA), que es la que
verdaderamente representa la situación en memoria,
una vez que la aplicación está en ejecución, de cada
uno de los bytes de dicha aplicación. Así las cosas,
todo se resumiría en la siguiente fórmula:
RVA + dirección base = VA (dirección real)
Tras la cual enseguida comprendemos la necesidad por
parte de cualquier virus de Win32 de guardar todas
las RVAs necesarias para el proceso de inicialización,
así como de obtener la dirección base del proceso
actual, con el fin de poder dar juego a dichas RVAs.
Una vez que Girigat ha completado esta etapa, más
tediosa de explicar que de programar (constituye
menos de diez líneas de código), el siguiente paso
consiste en obtener la dirección de las APIs
necesarias para su funcionamiento. Muchos de los
virus que hoy en día existen para Windows cometen
el error de asumir direcciones absolutas para cada
una de estas APIs, lo cual presenta de entrada como
gran inconveniente el hecho de que el virus será
completamente dependiente de la plataforma en la
que fue programado: si fue programado en WindowsNT
no funcionará en Windows95 o 98, y viceversa, de
la misma manera que corre el riesgo de no funcionar
en versiones posteriores del sistema. El motivo es
tan sencillo como observar que la dirección de una
misma API en una y otra plataforma varía de manera
ostensible.
La solución más sólida planteada a este problema
por parte de los escritores de virus de la scene
vino de la mano de Jacky Qwerty, del grupo español
29A; es por esto que Mister Sandman, autor de
Girigat y ex-miembro fundador del grupo, decidió
seguir en su virus la línea propuesta por Jacky y
ya vista en otros virus de este grupo. Esta
solución a la que nos referimos consiste en sacar
partido de la API GetProcAddress, que permite
al programador obtener la dirección actual de
cualquier API documentada del sistema.
No obstante la solución al problema no es tan
sencilla. Para un mayor aprovechamiento de la
memoria, los desarrolladores de Win32 decidieron
en su momento distribuir las APIs en diversos
módulos, que aparecen en forma de DLLs en el
directorio \SYSTEM de Windows. Por esta razón,
cada vez que se llama a la API GetProcAddress
es necesario indicar, además del nombre de la
API cuya dirección buscamos, la dirección del
módulo al que dicha API pertenece, y es aquí
donde aparece un nuevo problema para el escritor
de virus: ya que las APIs básicas que necesita
emplear para que su virus funcione correctamente
pertenecen al módulo KERNEL32.dll, antes de
poder llamar a la API GetProcAddress deberá
haber obtenido la dirección de dicho módulo.
La alternativa más clara de cara a solventar este
pequeño escollo, además de la más frecuente entre
los virus de Win32, es la de llamar a la API
GetModuleHandle, la cual, tras solicitarle el
nombre del módulo deseado, nos devuelve la dirección
base de dicho módulo. Otros autores de virus han
optado por métodos menos estables, dependientes en
cualquier caso de asumir por defecto una dirección
absoluta (hardcoded) de KERNEL32. No obstante,
llegados al punto de ir a usar GetModuleHandle,
se nos presenta un nuevo problema: ¿cómo va el
virus a obtener la dirección de dicha API, si
precisamente la está llamando porque desconoce la
dirección de las APIs que necesita usar en su
código? se les plantea aquí todo un caso de
"huevo-gallina" a los escritores de virus, que,
cómo no, han salido al paso una vez más con
distintas soluciones al problema.
Probablemente la solución más extendida a este
inconveniente es la que consiste en guardar las
RVAs de GetModuleHandle y GetProcAddress dentro
del código vírico durante la infección de una
determinada aplicación. Dado que la práctica
totalidad de los ejecutables "normales" de Win32
incluyen estas dos APIs en su tabla de importación
o IT (Import Table), muchos virus se aprovechan
durante el momento de la infección para buscar
las RVAs de estas dos APIs, y así emplearlas en
su posterior inicialización. Éste es el método
que hemos visto emplear en virus como Cabanas o
Marburg y que, sin embargo, presenta un par de
inconvenientes que desaconsejan su uso. El más
claro es el hecho de que muchas de las aplicaciones
que poseemos en nuestro ordenador, especialmente
las del sistema, aparecen binded, mientras que
otras muchas aplicaciones están unbinded. La
diferencia radica en el empaquetamiento o no de
los nombres de las APIs listadas en la IT, y esto
es algo que plantea ciertos problemas a los virus
que emplean la técnica anteriormente citada, con
especial énfasis desde el momento en el que ya no
sólo existen binds y no binds, sino que también
han aparecido, de la mano de Microsoft, los new
binds, característicos de Windows98 y NT, y que
difieren sustancialmente de los empleados en
Windows95. Por otra parte, el segundo de los
inconvenientes radica en el hecho de que, en el
caso de que una aplicación infectada bajo, por
ejemplo, Windows98, fuese copiada a NT, el virus
dejaría de funcionar, ya que estaría asumiendo una
serie de RVAs intrínsecas de Windows98, pero que
en ningún caso guardan relación con NT.
Girigat es de los pocos virus que va más allá y
plantea una alternativa más sencilla y estable:
en lugar de basarse en RVAs obtenidas durante el
proceso de infección, el virus escanea la IT de su
host para buscar la dirección base de la API
GetModuleHandle. La IT de cada aplicación PE es
rellenada con los datos correspondientes una vez
que dicho programa ha sido ejecutado, de manera
que Girigat se encuentra con el 50% del trabajo
hecho mediante este sencillo pero ingenioso truco,
teniendo la certeza de estar manejando en todo
momento datos de una fuente tan fidedigna como el
propio sistema en el que está corriendo.
Llegados a este punto es importante resaltar la
existencia de los formatos ANSI y Unicode. Con el
primero tanto europeos como americanos ya estamos
familiarizados desde Windows 3.1x, mientras que
el segundo constituye toda una novedad de la mano
de Windows95 y sucesivas versiones, ya que está
diseñado para dar soporte a alfabetos distintos
del latino, el griego y el cirílico, como pueden
ser el árabe, el hebreo, el chino o el hindú, al
que más tarde en este análisis haremos referencia
por otro motivo. El sistema Unicode está basado en
conceder dos bytes, en lugar de uno, a cada letra
o carácter que posea dicho formato. De esta forma
se emplea el segundo byte como identificador del
tipo de carácter que constituye el primer byte de
la serie. En el siguiente ejemplo lo veremos con
mayor claridad:
Texto "HispaSec" en ANSI:
db "H","i","s","p","a","S","e","c"
Texto "HispaSec" en Unicode:
db "H",0,"i",0,"s",0,"p",0,"a",0,"S",0,"e",0,"c",0
En este caso, al tratarse del alfabeto latino, el
byte de control permanece a cero, dígito que sería
distinto en caso de tratarse de otro tipo de
alfabeto, como los ejemplos citados anteriormente.
Lo que aquí nos interesa es que la aparición del
Unicode ha afectado también en lo que a la
programación de las propias aplicaciones se
refiere, y así, lo que en Windows 3.1x era la API
GetModuleHandle, a partir de Windows95 ha pasado
a llamarse o bien GetModuleHandleA (versión ANSI,
que requiere cadenas en formato ANSI como parámetros)
o bien GetModuleHandleW (versión Unicode, que
requiere cadenas en formato Unicode como parámetros,
aunque en ciertos casos también admite ANSI). Lo
realmente importante a este respecto en lo que
concierne al análisis de Girigat, y en general de
cualquier virus compatible de Win32, es que, a pesar
de que en Windows9x es prácticamente improbable
topar con aplicaciones que empleen APIs en Unicode
debido a la falta de soporte, en NT son tanto o
más frecuentes que las APIs en ANSI, por lo que,
si un virus quiere funcionar en NT en las mismas
condiciones en las que lo hace bajo Windows9x, debe
tener en cuenta la existencia de APIs en Unicode,
y saber cómo manejarlas a partir de ciertas rutinas.
Girigat no es menos, y la primera puesta en práctica
de la teoría anterior se produce en los primeros
bytes de su código, cuando busca GetModuleHandle
en la IT de su host: se trata de los pocos virus
de Win32 que tienen en cuenta el hecho de que, si
su host no importa GetModuleHandleA, posiblemente
sí que importe GetModuleHandleW. Es muy probable
que esta circunstancia se dé en pocas ocasiones,
pero en cualquier caso el autor del virus parece no
estar dispuesto a perder ni una sola ocasión de
hacer que su virus funcione.
Llegados a este punto, uno de los pasos más tediosos
ya está dado: una vez que el virus conoce la dirección
base de la API GetModuleHandle ya está en entera
disposición de, llamando a dicha API, conocer también
la dirección base del módulo KERNEL32. A partir de
aquí el punto de atención se centra en torno al uso
de la API GetProcAddress, especialmente en lo que
respecta a su obtención. Una vez más, muchos virus,
quizás una mayoría, han optado por obtener la RVA de
esta API durante el proceso de infección del ejecutable
que actualmente hace las veces de huésped. El virus
Girigat vuelve a optar por una vía alternativa mediante
la cual evita los inconvenientes anteriormente
descritos, y en este caso, conocedor de la dirección
base de KERNEL32.dll, se limita a escanear su tabla
de exportaciones o ET (Export Table) con el fin de
encontrar la API GetProcAddress, emulando el
funcionamiento de dicha API. Aquí uno podría pararse
a pensar por qué Girigat no busca directamente en
la ET de KERNEL32 todas las APIs que necesita, en
lugar de buscar tan sólo GetProcAddress para tal
fin... ¿no sería más directo, rápido y lógico optar
por lo primero? Lo cierto es que desconocemos la
respuesta a esta pregunta, y lo único que podemos
pensar es que probablemente Mister Sandman decidió
emplear GetProcAddress y no un escaneo constante
de la ET de KERNEL32 para evitar posibles conflictos,
especialmente bajo NT, ya que el empleo de la citada
API tiende a ser más estable.
El caso es que, con las direcciones base de KERNEL32
y de GetProcAddress en el zurrón, el virus está por
fin en condiciones de obtener el resto de las APIs
necesarias para poder trabajar, las cuales consigue
por medio de un bucle un tanto lioso, debido a la
cantidad de registros que entran en juego. Tras esto
podemos darle la bienvenida a lo que es la acción
vírica en sí, que ha necesitado valerse del código
que acabamos de describir para poder ejecutarse sin
complicaciones.
|