|
Echando un vistazo inicial al cuerpo vírico, tras haber desencriptado el código, se aprecian sin mayor dificultad las rutinas de inicialización del virus "Pusher", que ya presentan alguna particularidad digna de análisis.
El código comienza con una instrucción "call", que le permite al virus obtener el desplazamiento relativo (más conocido como "delta offset") dentro del programa huésped o "host". Inmediatamente después del "call" aparecen los tres bytes iniciales de la cabecera original del "host", que preceden a la firma que contiene el nombre del virus.
Esta cadena legible, la única del virus, contiene el texto "[PUSH]", que finalmente no fue respetado por el organismo CARO -el encargado de rebautizar los virus informáticos, de acuerdo con cierta normativa-, habiéndolo renombrado a "Pusher.374", denominación que hace referencia indirecta al nombre original del virus y al comportamiento que caracteriza al código de desencriptado o "decryptor" generado por su "engine" polimórfica.
Tras la citada cadena de texto llegamos al punto al que salta el flujo del código tras el "call" inicial. El código que aquí encontramos obtiene en el registro SI, directamente desde la pila, la dirección de los tres bytes pertenecientes a la cabecera del "host". Tras
esto, apunta con el registro DI al inicio del código del programa y, mediante dos instrucciones, restaura en memoria la cabecera del "host", de forma que, al acabar de ejecutarse el código infeccioso, el retorno al programa original y su posterior ejecución no dejarán ningún indicio de actividad vírica.
La forma en la que el virus "Pusher" efectúa este proceso llama la atención por el truco que emplea para optimizar bytes. El hecho de que la cabecera original del "host" aparezca después del "call" inicial y de que el registro empleado para obtener la última dirección de la pila sea SI no es fruto de la casualidad. Normalmente los virus residentes restauran su huésped tras haberse instalado en memoria... el virus "Pusher", que también es residente, altera el orden de estas operaciones con un claro propósito: ocupar menos bytes, ser más pequeño.
El truco al que nos referimos, a pesar de ser muy básico, resulta muy efectivo y, sobre todo, original. Cuando en lenguaje ensamblador se efectúa una llamada a una rutina mediante la instrucción "call", el sistema almacena en la pila la dirección de la instrucción siguiente al citado "call". Por otra parte, las instrucciones de tipo "movs" que nos provee el ensamblador nos permiten mover en memoria un byte (movsb), una palabra (movsw), una doble palabra (movsd)... indicando con SI ("source index") y DI ("destination index") el origen y el destino de los bytes que queremos desplazar. Con estas nociones básicas en mente entendemos al instante el truco empleado por el virus, especialmente si nos apoyamos en la siguiente representación:
xxxx:0100h call 10Ch ; Salta al offset 10Ch
xxxx:0103h db xx,yy,zz ; Cabecera original
xxxx:0106h db '[PUSHER]' ; Firma del virus
xxxx:010Ch pop si ; SI -> 103h (cabecera)
xxxx:010Dh mov di,100h ; DI -> inicio del código
xxxx:0110h push di ; Guarda 100h en la pila
xxxx:0111h movsb ; Un byte de SI a DI
xxxx:0112h movsw ; Dos bytes de SI a DI
De esta forma, como vemos, mediante las instrucciones "movsb" y "movsw", habiendo apuntado previamente de forma estratégica al búfer de la cabecera y al origen del código (que es 100h, ya que es un fichero COM), el virus restaura los tres primeros bytes de su "host" en memoria. Además, al guardar el valor 100h con un "push", el retorno al host se puede efectuar en cualquier momento mediante la instrucción "ret", que salta a la última dirección almacenada en la pila. En este caso será 100h, con lo que el virus saltará al inicio del programa, el cual, tras haber sido previamente restaurado en memoria, se ejecutará sin ningún problema.
|