Chapitre – 12
Lecture et modification du MBR à l'aide de la programmation
Enregistrement de démarrage principal (MBR) ou table de partition principale (MPT)
Le Master Boot Record (MBR) ou parfois appelé Master Partition Table (MPT) est créé sur le disque dur en exécutant la commande DOS FDISK.EXE.
Le MBR contient un petit programme permettant de charger et d'exécuter la partition active (ou de démarrage) à partir du disque dur. Le Master Boot Record contient des informations sur les quatre partitions principales du disque dur, telles que le secteur de départ, le secteur de fin, la taille de la partition, etc.
Le MBR est situé dans le secteur absolu 0 ou nous pouvons dire dans le cylindre 0, la tête 0 et le secteur 1 et s'il y a plus d'une partition sur le disque, il existe des enregistrements de démarrage principaux étendus situés au début de chaque volume de la partition étendue.
Pour une description détaillée, voir le chapitre « Une approche logique des disques et des systèmes d'exploitation » abordé plus haut dans ce livre.
Format de l'enregistrement de démarrage principal
Nous pouvons partitionner le disque dur en plusieurs lecteurs logiques, auxquels DOS attribue généralement sa propre lettre de lecteur. Une seule partition à la fois peut être marquée comme partition active (ou de démarrage).

L'enregistrement de démarrage principal a une limite de quatre entrées dans la table de partition principale. Cependant, l'emplacement du MBR étendu peut être obtenu à l'aide du MBR contenant les tables de partition étendues, qui a le même format que la table de partition principale, sauf qu'il ne contient pas de code de démarrage et que 446 octets d'espace sont généralement réservés au code de démarrage et sont laissés vides.
Les 512 octets du master boot record sont répartis comme indiqué dans le tableau :

Toutes les partitions étendues doivent exister dans l’espace réservé par l’entrée de partition étendue. Seules deux des partitions étendues sont destinées à être utilisées, la première comme partition normale et la seconde comme une autre partition étendue, si elle existe.
Ainsi, en utilisant une table de partition principale, nous pouvons obtenir l'emplacement d'une autre table de partition principale étendue à côté d'elle, s'il y en a une.
Format d'entrée de la table de partition
Le format d’entrée de la table de partition de n’importe quelle partition du MBR est indiqué dans le tableau suivant. Chaque entrée de partition de n'importe quel MBR peut être décomposée en octets suivants avec leurs significations spécifiques :

Écrire un programme pour lire la table de partition MBR
Vous trouverez ci-dessous un programme permettant de lire les quatre entrées de partition de la table de partition MBR. Le programme affiche tous les paramètres des informations de partition enregistrées dans la table de partition MBR.
L'encodage du programme ressemble à ceci :
/* Programme de lecture de la table de partition MBR */
# inclure <bios.h>
/* structure pour lire l'entrée de partition à partir de la table de partition */
section structurelle
{
char non signé amorçable ; /* Octet actif de la section */
unsigned char start_side ;/* Tête de départ */
int non signé start_sec_cyl ; /* combinaison
Secteur de départ et
numéro de cylindre */
type de partie char non signé ; /* Système de fichiers
Octet indicateur */
caractère non signé end_side ; /* Fin de l'en-tête */
entier non signé end_sec_cyl ; /* combinaison
Secteur de départ et
numéro de cylindre */
partie_début non signée longue ; /* Secteur relatif
Nombre */
entier long non signé; /* Longueur de la section dans
secteur */
} ;
/* Structure pour la lecture du MBR */
une partie de la structure
{
caractère non signé master_boot[446] ; /* IPL (initiale
Chargeur de programme)*/
structure partition pt[4] ; /* Table de partitions */
int dernierdeux ; /* Nombre magique */
} ;
partie de la structure p ;
main() invalide
{
clrscr();
/* Lecture du premier secteur du premier disque dur */
disque bios ( 2, 0x80, 0, 0, 1, 1, &p ) ;
afficher(); /* Afficher les informations MBR
Table de partition */
obtenir();
}
/* Fonction permettant d'afficher des informations sur la table de partition MBR */
afficher()
{
entier non signé s_sec, s_trk, e_sec, e_trk, i, t1, t2 ;
type de caractère[20], boot[5] ;
printf("\n\nPartie. Emplacement de chargement initial
Emplacement final Quantité relative");
printf("\nType Cylindre latéral Secteur
Cylindre latéral Secteurs Secteurs\n");
pour ( i = 0 ; i <= 3 ; i++ )
{
si ( p.pt[i].bootable == 0x80 )
strcpy ( boot, "Oui" ) ;
autre
strcpy ( boot, "Non" ) ;
commutateur ( p.pt[i].parttype )
{
cas 0x00 :
strcpy ( type, "Inutilisé" ) ; break ;
cas 0x1 :
strcpy ( type, "FAT12" ) ; pause ;
cas 0x2 :
strcpy ( type, "Xenix" ) ; pause ;
cas 0x3 :
strcpy ( type, "Xenix:usr" ) ; pause ;
cas 0x4 :
strcpy ( type, "FAT16<32M" ) ; pause ;
cas 0x5 :
strcpy ( type, "DOS-Ext." ) ; pause ;
cas 0x6 :
strcpy ( type, "FAT16>32M" ) ; pause ;
cas 0x7 :
strcpy ( type, "NTFS" ) ; pause ;
cas 0x0b :
strcpy ( type, "FAT32" ) ; pause ;
cas 0x0c :
strcpy ( type, "FAT32-LBA" ) ; pause ;
cas 0x0d :
strcpy ( type, "VFAT16" ) ; pause ;
cas 0x0e :
strcpy ( type, "VFAT16-LBA" ) ; pause ;
cas 0x0f :
strcpy ( type, "VFAT EXT" ) ; pause ;
cas 0x17 :
strcpy ( type, "HPFS" ) ; pause ;
cas 0x81 :
strcpy ( type, "Ancien LINUX" ) ; break ;
cas 0x82 :
strcpy ( type, "LinuxSwap" ) ; pause ;
cas 0x83 :
strcpy ( type, "LinuxNative" ) ; pause ;
cas 0x85 :
strcpy ( type, "Ext. Linux." ) ; break ;
défaut :
strcpy ( type, "Inconnu" ) ; pause ;
}
s_sec = ( p.pt[i].start_sec_cyl & 0x3f ); /* démarrage
Secteur de la
partition */
t1 = ( p.pt[i].start_sec_cyl & 0xff00 ) >> 8 ;
t2 = ( p.pt[i].start_sec_cyl & 0x00c0 ) << 2 ;
s_trk = t1 | t2 ; /* Cylindre de démarrage */
e_sec = ( p.pt[i].end_sec_cyl & 0x3f ); /*Secteur de fin */
t1 = ( p.pt[i].end_sec_cyl & 0xff00 ) >> 8 ;
t2 = ( p.pt[i].end_sec_cyl & 0x00c0 ) << 2 ;
e_trk = t1 | t2 ; /* fin du cylindre */
printf ( "\n%6s %3s", tapez, 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 ) ;
}
retourner 0;
}
Les informations fournies par la sortie du programme sont affichées comme suit :

Commentaires sur le codage :
La partition de structure est utilisée pour lire les différents paramètres de l'entrée de partition de la table de partition du MBR. La partie structure est utilisée pour lire les informations du MBR.
La fonction display() affiche les informations des paramètres de la table de partition MBR à l'écran. Comme nous pouvons le voir dans la sortie du programme, le numéro de cylindre et de secteur de début et de fin s'affiche comme suit :
Secteur de départ = 1
Cylindre de départ = 0
Secteur de fin = 63
Cylindre de fin = 701
Ces numéros de secteurs et de cylindres sont calculés à partir de la combinaison de deux octets. Les tableaux suivants montrent comment ces numéros sont calculés :

Ainsi, le CHS de départ de la partition = 0-0-1.
De même, le codage du cylindre de fin et le numéro de secteur de la partition ont été indiqués dans le tableau suivant :

Ainsi, la fin CHS de la partition = 701-254-63.
Programme pour trouver toutes les partitions logiques et leurs informations
Le programme dont nous avons parlé plus tôt était destiné à lire les informations de partition à partir de la table de partition du MBR. Mais en lisant uniquement le MBR, nous ne pouvons pas obtenir les informations des autres partitions logiques qui se trouvent dans la partition étendue du disque.
Nous avons déjà évoqué le fait que le Master Boot Record a une limite de quatre entrées dans la table de partition principale . Cependant, l'emplacement du Master Boot Record étendu peut être obtenu à l'aide du Master Boot Record qui contient des tables de partition étendues , dont le format est exactement le même que celui de la table de partition principale.
Toutes les partitions étendues doivent exister dans l'espace réservé par l'entrée de partition étendue. Seules deux des partitions étendues sont destinées à être utilisées, la première comme partition normale et la seconde comme une autre partition étendue si elle existe.
Ainsi, avec l'aide d'une table de partition principale, nous pouvons obtenir l'emplacement d'une autre table de partition principale étendue à côté d'elle, si elle est présente.
Le programme suivant permet de rechercher toutes les partitions logiques et leurs informations d'entrée de partition, de lire les MBR et les MBR étendus du disque. Le codage du programme est le suivant :
/* Programme pour lire les paramètres de toutes les partitions logiques présentes sur le disque */
#include<dos.h>
a buffer[512], report_par[20];
numéro_lecteur non signé = 0x80;
unsigned long star_sec[20], sec;
/* Structure du format du paquet d'adresse de disque, à utiliser par la fonction readabsolutesectors */
structure diskaddrpacket
{
char packetsize ; /* Taille du paquet, généralement 10H */
char réservé ; /* Réservé (0) */
int blockcount ; /* Nombre de blocs à transférer */
char far *bufferaddress ; /* adresse à transférer
Tampon */
unsigned long blocknumber[2] ; /* Démarrage absolu
Numéro de bloc */
} ;
void main()
{
int non_pair,i;
clrscr();
pas_pair = 0;
Toutes les informations de partition (star_sec,&no_par, &sec, tampon,
report_par);
printf(" \n\n Nombre total de partitions sur le disque = %d\n ",
pas_pair);
pour(i=0;i<no_par;i++)
{
printf("\n Numéro de secteur de départ de la partition %d =
%lu " , i+1, star_sec[i]);
}
printf("\n");
obtenir();
}
La sortie du programme sera affichée comme suit :
Partition 1 - FAT32
Partition 2 - FAT32
Partition 3 - FAT32
Nombre total de partitions sur le disque = 3
Numéro de secteur de départ de la partition 1 = 63
Numéro de secteur de départ de la partition 2 = 11277693
Numéro de secteur de départ de la partition 3 = 25623738
Commentaires sur le codage :
La structure diskaddrpacket est utilisée pour lire le format du paquet d'adresse de disque, à utiliser par la fonction readabsolutesectors.
La fonction All_partition_information( ) est utilisée pour trouver tous les paramètres de toutes les partitions à partir de l'entrée de partition.
Bien que dans ce programme, nous ayons affiché uniquement les informations sur le système de fichiers et les secteurs relatifs de toutes les partitions logiques disponibles sur le disque, vous pouvez également imprimer les informations d'autres paramètres d'informations de partition en utilisant la fonction All_partition_information( ) avec quelques printf supplémentaires.
Le codage de la fonction est le suivant :
/* Fonction pour rechercher toutes les informations des partitions logiques en lisant leur entrée de partition */
Toutes les informations de partition( unsigned long *star_sec,
non signé *no_par,
long *sec, char *buffer,
char non signé *report_par )
{
non signé long fat_check;
unsigned long *sectors_part;
statique long se_p;
int temp_var1,décalage_actif,pos_actif=0,i,pos_étendu=0, partloc1;
non signé long b_sec,se;
char non signé active_par;
longue relative_sec;
long no_sectors;
si(*sec==0 || *sec==1)
se_p=0;
faire{
se=*sec;
/* Lire le secteur absolu spécifié par *sec */
readabsolutesectors (numéro_lecteur,*sec,1,tampon);
/* ***** vérifier la partition active ***** */
si(*sec==se && *no_par==0) /*si primaire
partition */
{
*sec=se=0;
pour(offset_actif=446;offset_actif<=494;offset_actif+=16)
{
active_par=tampon[décalage_actif];
if(active_par==0x80) /* vérifier si actif
partition */
casser;
autre
active_pos++; /* position de l'actif
partition */
}
/* pour la partition étendue */
pour(offset_actif=450;offset_actif<=511;offset_actif+=16)
{
active_par=tampon[décalage_actif];
si(active_par==0x05 | active_par==0x0F)
/*vérifier la partition étendue */
casser;
autre
extended_pos++; /*position de l'extension
partition */
}
si(active_pos==4)
active_pos=1;
si(pos_étendu==4)
extended_pos=1;
partloc1=0x1C0+pos_étendu*16;
}
autre
{
active_pos=0;
extended_pos=1;
partieloc1=0x1D0;
si(se_p!=0)
{
*sec=se=se_p; /*démarrage de l'extension
partition */
}
}
/* Secteurs relatifs dans la partition */
relative_sec= *(unsigned long *)(buffer+454+active_pos*16);
/* Nombre de secteurs dans la partition */
no_sectors=*(long *)(buffer+458+active_pos*16);
/* Identifier l'octet indicateur du système de fichiers */
si( tampon[0x1C2+active_pos*16]==0x04 ||
tampon[0x1C2+active_pos*16]==0x05 ||
tampon[0x1C2+active_pos*16]==0x06 ||
tampon[0x1C2+active_pos*16]==0x0B ||
tampon[0x1C2+active_pos*16]==0x0C ||
tampon[0x1C2+active_pos*16]==0x0E ||
tampon[0x1C2+active_pos*16]==0x0F ||
tampon[0x1C2+active_pos*16]==0x07)
{
commutateur(tampon[0x1C2+active_pos*16])
{
/* Pour la partition NTFS */
case 0x07: report_par[*no_par]='N';
printf("\nPartition -%d = NTFS",
*pas_pair+1);
casser;
/* Pour la partition FAT32 */
cas 0x0B :
case 0x0C: report_par[*no_par]='3';
printf("\nPartition -%d = FAT32",
*pas_pair+1);
casser;
/* Pour la partition FAT16 */
cas 0x04:
cas 0x06:
case 0x0E: report_par[*no_par]='1';
printf("\nPartition -%d = FAT16",
*pas_pair+1);
casser;
} // Fin du commutateur
b_sec=*sec+sec_relative;
sector_part[*no_par]=no_sectors; /* Tableau pour stocker le nombre de secteurs de partitions */
} // Fin de la condition if
autre
{ /* si l'indicateur de partition ne correspond pas */
si(*sec==0)
{ no_par=0;
casser;
}
si((fat_check!=0x3631)&&(fat_check!=0x3233))
b_sec=*sec=0;
}
si((b_sec!=0)&&(sec!=0))
{
étoile_sec[*no_par]=b_sec;
(*pas_pair)++;
}
autre
casser;
/* vérifier si la partition étendue existe */
si (tampon[0x1C2+extended_pos*16]==0x05 ||
tampon[0x1C2+extended_pos*16]==0x0F )
{
temp_var1=(non signé )tampon[partloc1];
*sec=temp_var1 & 0x003F; /* secteur de
étendu
partition */
si(*sec!=0)
{
se_p=se+sec_relative+pas_de_secteurs ;
*sec=se_p;
}
autre
{ *sec=-1;
casser;
}
} //fermeture de l'instruction if
autre
{
si(*sec>0)
*sec=-1;
casser;
}
} while(1); // fermeture de la boucle do–while
/* vérifier les autres partitions primaires non actives sur le secteur 0 */
si(*sec==0)
{
pour(i=0;i<4;i++)
{
active_par=buffer[446+i*16];
/* Identifier l'octet indicateur du système de fichiers */
si((tampon[0x1C2+i*16]==(car)0x06 ||
tampon[0x1C2+i*16]==(car)0x0B ||
tampon[0x1C2+i*16]==(car)0x0C ||
tampon[0x1C2+i*16]==(car)0x07 ||
tampon[0x1C2+i*16]==(car)0x0E ||
tampon[0x1C2+i*16]==(car)0x04) && active_par!=0x80)
{
commutateur(tampon[0x1C2+active_pos*16])
{
/* Pour la partition NTFS */
case 0x07: report_par[*no_par]='N';
printf("\nPartition -%d = NTFS",
*pas_pair+1);
casser;
/* Pour la partition FAT32 */
cas 0x0B :
case 0x0C: report_par[*no_par]='3';
printf("\nPartition -%d = FAT32",
*pas_pair+1);
casser;
/* Pour la partition FAT16 */
cas 0x04:
cas 0x06:
case 0x0E: report_par[*no_par]='1';
printf("\nPartition -%d = FAT16",
*pas_pair+1);
casser;
} // Fin du commutateur
/* secteurs relatifs Nombre de partitions */
relative_sec=*(long *)(tampon+454+i*16);
no_sectors=*(long *)(buffer+458+i*16); /* nombre de
secteurs dans
partition*/
secteurs_part[*no_par]=no_sectors; /* Tableau à stocker
Nombre de
secteurs de
partitions */
*sec=star_sec[*no_par]=relative_sec;
(*pas_pair)++;
}
} //fermeture de boucle de for(i=0;i<4;i++)
} //fermeture de boucle de if(*sec==0)
retour;
}
Commentaires sur le codage :
La fonction commence à lire les informations des partitions à partir du MBR , puis lit les MBR étendus si nécessaire. La fonction readabsolutesectors lit le secteur absolu, spécifié par *sec.
sector_part[*no_par] est le tableau permettant de stocker le nombre de secteurs des partitions. Le numéro de partition est spécifié par *no_par à partir de 0.
no_sectors est le nombre de secteurs dans la partition et relative_sec est le numéro de secteur relatif pour cette partition.
star_sec[*no_par] est le tableau pour stocker les numéros de secteur des partitions. Le numéro de partition est spécifié par *no_par à partir de 0.
star_cyl, star_hea et star_sec sont les tableaux qui conservent les informations de démarrage de chaque partition en termes de CHS. star_cyl stocke les informations des cylindres de démarrage, star_hea stocke les informations des têtes de démarrage et star_sec stocke les informations des secteurs de démarrage des partitions.
Pour la description de la fonction readabsolutesectors, reportez-vous aux chapitres donnés plus haut dans ce livre.
Modifier le MBR par programmation
L'exemple de programme ci-dessous montre comment modifier les valeurs de l'entrée de la table de partition MBR . Le programme modifie les valeurs de la deuxième entrée de la table de partition MBR .
Le codage du programme est donné ci-dessous :
/* Programme pour modifier les valeurs de l'entrée de la table de partition du MBR */
# inclure <bios.h>
/* structure pour lire l'entrée de partition à partir de la table de partition */
structure de partition
{
unsigned char bootable ; /* Partition active
Octet */
unsigned char start_side ; /* Tête de départ */
unsigned int start_sec_cyl ; /* combinaison de
Secteur de départ et
numéro de cylindre */
unsigned char parttype ; /* Système de fichiers
Octet indicateur */
unsigned char end_side ; /* Fin de la tête */
unsigned int end_sec_cyl ; /* combinaison de
Secteur de départ et
numéro de cylindre */
unsigned long part_beg ; /* Secteur relatif
Nombre */
unsigned long plen ; /* Longueur de la partition en
secteurs */
} ;
/* Structure pour lire le MBR */
partie de structure
{
char non signé master_boot[446] ; /* IPL (initiale
Chargeur de programme)*/
struct partition pt[4] ; /* Table de partition*/
int lasttwo ; /* Nombre magique */
} ;
partie de structure p ;
void main()
{
int non signé t1,t2;
clrscr();
disque bios ( 2, 0x80, 0, 0, 1, 1, &p ) ;
display(); /* afficher la partition
Informations sur le tableau */
obtenir();
/* Supposons que nous souhaitons modifier les informations de partition de la deuxième entrée de partition de la table de partition du MBR, avec ces valeurs */
p.pt[1].bootable = 0x80; /* Partition de démarrage active */
p.pt[1].parttype = 0x7; /* Partition NTFS */
p.pt[1].start_side = 0; /* Tête de départ = 0 */
p.pt[1].end_side = 31; /* Fin de l'en-tête == 31 */
p.pt[1].part_beg = 808416;/* Secteur relatif = 808416 */
p.pt[1].full = 405216; /* Nombre total de secteurs dans la partition = 405216 */
/* Écrire de nouvelles informations sur le MBR *\
/* Pour écrire des valeurs dans la table de partition MBR, décommentez la fonction biosdisk ci-dessous */
// biosdisk ( 3, 0x80, 0, 0, 1, 1, &p ) ;
afficher(); /* Affichage modifié
Information */
obtenir();
}
Commentaires sur le codage :
Le programme ci-dessus est un exemple de programme pour montrer comment nous pouvons modifier les valeurs de l'entrée de la table de partition MBR . Si vous souhaitez modifier les valeurs d'entrée de partition pour les partitions logiques qui se trouvent dans une partition étendue , vous devez modifier les valeurs dans la table de partition MBR étendue .
Les valeurs qui ont été données ici pour modifier l'entrée de la table de partition servent simplement à démontrer comment procéder. Ne modifiez jamais la table de partition avec des valeurs non valides ou illogiques. Par conséquent, la section entière peut devenir inaccessible.
La section structure est utilisée pour lire l'enregistrement de partition à partir de la table de partition, et la partie structure est utilisée pour lire le MBR. Pour apporter des modifications à la table de partition, supprimez le commentaire de la fonction biosdisk() .
Si vous souhaitez modifier les valeurs de début et de fin, les numéros de secteur et de cylindre d'une partition, calculez les valeurs comme décrit dans les commentaires du programme de lecture et d'affichage de la table de partition MBR discuté au début de ce chapitre.