Lunatine
· 3 min read

Linux에서 MBR 파티션 테이블 살펴보기

  • 기존 Tumblr의 글을 옮겨온 것이기 때문에 Markdown 확장문법 유무로 인한 차이가 있습니다.

MBR 파티션 테이블

본 문서는 리눅스 시스템에서 MBR 파티션 테이블의 구조를 확인하는 방법에 대해서 설명하고 있습니다.[1]

MBR이란?

MBR은 Master Boot Record의 약자로 부팅을 하기 위한 정보를 담고 있으며 일반적으로 0번 섹터에 저장 되어 있습니다. MBR이 여전히 많이 쓰이고 있지만 오래 된 기술이다보니 그 크기는 1개 섹터 크기 (512Byte)로 되어있어 제약사항이 많습니다. 상세한 정보는 위키피디아 문서를 참고하시면 됩니다.

  • 위키피디아 MBR 문서

MBR 구조

MBR Structure

  • 표1. (출처 : Microsoft Technet)

MBR은 위와 같은 구조로 되어있습니다. 부팅을 위한 코드 공간이 446Byte. 프라이머리 파티션 테이블을 위한 공간이 64Byte 그리고 MBR 시그니쳐 값으로 2Byte (0xAA55)를 사용합니다. 본 문서에서는 프라이머리 파티션 테이블 부분을 살펴보도록 하겠습니다.

MBR Primary Partition Table

Imgur

64Byte의 MBR 파티션 테이블 구조는 위와 같은 16Byte 레코드 4개로 이루어져 있습니다. 각 레코드에는 파티션의 상태 정보와 종류, C/H/S 기반의 시작/끝 주소, LBA 기반의 섹터 시작 주소와 파티션 크기 정보가 담겨져 있습니다. 요즘에는 CHS 기반으로 접근하지 않기 때문에 실질적으로 첫 번째 LBA주소와 파티션 크기를 통해서 파티션 테이블 레이아웃을 표현 합니다.

먼저 디스크의 파티션 테이블을 살펴보면 아래와 같습니다. 섹터단위로 보기 위해서 -lu 옵션을 주었습니다. 아래 파티션 테이블은 첫 번째 파티션이 [AF](abbr:Advanced Format) 디스크를 위해서 2048 섹터부터 시작하도록 파티셔닝 되어있습니다.

$ fdisk -lu /dev/sda

Disk /dev/sda: 256.1 GB, 256060514304 bytes
255 heads, 63 sectors/track, 31130 cylinders, total 500118192 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x000f1ef8

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *        2048   199999487    99998720   83  Linux
/dev/sda2       199999488   500118191   150059352   83  Linux

앞서 살펴본 MBR 파티션 테이블에서는 Start에 해당하는 LBA주소 2048과 그 크기인 199997440이 저장되어있고 이를 통해서 End 위치[2] 를 표기하게 됩니다.

자, 이제 MBR 파티션 테이블을 열어서 실제로 저장이 되어있는지 확인해 보도록 하겠습니다.

MBR 파티션 테이블 열어보기

먼저 MBR은 0번 섹터에 저장 되기 때문에 아래 커맨드를 통해서 MBR을 통째로 덤프 받도록 합니다. (본 예제에서는 /dev/sda가 OS 디스크 입니다) 1섹터는 512byte 이기 때문에 512byte 1개를 파일로 내려 받습니다.

$ dd if=/dev/sda of=mbr.dump bs=512 count=1

이제 이 파일에서 파티션 테이블에 해당하는 뒤쪽 66byte만 확인하면 아래와 같습니다.

  • 사실 MBR을 따로 받았기 때문에 -n 66 옵션은 생략해도 무방합니다. 그리고 MBR을 저장하지 않고 직접 디스크에서 덤프하는 방법도 있습니다. 본 예제에서는 덤프받은 파일을 가지고 설명합니다.
    $ hexdump -s 446 -n 66 mbr.dump
    00001be 2080 0021 fe83 ffff 0800 0000 b800 0beb
    00001ce 6400 a104 e983 9a7f c000 0beb 72b0 11e3
    00001de 0000 0000 0000 0000 0000 0000 0000 0000
    *
    00001fe aa55
    0000200

마지막에 앞서 살펴본 MBR의 시그니쳐인 0xAA55의 값인 aa55가 보입니다.

이렇게 보면 읽기 어렵기 때문에 MBR 파티션테이블의 레코드가 16Byte 이므로 16Byte씩 끊어서 보기좋게 표시해 보도록 하겠습니다.

$ hexdump -s 446 -e '8/1 "0x%02x " "\t" 2/4 "%0d "\n"' mbr.dump
0x80 0x20 0x21 0x00 0x83 0xfe 0xff 0xff	2048 199997440
0x00 0x64 0x04 0xa1 0x83 0xe9 0x7f 0x9a	199999488 300118704
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00	0 0
*
0x55 0xaa 0x   0x   0x   0x   0x   0x

먼저, 표2.의 파티션테이블의 레코드 명세에 따라서 8Byte는 1Byte 씩 Hex로 표기하도록 하였고 나머지 8Byte는 4Byte씩 숫자로 표기하도록 하였습니다. 그 결과 첫 번째 줄의 마지막 두 컬럼에 fdisk로 확인했던 첫 번째 파티션의 시작 주소인 2048과 그 크기를 확인 할 수 있습니다. 마찬가지로 총 2개의 파티션 테이블을 가지고 있기 때문에 두 번째 줄에서도 두 번째 파티션의 시작 주소와 크기를 확인할 수 있습니다.

이제 Hex로 표기한 8Byte를 살펴보도록 하겠습니다. 첫 번째 줄을 살펴보면 표2.의 명세대로 첫 번째 Byte는 파티션의 상태를 의미합니다. 첫 번째 줄의 0x80을 통해서 부트 파티션임을 확인 할 수 있으며 이는 fdisk에서 "*" 로 표기 된 부트 플래그를 의미하는 걸 알 수 있습니다.

그 뒤의 3Byte(0x20 0x21 0x00)는 C/H/S 값을 의미하며 다음 1Byte 0x83은 파티션의 종류를 의미합니다. 낯익은 숫자인데 이 숫자는 fdisk에서 파티션 타입을 지정할 때 사용하는 값과 정확히 일치합니다.

Imgur

그리고 나머지 3Byte (0xfe 0xff 0xff)는 종료 지점을 나타내는 CHS 값 입니다.

다시, 시작지점 C/H/S를 나타내는 앞의 3Byte 값을 CHS to LBA 변환 식에 대입해 보면

LBA = ( ( CYLINDER * heads per cylinder + HEAD ) * sectors per track ) + SECTOR – 1
LBA = ( ( 0x00 * 255 + 0x20 ) * 63) + 0x21 -1
 = 2048

위와 같이 시작 지점을 나타내는 LBA 주소 값을 얻을 수 있습니다. 실제로 요즘에는 사용되지 않는(다만 OS에서 지원해주고 있는) C/H/S 값은 LBA를 통해 역으로 계산 된 것이기 때문에 참고로만 보시면 됩니다.

이렇게 실제 디스크의 첫 번째 섹터에 있는 MBR을 열어보고 시스템 툴에서 보여주는 값이 어떻게 저장되어 있는지 확인해 보았습니다.

보너스

  • MBR은 0번 섹터에 기록되기 때문에 [GPT] 는 1번 섹터부터 기록 됩니다.
  • MBR이 담긴 섹터의 앞쪽 446Byte는 부트코드가 담겨있는데 이곳에 GRUB 부트로더가 들어있습니다. ($ hexdump -C -n446 mbr.dump로 확인해 보세요)
  • MBR의 파티션 테이블 레코드에서 파티션 크기를 나타내는 값이 4Byte이기 때문에 2^32인 2TB까지만 사용이 가능합니다. 즉, MBR로 단일 파티션이 2TB이상 사용하지 못하는 이유입니다

  1. 이 문서는 MBR에 대한 질문을 받아서 설명해 줬던 내용을 정리한 것입니다. ↩︎

  2. 2048 + 199997440 - 1 (2048부터 시작하기 때문) ↩︎