Глава – 12
Чтение и изменение MBR с помощью программирования
Основная загрузочная запись (MBR) или основная таблица разделов (MPT)
Основная загрузочная запись (MBR) или иногда называемая основной таблицей разделов (MPT) создается на жестком диске путем выполнения команды FDISK.EXE DOS.
MBR содержит небольшую программу для загрузки и запуска активного (или загрузочного) раздела с жесткого диска. Основная загрузочная запись содержит информацию обо всех четырех основных разделах на жестком диске, такую как начальный сектор, конечный сектор, размер раздела и т. д.
MBR расположена в абсолютном секторе 0 или, можно сказать, в цилиндре 0, головке 0 и секторе 1, и если на диске присутствует более одного раздела, то существуют расширенные главные загрузочные записи, расположенные в начале каждого тома расширенного раздела.
Подробное описание см. в главе «Логический подход к дискам и ОС», обсуждавшейся ранее в этой книге.
Формат основной загрузочной записи
Мы можем разбить жесткий диск на несколько логических дисков, которым DOS обычно назначает собственную букву диска. Только один раздел за раз может быть отмечен как активный (или загрузочный) раздел.

Основная загрузочная запись имеет ограничение в четыре записи в основной таблице разделов. Однако местоположение расширенной основной загрузочной записи можно получить с помощью основной загрузочной записи, содержащей расширенные таблицы разделов, формат которой точно такой же, как у основной таблицы разделов, за исключением того, что в ней нет загрузочного кода, и это пространство в 446 байт обычно зарезервировано для загрузочного кода и остается пустым.
Все 512 байт основной загрузочной записи разбиты следующим образом, как показано в таблице:

Все расширенные разделы должны существовать в пространстве, зарезервированном записью расширенного раздела. Только два из расширенных разделов предназначены для использования, первый как обычный раздел, а второй как другой расширенный раздел, если он существует.
Таким образом, с помощью одной Главной таблицы разделов мы можем получить местоположение другой Расширенной главной таблицы разделов рядом с ней, если таковая имеется.
Формат записи таблицы разделов
Формат записи таблицы разделов любого раздела в MBR приведен в следующей таблице. Каждая запись раздела любого MBR может быть разбита на следующие байты с их конкретными значениями:

Написание программы для чтения таблицы разделов MBR
Далее приведена программа для чтения всех четырех записей разделов из таблицы разделов MBR. Программа отображает все параметры информации о разделах, записанные в таблице разделов MBR.
Кодировка программы выглядит следующим образом:
/* Программа для чтения таблицы разделов MBR */
# включить <bios.h>
/* структура для чтения записи раздела из таблицы разделов */
структурный раздел
{
unsigned char bootable ; /* Активный байт раздела */
unsigned char start_side ;/* Начальная голова */
unsigned int start_sec_cyl ; /* комбинация
Стартовый сектор и
номер цилиндра */
unsigned char parttype ; /* Файловая система
Индикаторный байт */
unsigned char end_side ; /* Конечный заголовок */
беззнаковое целое end_sec_cyl ; /* комбинация
Стартовый сектор и
номер цилиндра */
unsigned long part_beg ; /* Относительный сектор
Число */
unsigned long plen ; /* Длина раздела в
секторы */
} ;
/* Структура для чтения MBR */
часть структуры
{
unsigned char master_boot[446] ; /* IPL (Начальная
Загрузчик программ)*/
struct partition pt[4] ; /* Таблица разделов */
int lasttwo ; /* Магическое число */
} ;
часть структуры p ;
недействительный основной()
{
clrscr();
/* Чтение первого сектора первого жесткого диска */
biosdisk ( 2, 0x80, 0, 0, 1, 1, &p ) ;
display(); /* Отображение информации MBR
Таблица разделов */
получить();
}
/* Функция отображения информации о таблице разделов MBR */
отображать()
{
беззнаковое целое s_sec, s_trk, e_sec, e_trk, i, t1, t2 ;
тип символа[20], boot[5] ;
printf("\n\nЧасть. Начальное местоположение загрузки
Конечное местоположение Относительное количество");
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; /* Конечный заголовок == 31 */
p.pt[1].part_beg = 808416;/* Относительный сектор = 808416 */
стр.пт[1].полный = 405216; /* Общее количество секторов в разделе = 405216 */
/* Запись новой информации в MBR *\
/* Чтобы записать значения в таблицу разделов MBR, раскомментируйте функцию biosdisk, указанную ниже */
// biosdisk ( 3, 0x80, 0, 0, 1, 1, &p ) ;
display(); /* Отображение измененного
Информация */
получить();
}
Комментарии по кодированию:
Программа, приведенная выше, является примером программы, показывающей, как мы можем изменить значения записи таблицы разделов MBR . Если вы хотите изменить значения записи раздела для таких логических разделов , которые лежат в расширенном разделе , вам нужно изменить значения в таблице разделов Extended MBR .
Значения, которые были даны здесь для изменения записи таблицы разделов, просто для демонстрации того, как изменять. Никогда не изменяйте таблицу разделов недопустимыми или нелогичными значениями. В результате весь раздел может стать недоступным.
Раздел структуры используется для чтения записи раздела из таблицы разделов, а часть структуры — для чтения MBR. Чтобы внести изменения в таблицу разделов, раскомментируйте функцию biosdisk() .
Если вы хотите изменить начальные и конечные значения, номера секторов и цилиндров раздела, рассчитайте значения, как описано в комментариях к программе для чтения и отображения таблицы разделов MBR , обсуждаемой в начале этой главы.