,, MMP""MM""YMM `7MM P' MM `7 MM MM MMpMMMb. .gP"Ya MM MM MM ,M' Yb MM MM MM 8M"""""" MM MM MM YM. , .JMML. .JMML JMML.`Mbmmd' `7MMF' `7MF' `7MMF' `7MMF' `MA ,V MM MM VM: ,V `7M' `MF' MM MM .gP"Ya ,6"Yb.`7M' `MF'.gP"Ya `7MMpMMMb. MM. M' `VA ,V' MMmmmmmmMM ,M' Yb 8) MM VA ,V ,M' Yb MM MM `MM A' XMX MM MM 8M"""""" ,pm9MM VA ,V 8M"""""" MM MM :MM; ,V' VA. MM MM YM. , 8M MM VVV YM. , MM MM VF .AM. .MA..JMML. .JMML.`Mbmmd' `Moo9^Yo. W `Mbmmd'.JMML JMML. ,, ,, ,, .g8"""bgd `7MM `7MM mm db .dP' `M MM MM MM dM' ` ,pW"Wq. MM MM .gP"Ya ,p6"bo mmMMmm `7MM ,pW"Wq.`7MMpMMMb. MM 6W' `Wb MM MM ,M' Yb 6M' OO MM MM 6W' `Wb MM MM MM. 8M M8 MM MM 8M"""""" 8M MM MM 8M M8 MM MM `Mb. ,'YA. ,A9 MM MM YM. , YM. , MM MM YA. ,A9 MM MM `"bmmmd' `Ybmd9'.JMML..JMML.`Mbmmd' YMbmd' `Mbmo.JMML.`Ybmd9'.JMML JMML. -- Contact -- https://twitter.com/vxunderground email@example.com
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:
|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):
|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|
|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.