Boot Infectors

By Dark Angel
[Phalcon/Skism]

         As most of our readers have no doubt noticed, 40Hex articles have
    traditionally covered file based viruses. It is time to fill in the hole and
    cover the other large class of viruses, the partition table and boot sector
    viruses, herein termed "boot infectors" for brevity.
         File based viruses are executed after the operating system loads. Boot
    infectors, however, latch onto the parts of the drive that are accessed by the
    BIOS when it attempts to load the operating system itself. Therefore, there is
    little that can be done to intercept the boot infector once it has
    successfully installed itself onto a disk.
         A brief explanation of the basics of disk terminology is in order. Each
    disk is divided into 512 byte chunks called sectors. Due to an unfortunate
    choice in terminology, however, the system BIOS uses the term "sectors"
    differently. For our purposes, we will divide the disk into 512 byte blocks,
    with block 0 residing on the beginning of the disk.
         The system BIOS assigns three values to each block on the disk. The
    values are known as sectors, cylinders (sometimes known as tracks), and heads
    (sometimes called sides) and can be represented as a triple
    (sector,cylinder,head). Each disk has a certain number of sectors (SEC),
    cylinders (CYL), and heads (HDS). Cylinders are numbered from 0 to CYL - 1.
    Heads are numbered from 0 to HDS - 1. Sectors, for some unfathomable reason,
    are numbered from 1 to SEC. Block 0 corresponds to the triple (1,0,0) (sector
    1, cylinder 0, head 0). Block 1 corresponds to (2,0,0), Block 2 with (3,0,0),
    and so on, until Block SPH. Block SPH corresponds to (1,1,0), Block SPH+1 with
    (2,1,0), and so on. Block 2*SPH is (1,2,0), Block 2*SPH+1 is (2,2,0), etc.
    This continues until Block HPC*SPH, which is (0,0,1).
         An introduction to the boot process is vital to understanding boot
    infectors. When the system is reset, the BIOS checks the first block, triple
    (1,0,0), of the first hard drive of the system (if any are installed, of
    course) to absolute memory address 7C000. If the hard drive exists, the block
    that was read in is checked for the signature 0AA55 (in reverse word format)
    occuring at offset 1FE. This is the marker for a valid partition table. If a
    partition table is found, the code residing in this block is executed at
    0:7C00. If a valid partition table is not found (or the hard drive doesn't
    exist), then the BIOS tries booting from the floppy drive. It again reads the
    first block from the first floppy drive to absolute memory address 7C000. If
    there is a readable disk in the drive, it will be loaded in and executed. No
    check is made for the 0AA55 signature, although many boot sectors have it
    there anyway just for consistency.
         Technically, the first block of the hard disk is a boot sector just as it
    is on floppies. However, it is sometimes given a different name because of the
    partition table convention that allows multiple operating systems to reside on
    a single drive. We will call it by the somewhat misleading name of partition
    table. Another common name is the Master Boot Record, for reasons that will
    become clear momentarily. The partition table convention is basically a simple
    structure at the end of the first block of the hard drive that defines where
    each operating system exists on a given hard drive. The partition table
    structure begins at offset 1BE in the block and consists of an array with four
    entries. The format of each entry is:

    Ofs Size Description
     0  BYTE boot indicator, 0 = non-bootable, 80h = bootable
     1  BYTE head the partition begins on
     2  BYTE sector the partition begins on
     3  BYTE cylinder the partition begins on
     4  BYTE system indicator, indicates what OS resides in the partition
             01 indicates DOS 12-bit FAT
             04 indicates DOS 16-bit FAT
     5  BYTE head the partition ends on
     6  BYTE sector the partition ends on
     7  BYTE cylinder the partition ends on
     8 DWORD total number of blocks preceding the partition
    0C DWORD total number of blocks in the partition

         The code in the partition table loads the boot record of the active
    partition (as indicated in the first bit of the partition table structure).
    The boot record then loads the operating system that resides in its respective
    partition.
         When BIOS decides to boot from a floppy, it reads in the first block off
    the floppy to 7C000. Floppies don't have partition tables, so this block is
    the equivalent of the boot record of a partition on a hard disk.
         In DOS, the boot record consists of three bytes for a JMP followed by the
    following structure, sometimes known as the BIOS parameter block (BPB):

    Offset  Size     Description
      3     8 bytes  OEM name and version (ASCII)
     0B     Word     bytes per sector
     0D     Byte     sectors per cluster
     0E     Word     reserved sectors (starting at logical sector 0)
     10     Byte     number of FATs
     11     Word     number of root directory entries (32 bytes each)
     13     Word     total sectors in partition
     15     Byte     media descriptor
     17     Word     sectors per FAT
     19     Word     sectors per track
     1B     Word     number of heads
     1D     Word     number of hidden sectors

         The rest of the boot record consists of code that loads and executes the
    DOS system files, which then take over. There are a number of terms in the
    above structure which may be unfamiliar, but don't fret; they will be
    explained in due course.
         First, however, it is important to note that nothing requires these
    structures to exist! The partition table, for example, is merely a de facto
    convention which was set up to allow operating systems to co-exist on a single
    hard drive. The boot record structure defined above is used by DOS for DOS
    programs. Of course, another operating system could interpret the structure,
    but there is no requirement for a given operating system to use that format.
    When infecting disks, however, keep in mind that certain programs require the
    structures to be in place. DOS, for example, won't recognise partitions
    properly without the partition table being at its usual location. Floppies
    also won't work properly if the boot record is not loaded when DOS requests a
    read to the first block. In other words, make sure that all requests to the
    partition table or boot record return the partition table and boot record in
    the appropriate locations. The other code may be changed with the only
    drawback in such a scheme being easy detection of the code modifications. A
    better approach is to redirect requests to the modified blocks to a stored
    copy of the original. In other words, stealth.
         Seeing these structures, the method of infection, conceptually, at the
    very least, should be apparent. It's a simple matter to replace the code of
    the partition table or boot record with your own. All your code has to do is
    store the block somewhere else on the disk and replace the block with itself.
    When the virus gains control, it needs to put itself in memory and then load
    the original block into memory at 7C000 and then transfer control to this
    code. Once it is in memory, it is free to infect any disks which come into
    contact with the computer.
         This is all nice and easy to say, but there are a few details which would
    be helpful to know before plunging into writing a boot infector. When control
    is transferred to either the partition table or boot record, CS:IP is set to
    0:7C00. SS:SP is undefined, so most boot infectors set it to 0:7C00, which
    causes the stack to be placed just below the loading area. This is sufficient
    for the needs of most viruses.
         Additionally, it would be nice to be able to locate empty space to store
    the original boot sector or partition table. Here, the virus has a number of
    choices. In hard disks, many viruses store the original partition table in the
    unused space between the partition table and the first partition. The first
    partition generally starts at triple (2,1,0) or later (some start as late as
    (2,0,1), so there is a wealth of space in which to store the virus in that
    area. A simple calculation reveals that there are (number of cylinders - 2)
    sectors between (1,0,0) where the partition table is and (2,1,0) where the
    first partition starts). Multiply that value by 512 and you have the number of
    bytes you can store there. That's a large chunk of space you have at your
    disposal. A virus may also store itself at the end of the root directory,
    although it risks overwriting valid directory entries. The BPB contains
    everything necessary to calculate the location and length of the root
    directory.
         An alternate approach, which is used by several viruses, is to alter the
    File Allocation Table, or FAT. The FAT is an array of entries which describe
    how the blocks on the disk are related. FAT entries are either 12 or 16 bits
    long, depending on the disk. 12 bit FAT's are generally used in disks and
    partitions with less than 20740 sectors and 16 bit FAT's are used in larger
    disks and partitions. The location and size of the FAT can be found in the
    BPB. Each entry in the FAT corresponds to a block on the disk. The FAT
    describes a file's placement on the disk. By following the chain, you can find
    the location of the blocks of the file, since they need not be contiguous. The
    value of the FAT entry is the number of the next block in the chain, i.e. an
    index to the FAT entry corresponding to the next block of the file, unless it
    is one of the special values. If the value of the FAT entry is 0, then the
    block is unused. If the value is -1 to -8 (FFF8-FFFF) then the block is the
    last block in a file. If the value is -9 to -10h (FFF0-FFF7) then the block is
    reserved (usually a bad block). The first and second entries in the FAT are
    always -1. The third entry governs the first data area. The idea is for the
    virus to find empty blocks, mark them as bad in the FAT, and store the code
    there. This way, DOS thinks the blocks are bad and does not overwrite the
    virus.
         One important issue with partition table infectors is whether they should
    preserve the partition table itself, i.e. leave the partition table structure
    at offset 1BE in the first block of the disk. Similarly, should boot sector
    infectors retain the BPB? This is a particularly interesting issue with
    stealth viruses, viruses which redirect attempts at accessing the partition
    table or boot sector. The advantage of retaining the structures is that DOS
    will recognize the disks even when the virus is not loaded in memory.
    Therefore, the virus is somewhat less vulnerable to detection. However, if the
    virus does not keep the structure, then it will be more difficult for the user
    to boot the computer without loading the virus in memory, since DOS will not
    recognise the drive. This is an especially nifty feature, since primitive
    cleaning attempts such as FDISK/MBR will fail against such a virus.
         Within this motley assortment of information, you will find enough to aid
    you in crafting an original boot infector. There is intentionally no code in
    this tutorial, mainly because there is little virus-specific information
    contained within. Many of the routines used in a boot infector are important
    when writing any boot sector, so there is little importance in repeating the
    code here.