Capítulo – 12
Lendo e modificando o MBR com programação
Master Boot Record (MBR) ou Master Partition Table (MPT)
O Master Boot Record (MBR) ou às vezes referido como The master partition table (MPT), é criado na unidade de disco rígido executando o comando FDISK.EXE do DOS.
O MBR contém um pequeno programa para carregar e iniciar a partição ativa (ou inicializável) do disco rígido. O registro mestre de inicialização contém informações sobre todas as quatro partições primárias na unidade de disco rígido, como o setor inicial, o setor final, o tamanho da partição etc.
O MBR está localizado no Setor Absoluto 0 ou podemos dizer no cilindro 0, cabeça 0 e setor1 e se houver mais de uma partição presente no disco existem Registros de inicialização mestre estendidos, localizados no início de cada volume de partição estendido.
Para obter uma descrição detalhada, consulte o capítulo “Abordagem lógica para discos e SO”, discutido anteriormente neste livro.
Formato de registro mestre de inicialização
Podemos particionar a unidade de disco rígido em várias unidades lógicas que geralmente recebem sua própria letra de unidade pelo DOS). Apenas uma partição de cada vez pode ser marcada como a partição ativa (ou inicializável).
O Master Boot Record tem o limite de quatro entradas na Master Partition Table. No entanto, a localização do Extended Master Boot Record pode ser obtida com a ajuda do Master Boot Record que contém Extended Partition Tables, cujo formato é exatamente o mesmo da tabela de partição principal, exceto que não há código de inicialização e este espaço de 446 Bytes é normalmente reservado para o código de inicialização e permanece vazio.
Todos os 512Bytes do Master Boot Record estão quebrados da seguinte forma, fornecidos na Tabela:
Todas as partições estendidas devem existir dentro do espaço reservado pela entrada da partição estendida. Apenas duas das partições estendidas devem ser usadas, a primeira como uma partição normal e a segunda como outra partição estendida, se existir.
Assim, com a ajuda de uma Master Partition Table, podemos obter a localização de outra Extended Master Partition Table ao lado dela, se houver.
Formato de entrada da tabela de partição
O formato de entrada da tabela de partição de qualquer partição no MBR foi fornecido na tabela a seguir. Cada Entrada de Partição de qualquer MBR pode ser dividida nos seguintes bytes com seus significados específicos:
Escrevendo programa para ler a tabela de partições do MBR
O programa para ler todas as quatro entradas de partição da tabela de partição do MBR foi dado a seguir. O programa exibe todos os parâmetros de informação da partição, escritos na tabela de partição do MBR.
A codificação do programa é a seguinte:
/* Programa para ler a tabela de partição 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 */
} ;
/* Estrutura para ler 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();
/* Leia o primeiro setor do primeiro disco rígido */
biosdisk ( 2, 0x80, 0, 0, 1, 1, &p ) ;
display(); /* Display the information of MBR
Partition Table */
getch();
}
/* Função para exibir as informações da tabela de partição do 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;
}
As informações fornecidas pela saída do programa são exibidas como abaixo:
Comentários sobre a codificação:
A partição de estrutura é usada para ler os vários parâmetros de entrada da partição na tabela de partição do MBR. A parte da estrutura é usada para ler as informações do MBR.
A função display() exibe as informações dos parâmetros da tabela de partição MBR na tela. Conforme vemos a saída do programa, o cilindro inicial e final e o número do setor são exibidos da seguinte forma:
Starting Sector = 1
Starting Cylinder = 0
Ending Sector = 63
Ending Cylinder = 701
Esses números de setor e cilindro são calculados a partir da combinação de dois bytes. As tabelas a seguir mostram como esses números são calculados:
Assim, iniciando C-H-S da partição = 0-0-1.
Da mesma forma, a codificação para o cilindro final e o número do setor da partição foram fornecidos na tabela a seguir:
Assim, a terminação C-H-S da partição = 701-254-63.
Programa para encontrar todas as partições lógicas e suas informações
O programa que discutimos anteriormente era ler as informações de partição da tabela de partição do MBR. Mas apenas lendo o MBR, não podemos obter as informações de outras partições lógicas que estão na partição estendida do disco.
Já discutimos que o Registro de inicialização mestre tem o limite de quatro entradas na Tabela de partição mestre. No entanto, a localização do Extended Master Boot Record pode ser obtida com a ajuda do Master Boot Record que contém Extended Partition Tables, cujo formato é exatamente o mesmo da tabela de partição principal.
Todas as partições estendidas devem existir dentro do espaço reservado pela entrada da partição estendida. Apenas duas das partições estendidas devem ser usadas, a primeira como uma partição normal e a segunda como outra partição estendida, se existir.
Assim, com a ajuda de uma Master Partition Table, podemos obter a localização de outra Extended Master Partition Table ao lado dela, se houver.
O programa a seguir é para localizar todas as partições lógicas e suas informações de entrada de partição, lendo MBR e MBRs estendidos do disco. A codificação do programa é a seguinte:
/* Programa para ler os parâmetros de todas as partições lógicas presentes no disco */
#include<dos.h>
har buffer[512], report_par[20];
unsigned drive_num =0x80;
unsigned long star_sec[20], sec;
/* Estrutura do formato de pacote de endereço de disco, a ser usado pela função readabsolutesectors */
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();
}
A saída do programa será exibida semelhante a esta:
Partição 1 - FAT32
Partição 2 - FAT32
Partição 3 - FAT32
Total de Partições no Disco = 3
Número do setor inicial da partição 1 = 63
Número do setor inicial da partição 2 = 11277693
Número do setor inicial da partição 3 = 25623738
Comentários sobre a codificação:
A estrutura diskaddrpacket é usada para ler o formato de pacote de endereço de disco, a ser usado pela função readabsolutesectors.
A função All_partition_information( ) é usada para encontrar todos os parâmetros de todas as partições da entrada da partição.
Embora neste programa tenhamos exibido apenas as informações do sistema de arquivos e do setor relativo de todas as partições lógicas disponíveis no disco, você também pode imprimir as informações de outros parâmetros de informações da partição usando a função All_partition_information( ) com mais printf.
A codificação da função é a seguinte:
/* Função para encontrar todas as partições lógicas’ informações lendo sua entrada de partição */
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;
/* Ler setor absoluto especificado por *sec */
readabsolutesectors (drive_num,*sec,1,buffer);
/* ***** verificar partição ativa ***** */
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 */
}
/* para partição estendida */
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 */
}
}
/* Setores relativos na partição */
relative_sec= *(unsigned long *)(buffer+454+active_pos*16);
/* Número de setores na partição */
no_sectors=*(longo *)(buffer+458+active_pos*16);
/* Identifique o byte indicador do sistema de arquivos */
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;
/* Para partição FAT32 */
case 0x0B:
case 0x0C: report_par[*no_par]='3';
printf("\n Partition -%d = FAT32",
*no_par+1);
break;
/* Para partição FAT16 */
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;
/* verificando se existe partição estendida */
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
/* verifique se há outras partições primárias não ativas no setor 0 */
if(*sec==0)
{
for(i=0;i<4;i++)
{
active_par=buffer[446+i*16];
/* Identifique o Byte do indicador do sistema de arquivos */
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])
{
/* Para partição NTFS */
case 0x07: report_par[*no_par]='N';
printf("\n Partition -%d = NTFS",
*no_par+1);
break;
/* Para partição FAT32 */
case 0x0B:
case 0x0C: report_par[*no_par]='3';
printf("\n Partition -%d = FAT32",
*no_par+1);
break;
/* Para partição FAT16 */
case 0x04:
case 0x06:
case 0x0E: report_par[*no_par]='1';
printf("\n Partition -%d = FAT16",
*no_par+1);
break;
} // End of switch
/* setores relativos Número de Partição */
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;
}
Comentários sobre a codificação:
A função inicia lendo as informações de partições do MBR e, em seguida, lê os MBRs estendidos, se necessário. A função readabsolutesectors lê o setor absoluto, especificado por *sec.
sectors_part[*no_par] é o array para armazenar o número de setores das partições. O número da partição é especificado por *no_par começando em 0.
no_sectors é o número de setores na partição e relative_sec é o número do setor relativo para essa partição.
star_sec[*no_par] é o array para armazenar os números de setor declarados das partições. O número da partição é especificado por *no_par começando em 0.
star_cyl, star_hea e star_sec são os arrays que guardam as informações de início de cada partição em termos de CHS. star_cyl armazena as informações dos cilindros iniciais, star_hea armazena as informações das cabeças iniciais e star_sec armazena as informações dos setores iniciais das partições.
Para a descrição da função readabsolutesectors, consulte os capítulos fornecidos anteriormente neste livro.
Modificar MBR por programação
O programa de exemplo para mostrar como podemos modificar os valores da entrada da tabela de partição MBR foi fornecido abaixo. O programa modifica os valores na segunda entrada de partição da tabela de partição MBR.
A codificação do programa foi dada abaixo:
/* Programa para modificar os valores da entrada da tabela de partição do MBR */
# incluem <bios.h>
/* estrutura para ler a entrada de partição da tabela de partição */
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 */
} ;
/* Estrutura para ler 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();
/* Vamos supor que queremos modificar as informações de partição da segunda entrada de partição da tabela de partições do MBR, com esses valores */
p.pt[1].bootable = 0x80; /* Partição de inicialização ativa */
p.pt[1].parttype = 0x7; /* Partição NTFS */
p.pt[1].start_side = 0; /* Cabeçalho inicial =0 */
p.pt[1].end_side = 31; /* Cabeça final == 31 */
p.pt[1].part_beg = 808416;/* Setor Relativo = 808416 */
p.pt[1].plen = 405216; /* Total de setores na partição = 405216 */
/* Escrever novas informações no MBR *\
/* Para gravar os valores na tabela de partição MBR, remova o comentário da função biosdisk fornecida abaixo */
// biosdisk ( 3, 0x80, 0, 0, 1, 1, &p );
display(); /* Display the Modified
Information */
getch();
}
Comentários sobre a codificação:
O programa fornecido acima é um exemplo de programa para mostrar como podemos modificar os valores da entrada da tabela de partição do MBR. Se você deseja modificar os valores da entrada de partição para tais partições lógicas, que se encontram na partição estendida, você deve modificar os valores na tabela de partição do MBR estendido .
Os valores que foram fornecidos aqui para modificar a entrada da tabela de partição são apenas para demonstração, como modificar. Nunca modifique a tabela de partição com valores ilegais ou ilógicos. Ao fazer isso, toda a partição pode ficar inacessível.
A partição de estrutura é usada para ler a entrada de partição da tabela de partição e a parte da estrutura para ler o MBR. Para realmente fazer as modificações na tabela de partições, descomente a função biosdisk( ).
Se você deseja modificar os valores de início e fim, setores e números de cilindros da partição, calcule os valores, conforme descrito nos comentários do programa para ler e exibir a tabela de partição do MBR , discutido no início deste capítulo.
Página modificada em: 17/01/2022