Chapter – 12
Reading and Modifying MBR with Programming
Master Boot Record (MBR) or Master Partition Table (MPT)
The Master Boot Record (MBR) or sometimes referred as The master partition table (MPT), is created on the hard disk drive by executing FDISK.EXE command of DOS.
The MBR contains a small program to load and start the active (or bootable) partition from the hard disk drive. The Master boot Record contains information about all four primary partitions on the hard disk drive such as the starting sector, ending sector, size of the partition etc.
The MBR is located at Absolute Sector 0 or we can say at cylinder 0, head 0, and sector1 and if there is more than one partition are present in the disk there are Extended Master Boot Records, located at the beginning of each extended partition volume.
For detailed description refer the chapter “Logical Approach to Disks and OS”, discussed earlier in this book.
Master boot record format
We may partition the Hard Disk Drive into several logical drives which are generally assigned their own drive letter by DOS). Only one partition at a time can be marked as the active (or bootable) Partition.
The Master Boot Record has the limit of four entries in the Master Partition Table. However the location of Extended Master Boot Record can be obtained with the help of Master Boot Record that contains Extended Partition Tables, whose format is exactly the same as of the main Partition Table except there is no boot code and this space of 446 Bytes is normally reserved for the boot code and remains empty.
All the 512Bytes of The Master Boot Record are Broken as follows, given in the Table:
All the extended partitions should exist within the space reserved by the extended partition entry. Only two of the extended partitions are meant to be used, the first as a normal partition and the second as another extended partition if exists.
Thus with the help of one Master Partition Table We can get the location of another Extended Master Partition Table next to it, if present.
Partition Table Entry Format
The format of partition table entry of any Partition in MBR has been given in the next table. Every Partition Entry of any MBR may be broken into the following bytes with their specific meanings:
Writing program to read the partition table of MBR
The program to read all four partition entries from partition table of MBR has been given next. The program displays all the parameters of partition information, written in partition table of MBR.
The coding of the program is as follows:
/* Program To Read MBR Partition Table */
# include <bios.h>
/* structure to read the partition entry from partition table */
struct partition
{
unsigned char bootable ; /* Active Partition Byte */
unsigned char start_side ;/* Starting Head */
unsigned int start_sec_cyl ; /* combination of
Starting sector and
cylinder number */
unsigned char parttype ; /* File system
Indicator Byte */
unsigned char end_side ; /* Ending Head */
unsigned int end_sec_cyl ; /* combination of
Starting sector and
cylinder number */
unsigned long part_beg ; /* Relative Sector
Number */
unsigned long plen ; /* Partition length in
sectors */
} ;
/* Structure to read MBR */
struct part
{
unsigned char master_boot[446] ; /* IPL (Initial
Program Loader)*/
struct partition pt[4] ; /* Partition table */
int lasttwo ; /* Magic Number */
} ;
struct part p ;
void main()
{
clrscr();
/* Read First Sector of first hard disk */
biosdisk ( 2, 0x80, 0, 0, 1, 1, &p ) ;
display(); /* Display the information of MBR
Partition Table */
getch();
}
/* Function to Display the Information Of partition table of MBR */
display()
{
unsigned int s_sec, s_trk, e_sec, e_trk, i, t1, t2 ;
char type[20], boot[5] ;
printf("\n\nPart. Boot Starting location
Ending Location Relative Number of");
printf("\nType Side Cylinder Sector
Side Cylinder Sector Sectors Sectors\n");
for ( i = 0 ; i <= 3 ; i++ )
{
if ( p.pt[i].bootable == 0x80 )
strcpy ( boot, "Yes" ) ;
else
strcpy ( boot, "No" ) ;
switch ( p.pt[i].parttype )
{
case 0x00 :
strcpy ( type, "Unused" ) ; break ;
case 0x1 :
strcpy ( type, "FAT12" ) ; break ;
case 0x2 :
strcpy ( type, "Xenix" ) ; break ;
case 0x3 :
strcpy ( type, "Xenix:usr" ) ; break ;
case 0x4 :
strcpy ( type, "FAT16<32M" ) ; break ;
case 0x5 :
strcpy ( type, "DOS-Ext." ) ; break ;
case 0x6 :
strcpy ( type, "FAT16>32M" ) ; break ;
case 0x7 :
strcpy ( type, "NTFS" ) ; break ;
case 0x0b :
strcpy ( type, "FAT32" ) ; break ;
case 0x0c :
strcpy ( type, "FAT32-LBA" ) ; break ;
case 0x0d :
strcpy ( type, "VFAT16" ) ; break ;
case 0x0e :
strcpy ( type, "VFAT16-LBA" ) ; break ;
case 0x0f :
strcpy ( type, "VFAT EXT" ) ; break ;
case 0x17 :
strcpy ( type, "HPFS" ) ; break ;
case 0x81 :
strcpy ( type, "Old LINUX" ) ; break ;
case 0x82 :
strcpy ( type, "LinuxSwap" ) ; break ;
case 0x83 :
strcpy ( type, "LinuxNative" ) ; break ;
case 0x85 :
strcpy ( type, "Linux Ext." ) ; break ;
default :
strcpy ( type, "Unknown" ) ; break ;
}
s_sec = ( p.pt[i].start_sec_cyl & 0x3f ) ; /* starting
Sector of the
partition */
t1 = ( p.pt[i].start_sec_cyl & 0xff00 ) >> 8 ;
t2 = ( p.pt[i].start_sec_cyl & 0x00c0 ) << 2 ;
s_trk = t1 | t2 ; /* Starting Cylinder */
e_sec = ( p.pt[i].end_sec_cyl & 0x3f ) ; /*Ending Sector */
t1 = ( p.pt[i].end_sec_cyl & 0xff00 ) >> 8 ;
t2 = ( p.pt[i].end_sec_cyl & 0x00c0 ) << 2 ;
e_trk = t1 | t2 ; /* ending Cylinder */
printf ( "\n%6s %3s", type, boot ) ;
printf ( "%4d %6d %8d", p.pt[i].start_side, s_trk,s_sec ) ;
printf ( "%7d %6u %8u", p.pt[i].end_side, e_trk, e_sec ) ;
printf ( " %10lu %10lu", p.pt[i].part_beg,
p.pt[i].plen ) ;
}
return 0;
}
The information given by the output of the program is displayed something like as given below:
Comments on coding:
The structure partition is used to read the various parameters of partition entry of partition in partition table of MBR. The structure part is used to read MBR information.
The function display() displays the information of MBR Partition Table parameters on the screen. As we see the output of the program, the starting and ending cylinder and sector number are displayed as follows:
Starting Sector = 1
Starting Cylinder = 0
Ending Sector = 63
Ending Cylinder = 701
These sector and cylinder numbers are calculated from the combination of two bytes. The following tables show that how these numbers are calculated:
Thus Starting C-H-S of the partition= 0-0-1.
Similarly, the Encoding for the Ending Cylinder and Sector number of the partition have been given in the next table:
Thus the Ending C-H-S of the Partition = 701-254-63.
Program to find all logical partitions and their information
The program we discussed earlier was to read the partition information from the partition table of MBR. But just only by reading the MBR, we can not get the information of other logical partitions which are in extended partition of the disk.
We have already discussed that the Master Boot Record has the limit of four entries in the Master Partition Table. However the location of Extended Master Boot Record can be obtained with the help of Master Boot Record that contains Extended Partition Tables, whose format is exactly the same as of the main Partition Table.
All the extended partitions should exist within the space reserved by the extended partition entry. Only two of the extended partitions are meant to be used, the first as a normal partition and the second as another extended partition if exists.
Thus with the help of one Master Partition Table We can get the location of another Extended Master Partition Table next to it, if present.
The following program is for finding all the logical partitions and their partition entry information, reading MBR and Extended MBRs from the disk. The coding of the program is as follows:
/* Program to read the parameters of all logical partition present in the disk */
#include<dos.h>
har buffer[512], report_par[20];
unsigned drive_num =0x80;
unsigned long star_sec[20], sec;
/* Structure of Disk Address packet format, to be used by the readabsolutesectors Function */
struct diskaddrpacket
{
char packetsize ; /* Size of Packet, generally 10H */
char reserved ; /* Reserved (0) */
int blockcount ; /* Number of Blocks to Transfer */
char far *bufferaddress ; /* address to Transfer
Buffer */
unsigned long blocknumber[2] ; /* Starting Absolute
Block Number */
} ;
void main()
{
int no_par,i;
clrscr();
no_par = 0;
All_partition_information (star_sec,&no_par, &sec, buffer,
report_par);
printf(" \n\n Total Partitions in Disk = %d\n ",
no_par);
for(i=0;i<no_par;i++)
{
printf("\n Starting Sector Number of Partition %d =
%lu " , i+1, star_sec[i]);
}
printf("\n");
getch();
}
The Output of the program will be displayed as similar to this:
Partition 1 - FAT32
Partition 2 - FAT32
Partition 3 - FAT32
Total Partitions in Disk = 3
Starting Sector Number of Partition 1 = 63
Starting Sector Number of Partition 2 = 11277693
Starting Sector Number of Partition 3 = 25623738
Comments on coding:
The structure diskaddrpacket is used to read Disk Address packet format, to be used by the readabsolutesectors function.
The function All_partition_information( ) is used to find all the parameters of all partitions from the partition entry.
Although in this program, we have displayed only the File system and relative sector information of all available logical partitions in the disk, you can also print the information of other parameters of partition information by using the function All_partition_information( ) with some more printf.
The coding of the function is as follows:
/* Function to Find all logical partitions’ information reading their partition entry */
All_partition_information( unsigned long *star_sec,
unsigned *no_par,
long *sec, char *buffer,
unsigned char *report_par )
{
unsigned long fat_check;
unsigned long *sectors_part;
static long se_p;
int temp_var1,active_offset,active_pos=0,i, extended_pos=0, partloc1;
unsigned long b_sec,se;
unsigned char active_par;
long relative_sec;
long no_sectors;
if(*sec==0 || *sec==1)
se_p=0;
do{
se=*sec;
/* Read absolute sector specified by *sec */
readabsolutesectors (drive_num,*sec,1,buffer);
/* ***** check for active partition ***** */
if(*sec==se && *no_par==0) /*if primary
partition */
{
*sec=se=0;
for(active_offset=446; active_offset<=494;active_offset+=16)
{
active_par=buffer[active_offset];
if(active_par==0x80) /* check for active
partition */
break;
else
active_pos++; /* position of active
partition */
}
/* for extended partition */
for(active_offset=450; active_offset<=511;active_offset+=16)
{
active_par=buffer[active_offset];
if(active_par==0x05 | active_par==0x0F)
/*check for extended partition */
break;
else
extended_pos++; /*position of extended
partition */
}
if(active_pos==4)
active_pos=1;
if(extended_pos==4)
extended_pos=1;
partloc1=0x1C0+extended_pos*16;
}
else
{
active_pos=0;
extended_pos=1;
partloc1=0x1D0;
if(se_p!=0)
{
*sec=se=se_p; /*starting of extended
partition */
}
}
/* Relative Sectors in partition */
relative_sec= *(unsigned long *)(buffer+454+active_pos*16);
/* Number of Sectors in Partition */
no_sectors=*(long *)(buffer+458+active_pos*16);
/* Identify the File System Indicator Byte */
if( buffer[0x1C2+active_pos*16]==0x04 ||
buffer[0x1C2+active_pos*16]==0x05 ||
buffer[0x1C2+active_pos*16]==0x06 ||
buffer[0x1C2+active_pos*16]==0x0B ||
buffer[0x1C2+active_pos*16]==0x0C ||
buffer[0x1C2+active_pos*16]==0x0E ||
buffer[0x1C2+active_pos*16]==0x0F ||
buffer[0x1C2+active_pos*16]==0x07)
{
switch(buffer[0x1C2+active_pos*16])
{
/* For NTFS Partition */
case 0x07: report_par[*no_par]='N';
printf("\n Partition -%d = NTFS",
*no_par+1);
break;
/* For FAT32 Partition */
case 0x0B:
case 0x0C: report_par[*no_par]='3';
printf("\n Partition -%d = FAT32",
*no_par+1);
break;
/* For FAT16 Partition */
case 0x04:
case 0x06:
case 0x0E: report_par[*no_par]='1';
printf("\n Partition -%d = FAT16",
*no_par+1);
break;
} // End of the Switch
b_sec=*sec+relative_sec;
sectors_part[*no_par]=no_sectors; /* Array to store Number of sectors of partitions */
} //End of if Condition
else
{ /* if partition indicator not match */
if(*sec==0)
{ no_par=0;
break;
}
if((fat_check!=0x3631)&&(fat_check!=0x3233))
b_sec=*sec=0;
}
if((b_sec!=0)&&(sec!=0))
{
star_sec[*no_par]=b_sec;
(*no_par)++;
}
else
break;
/* checking if extended partition exist */
if(buffer[0x1C2+extended_pos*16]==0x05 ||
buffer[0x1C2+extended_pos*16]==0x0F )
{
temp_var1=(unsigned )buffer[partloc1];
*sec=temp_var1 & 0x003F; /* sector of
extended
partition */
if(*sec!=0)
{
se_p=se+relative_sec+no_sectors;
*sec=se_p;
}
else
{ *sec=-1;
break;
}
} //close of if statement
else
{
if(*sec>0)
*sec=-1;
break;
}
} while(1); // close of do–while loop
/* check for other non active primary partitions on sector 0 */
if(*sec==0)
{
for(i=0;i<4;i++)
{
active_par=buffer[446+i*16];
/* Identify the file system indicator Byte */
if((buffer[0x1C2+i*16]==(char)0x06 ||
buffer[0x1C2+i*16]==(char)0x0B ||
buffer[0x1C2+i*16]==(char)0x0C ||
buffer[0x1C2+i*16]==(char)0x07 ||
buffer[0x1C2+i*16]==(char)0x0E ||
buffer[0x1C2+i*16]==(char)0x04) && active_par!=0x80)
{
switch(buffer[0x1C2+active_pos*16])
{
/* For NTFS Partition */
case 0x07: report_par[*no_par]='N';
printf("\n Partition -%d = NTFS",
*no_par+1);
break;
/* For FAT32 Partition */
case 0x0B:
case 0x0C: report_par[*no_par]='3';
printf("\n Partition -%d = FAT32",
*no_par+1);
break;
/* For FAT16 Partition */
case 0x04:
case 0x06:
case 0x0E: report_par[*no_par]='1';
printf("\n Partition -%d = FAT16",
*no_par+1);
break;
} // End of switch
/* relative sectors Number of Partition */
relative_sec=*(long *)(buffer+454+i*16);
no_sectors=*(long *)(buffer+458+i*16); /* number of
sectors in
partition*/
sectors_part[*no_par]=no_sectors; /* Array to store
Number of
sectors of
partitions */
*sec=star_sec[*no_par]=relative_sec;
(*no_par)++;
}
} //loop close of for(i=0;i<4;i++)
} //loop close of if(*sec==0)
return;
}
Comments on coding:
The function starts reading the partitions information from the MBR and then reads the Extended MBRs if required. The function readabsolutesectors reads the absolute sector, specified by *sec.
sectors_part[*no_par] is the array to store the number of sectors of partitions. The partition number is specified by *no_par starting from 0.
no_sectors is the number of sectors in partition and relative_sec is the relative sector number for that partition.
star_sec[*no_par] is the array to store the stating sector numbers of partitions. The partition number is specified by *no_par starting from 0.
star_cyl, star_hea and star_sec are the arrays which keep the information of starting of each partition in terms of CHS. star_cyl stores the information of starting cylinders, star_hea stores the information of starting heads and star_sec stores the information of starting sectors of partitions.
For the description of readabsolutesectors function refer the chapters given earlier in this book.
Modify MBR by Programming
The sample program to show, how we can modify the values of MBR partition table entry has been given below. The program modifies the values second partition entry of MBR partition table.
The coding of the program has been given below:
/* Program to modify the values of partition table entry of MBR */
# include <bios.h>
/* structure to read the partition entry from partition table */
struct partition
{
unsigned char bootable ; /* Active Partition
Byte */
unsigned char start_side ; /* Starting Head */
unsigned int start_sec_cyl ; /* combination of
Starting sector and
cylinder number */
unsigned char parttype ; /* File system
Indicator Byte */
unsigned char end_side ; /* Ending Head */
unsigned int end_sec_cyl ; /* combination of
Starting sector and
cylinder number */
unsigned long part_beg ; /* Relative Sector
Number */
unsigned long plen ; /* Partition length in
sectors */
} ;
/* Structure to read MBR */
struct part
{
unsigned char master_boot[446] ; /* IPL (Initial
Program Loader)*/
struct partition pt[4] ; /* Partition table*/
int lasttwo ; /* Magic Number */
} ;
struct part p ;
void main()
{
unsigned int t1,t2;
clrscr();
biosdisk ( 2, 0x80, 0, 0, 1, 1, &p ) ;
display(); /* display the partition
Table information */
getch();
/* Let us assume that we want to modify the partition information of second partition entry from partition table of MBR, with these values */
p.pt[1].bootable = 0x80; /* Active Boot Partition */
p.pt[1].parttype = 0x7; /* NTFS Partition */
p.pt[1].start_side = 0; /* Starting Head =0 */
p.pt[1].end_side = 31; /* Ending Head == 31 */
p.pt[1].part_beg = 808416;/* Relative Sector = 808416 */
p.pt[1].plen = 405216; /* Total Sectors in Partition = 405216 */
/* Write New Information to MBR *\
/* To write the values to MBR partition table, Uncomment the biosdisk function given below */
// biosdisk ( 3, 0x80, 0, 0, 1, 1, &p ) ;
display(); /* Display the Modified
Information */
getch();
}
Comments on coding:
The program given above is a sample program to show how we can modify the values of partition table entry of MBR. If you want to modify the values of partition entry for such logical partitions, which lie in extended partition, you have to modify the values in partition table of Extended MBR.
The values which have been given here to modify the partition table entry are just for demonstrate, how to modify. Never modify partition table with illegal or illogical values. By doing so the entire partition may become inaccessible.
The structure partition is used to read the partition entry from partition table and structure part to read MBR. To actually make the modifications in partition table uncomment the biosdisk( ) function.
If you want to modify the values of starting and ending, sectors and cylinder numbers of the partition, calculate the values, as described in the comments of the program to read and display the partition table of MBR, discussed in the starting of this chapter.
Page Modified on: 17/01/2022