장 – 12
프로그래밍으로 MBR 읽기 및 수정
마스터 부트 레코드(MBR) 또는 마스터 파티션 테이블(MPT)
마스터 부트 레코드(MBR) 또는 마스터 파티션 테이블(MPT)이라고도 하는 DOS의 FDISK.EXE 명령을 실행하여 하드 디스크 드라이브에 생성됩니다.
MBR에는 하드 디스크 드라이브에서 활성(또는 부팅 가능한) 파티션을 로드하고 시작하는 작은 프로그램이 포함되어 있습니다. 마스터 부트 레코드에는 시작 섹터, 종료 섹터, 파티션 크기 등과 같은 하드 디스크 드라이브의 모든 4개 기본 파티션에 대한 정보가 들어 있습니다.
MBR은 절대 섹터 0에 있거나 실린더 0, 헤드 0, 섹터 1에 있으며 디스크에 파티션이 두 개 이상 있는 경우 각 시작 부분에 확장 마스터 부트 레코드가 있습니다. 확장 파티션 볼륨.
자세한 설명은 이 책의 앞부분에서 논의한 “디스크 및 OS에 대한 논리적 접근' 장을 참조하십시오.
마스터 부트 레코드 형식
하드 디스크 드라이브를 일반적으로 DOS에 의해 고유한 드라이브 문자가 할당된 여러 논리 드라이브로 분할할 수 있습니다. 한 번에 하나의 파티션만 활성(또는 부팅 가능한) 파티션으로 표시할 수 있습니다.
마스터 부트 레코드의 마스터 파티션 테이블 항목은 4개로 제한됩니다. 그러나 확장 마스터 부트 레코드의 위치는 확장 파티션 테이블이 포함된 마스터 부트 레코드의 도움으로 얻을 수 있습니다. 확장 파티션 테이블은 부트 코드가 없고 이 446바이트 공간이 일반적으로 기본 파티션 테이블과 형식이 정확히 동일합니다. 부팅 코드용으로 예약되어 있으며 비어 있습니다.
마스터 부트 레코드의 모든 512바이트는 표에 나와 있는 대로 다음과 같이 손상됩니다.
모든 확장 파티션은 확장 파티션 항목이 예약한 공간 내에 있어야 합니다. 확장 파티션 중 2개만 사용됩니다. 첫 번째는 일반 파티션으로, 두 번째는 다른 확장 파티션이 있는 경우 사용합니다.
따라서 하나의 마스터 파티션 테이블의 도움으로 옆에 있는 다른 확장 마스터 파티션 테이블의 위치를 얻을 수 있습니다(있는 경우).
파티션 테이블 항목 형식
MBR에서 파티션의 파티션 테이블 항목 형식은 다음 표에 나와 있습니다. 모든 MBR의 모든 파티션 항목은 특정 의미를 가진 다음 바이트로 나눌 수 있습니다.
MBR의 파티션 테이블을 읽는 프로그램 작성
다음은 MBR의 파티션 테이블에서 4개의 파티션 항목을 모두 읽는 프로그램입니다. 프로그램은 MBR의 파티션 테이블에 작성된 파티션 정보의 모든 매개변수를 표시합니다.
프로그램의 코딩은 다음과 같습니다:
/* MBR 파티션 테이블을 읽는 프로그램 */
# include <bios.h>
/* 파티션 테이블에서 파티션 항목을 읽는 구조 */
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 */
} ;
/* 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();
/* 첫 번째 하드 디스크의 첫 번째 섹터 읽기 */
biosdisk ( 2, 0x80, 0, 0, 1, 1, &p ) ;
display(); /* Display the information of MBR
Partition Table */
getch();
}
/* 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;
}
프로그램의 출력에 의해 제공된 정보는 아래와 같이 표시됩니다.
코딩에 대한 의견:
구조 파티션은 MBR의 파티션 테이블에서 파티션의 파티션 항목의 다양한 매개변수를 읽는 데 사용됩니다. 구조 부분은 MBR 정보를 읽는 데 사용됩니다.
display() 함수는 MBR 파티션 테이블 매개변수의 정보를 화면에 표시합니다. 프로그램의 출력을 보면 시작 및 종료 실린더와 섹터 번호가 다음과 같이 표시됩니다.
Starting Sector = 1
Starting Cylinder = 0
Ending Sector = 63
Ending Cylinder = 701
이러한 섹터 및 실린더 번호는 2바이트의 조합으로 계산됩니다. 다음 표는 이러한 숫자가 계산되는 방식을 보여줍니다.
따라서 파티션의 시작 C-H-S= 0-0-1.
마찬가지로 파티션의 끝 실린더 및 섹터 번호에 대한 인코딩은 다음 표에 나와 있습니다.
따라서 파티션의 끝 C-H-S = 701-254-63.
모든 논리 파티션과 해당 정보를 찾는 프로그램
앞에서 논의한 프로그램은 MBR의 파티션 테이블에서 파티션 정보를 읽는 것이었습니다. 그러나 MBR을 읽는 것만으로는 디스크의 확장 파티션에 있는 다른 논리 파티션의 정보를 얻을 수 없습니다.
우리는 이미 마스터 부트 레코드가 마스터 파티션 테이블의 항목을 4개로 제한한다는 점에 대해 논의했습니다. 그러나 확장 마스터 부트 레코드의 위치는 기본 파티션 테이블과 형식이 정확히 동일한 확장 파티션 테이블을 포함하는 마스터 부트 레코드의 도움으로 얻을 수 있습니다.
모든 확장 파티션은 확장 파티션 항목이 예약한 공간 내에 있어야 합니다. 확장 파티션 중 2개만 사용됩니다. 첫 번째는 일반 파티션으로, 두 번째는 다른 확장 파티션이 있는 경우 사용합니다.
따라서 하나의 마스터 파티션 테이블의 도움으로 옆에 있는 다른 확장 마스터 파티션 테이블의 위치를 알 수 있습니다(있는 경우).
다음 프로그램은 디스크에서 MBR 및 확장 MBR을 읽는 모든 논리 파티션과 해당 파티션 항목 정보를 찾기 위한 것입니다. 프로그램의 코딩은 다음과 같습니다.
/* 디스크에 있는 모든 논리 파티션의 매개변수를 읽는 프로그램 */
#include<dos.h>
har buffer[512], report_par[20];
unsigned drive_num =0x80;
unsigned long star_sec[20], sec;
/* 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();
}
프로그램의 출력은 다음과 유사하게 표시됩니다.
파티션 1 - FAT32
파티션 2 - FAT32
파티션 3 - FAT32
디스크의 총 파티션 = 3
파티션 1의 시작 섹터 번호 = 63
파티션 2의 시작 섹터 번호 = 11277693
파티션 3의 시작 섹터 번호 = 25623738
코딩에 대한 의견:
diskaddrpacket 구조는 readabsolutesectors 기능에서 사용할 디스크 주소 패킷 형식을 읽는 데 사용됩니다.
All_partition_information( ) 함수는 파티션 항목에서 모든 파티션의 모든 매개변수를 찾는 데 사용됩니다.
이 프로그램에서는 디스크에서 사용 가능한 모든 논리 파티션의 파일 시스템 및 상대 섹터 정보만 표시했지만 All_partition_information( ) 함수를 사용하여 파티션 정보의 다른 매개변수 정보를 인쇄할 수도 있습니다. 더 많은 printf와 함께.
함수의 코딩은 다음과 같습니다.
/* 모든 논리 파티션을 찾는 기능’ 파티션 항목을 읽는 정보 */
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_sec= *(unsigned long *)(buffer+454+active_pos*16);
/* 파티션의 섹터 수 */
no_sectors=*(long *)(buffer+458+active_pos*16);
/* 파일 시스템 표시기 바이트 식별 */
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;
/* FAT32 파티션의 경우 */
case 0x0B:
case 0x0C: report_par[*no_par]='3';
printf("\n Partition -%d = FAT32",
*no_par+1);
break;
/* 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;
/* 확장 파티션이 있는지 확인 */
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
/* 섹터 0에서 다른 비활성 주 파티션 확인 */
if(*sec==0)
{
for(i=0;i<4;i++)
{
active_par=buffer[446+i*16];
/* 파일 시스템 표시기 바이트 식별 */
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])
{
/* NTFS 파티션의 경우 */
case 0x07: report_par[*no_par]='N';
printf("\n Partition -%d = NTFS",
*no_par+1);
break;
/* FAT32 파티션의 경우 */
case 0x0B:
case 0x0C: report_par[*no_par]='3';
printf("\n Partition -%d = FAT32",
*no_par+1);
break;
/* FAT16 파티션의 경우 */
case 0x04:
case 0x06:
case 0x0E: report_par[*no_par]='1';
printf("\n Partition -%d = FAT16",
*no_par+1);
break;
} // End of switch
/* 상대 섹터 파티션 수 */
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;
}
코딩에 대한 의견:
함수는 MBR에서 파티션 정보 읽기를 시작한 다음 필요한 경우 확장 MBR을 읽습니다. 함수 readabsolutesectors는 *sec로 지정된 절대 섹터를 읽습니다.
sectors_part[*no_par]는 파티션의 섹터 수를 저장할 배열입니다. 파티션 번호는 0부터 시작하는 *no_par로 지정됩니다.
no_sectors는 파티션의 섹터 수이고 relative_sec은 해당 파티션의 상대 섹터 번호입니다.
star_sec[*no_par]는 파티션의 명시 섹터 번호를 저장하는 배열입니다. 파티션 번호는 0부터 시작하는 *no_par로 지정됩니다.
star_cyl, star_hea, star_sec은 각 파티션의 시작 정보를 CHS 기준으로 유지하는 배열입니다. star_cyl은 시작 실린더의 정보를 저장하고 star_hea는 시작 헤드의 정보를 저장하고 star_sec은 파티션의 시작 섹터 정보를 저장합니다.
readabsolutesectors 기능에 대한 설명은 이 책의 앞부분에 제공된 장을 참조하십시오.
프로그래밍으로 MBR 수정
MBR 파티션 테이블 항목 값을 수정하는 방법을 보여주는 샘플 프로그램이 아래에 나와 있습니다. 프로그램은 MBR 파티션 테이블의 파티션 항목 두 번째 값을 수정합니다.
프로그램 코딩은 다음과 같습니다.
/* MBR의 파티션 테이블 항목 값을 수정하는 프로그램 */
# include <bios.h>
/* 파티션 테이블에서 파티션 항목을 읽는 구조 */
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 */
} ;
/* 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();
/* MBR의 파티션 테이블에서 두 번째 파티션 항목의 파티션 정보를 다음 값으로 수정한다고 가정합니다 */
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 */
/* MBR에 새 정보 쓰기 *\
/* MBR 파티션 테이블에 값을 쓰려면 아래 주어진 biosdisk 기능의 주석을 해제하십시오. */
// biosdisk ( 3, 0x80, 0, 0, 1, 1, &p ) ;
display(); /* Display the Modified
Information */
getch();
}
코딩에 대한 의견:
위의 프로그램은 MBR의 파티션 테이블 항목 값을 수정하는 방법을 보여주는 샘플 프로그램입니다. 확장 파티션에 있는 이러한 논리 파티션에 대한 파티션 항목 값을 수정하려면 확장 MBR의 파티션 테이블에서 값을 수정해야 합니다. .
파티션 테이블 항목을 수정하기 위해 여기에 제공된 값은 수정 방법을 보여주기 위한 것입니다. 불법적이거나 비논리적인 값으로 파티션 테이블을 수정하지 마십시오. 이렇게 하면 전체 파티션에 액세스할 수 없게 됩니다.
구조 파티션은 파티션 테이블에서 파티션 항목을 읽고 MBR을 읽는 구조 부분에 사용됩니다. 실제로 파티션 테이블을 수정하려면 biosdisk( ) 함수
의 주석 처리를 제거하세요.
파티션의 시작 및 끝 값, 섹터 및 실린더 번호를 수정하려면 프로그램 주석에 설명된 대로 값을 계산하여 MBR 파티션 테이블을 읽고 표시합니다, 이 장의 시작 부분에서 논의되었습니다.