http://blog.chinaunix.net/uid-24774106-id-3340397.html

 

 最近排查一个USB相关的故障,由于信息安全就不多说工作上的事情了,顺路学习了MBR的相关知识,在网上找了一些资料,现在把学习心得写下来,抛砖引玉。感谢无数前辈的分享精神。

    我的U盘插入linux后被识别成了sdb4,我当时很纳闷,为什么是4,没有sdb1 sdb2 sdb3,直接就sdb4 了。linux是从哪里显示的这个4.
 
    是这样的,sdb,这个b是有linux 动态分配的,Linux那些事儿,我是SCSI硬盘中有精彩的讲解。在Kernel代码中时sd_probe函数做的事情。linux对于scsi设备,支持sda~sdzzz,因为英文字母有26个,所以支持这么多SCSI设备

  • #define SD_MAX_DISKS (((26 * 26) + 26 + 1) * 26)
  •     因为我的板子上,有自带的sda SCSI盘,所以我插入的U盘被识别成了sdb。为啥是sdb,LINUX是怎样防止不同的SCSI赋予同一个disk_name 呢,这就是IDR做的事情。IDR integer ID management,是管理小整数分配的。不太了解的筒子请摸我 and 再摸我

        剩下的是,linux 为什么把我的U盘识别成了sdb4。这个分区的信息记录在了U盘的mbr,这就引出了我们本文的主角 MBR。

        MBR,Master Boot Record的缩写,可以成为主引导记录或者主引导扇区。计算机开机之后,访问磁盘必须先访问这个MBR,获取到这个磁盘的相关信息,比如这个磁盘有几个分区啊,每个分区从哪开始,到哪结束,每个分区都是啥文件系统等等信息。

        MBR是一个扇区,在磁盘的位置是(柱面,磁头,扇区)=(0,0,1)。MBR是怎么组织的呢?一个扇区512个字节(不一定,apple有文章表示,扇区大小不一定是512)。
    主引导扇区MBR的解析

        其中从0x01BE到0x01FD这六十四个字节表示的是4个主分区的信息。每个主分区16个字节描述,这16反个字节的含义是:
    主引导扇区MBR的解析

         其中扇区最后两个字节是0x55 0xaa,这也可以验证是否是标准的MBR。下面代码中有。

        对了,有个工具winhex,可以看磁盘的信息,我今天在我的Window 7上看了,发现MBR信息完全不对,按照维基百科提到,分区激活状态时0x80,非激活状态时0x00,结果在winhex上显示的是0xDE,搞得哥很难受。也许是我没学会正确的使用方法。感兴趣的可以搜搜这个工具。其实我们完全可以自己解析MBR的格式。

       我将我的U盘的第一个扇区的内容保存了下来,写了个程序分析这个扇区(MBR)的内容。本程序主要参考了网上的资源,风格不太一致,大家也可以看得出来。上面的表格是wiki百科的内容,光荣属于前辈,我只是整理了下自己的学习心得。


  • #include<stdio.h>
  • #include <unistd.h>
  • #include<sys/types.h>
  • #include<sys/stat.h>
  • #include<fcntl.h>
  • #define PT_OFFSET 446
  • #define PT_LEN 16
  • #define PT_N 4
  • #define CHECK_POS 510 
  • //Cylinder-Head-Sectoradderess type
  • typedef struct
  • {
  •         unsigned char head:8;
  •         unsigned char sector:6;
  •         unsigned short cylinder:10;
  • } CHS;
  • void printPT(char *buf);
  • int main(int argc, char *argv[])
  • {
  •         int fd = open(argv[1], O_RDONLY);
  •         if(fd < 0)
  •         {
  •                 perror("open");
  •                 exit(1);
  •         }
  •         if(lseek(fd,CHECK_POS,SEEK_SET) == -1)
  •         {
  •                 fprintf(stderr,"lseek to CHECK_POS err %m\n");
  •                 close(fd);
  •                 return -1;
  •         } 
  •         unsigned char checkbuf[16] = {0};
  •         if(read(fd,checkbuf,2) != 2)
  •         {
  •                 fprintf(stderr,"read check info failed %m\n");
  •                 close(fd);
  •                 return -2;
  •         }
  •         if(checkbuf[0] != 0x55 || checkbuf[1] != 0xaa)
  •         {
  •                 fprintf(stderr, "not valid mbr format\n");
  •                 close(fd);
  •                 return -3;
  •         }
  •         if(lseek(fd, PT_OFFSET, SEEK_SET) ==-1)
  •         {
  •                 close(fd);
  •                 perror("lseek");
  •                 exit(1);
  •         }
  •         char buf[PT_LEN];
  •         int i;
  •         for(i = 0; i < PT_N; i++)
  •         {
  •                 bzero(buf, PT_LEN);
  •                 if(read(fd, buf, PT_LEN) !=PT_LEN)
  •                 {
  •                         printf("can't getfull partition table[%d]\n", i);
  •                         close(fd);
  •                         exit(1);
  •                 }
  •                 if(buf[1] || buf[2] || buf[3])
  •                         printPT(buf);
  •         }
  •         close(fd);
  •         return 0;
  • }
  • void printPT(char *buf)
  • {
  •         switch((unsigned char)buf[0])
  •         {
  •                 case 0x80:
  •                         printf("bootable\n");
  •                         break;
  •                 case 0x00:
  •                         printf("non-bootable\n");
  •                         break;
  •                 default:
  •                         printf("invalid\n");
  •         }
  •         CHS chs;
  •         memcpy(&chs, buf+1, 3); 
  •         printf("from CHSAddr: \n");
  •         printf("%12s%12s%12s\n","head","sector","cylinder");
  •         printf("%12d%12d%12d\n",chs.head,chs.sector,chs.cylinder);
  •         memcpy(&chs, buf+5, 3);
  •         printf("to CHSAddr: \n");
  •         printf("%12s%12s%12s\n","head","sector","cylinder");
  •         printf("%12d%12d%12d\n",chs.head,chs.sector,chs.cylinder);
  •         printf("partition type:%d\n",(unsigned char)buf[4]);
  •         printf("LENGTH:%d(sectors)\n\n", *(unsigned int*)&buf[12]);
  • }
  •     
  • dd if=/dev/sdb of=mbr bs=512 count=1
  • 首先看一下我的U盘的MBR的庐山真面目:

  • [root@localhost mbr]# cat mbr |od -tx1 -Ax
  • 000000 fa 31 c0 8e d8 8e c0 8e d0 bc 00 7c fb fc 89 e6
  • 000010 bf 00 06 b9 00 01 f3 a5 ea dc 06 00 00 10 00 01
  • 000020 00 00 7c 00 00 00 00 00 00 00 00 00 00 80 3f 00
  • 000030 ff 00 cd 03 1e 0e 1f 3a 16 10 00 74 06 1f ea 36
  • 000040 e7 00 f0 3d fb 54 75 05 8c d8 fb eb 1d 80 fc 08
  • 000050 75 1b e8 81 00 8a 36 13 00 fe ce 8b 0e 15 00 86
  • 000060 cd c0 e1 06 0a 0e 11 00 31 c0 f8 eb 65 80 fc 02
  • 000070 72 cb 80 fc 04 77 c6 60 80 cc 40 50 be 00 00 c7
  • 000080 04 10 00 30 e4 89 44 02 89 5c 04 8c 44 06 66 31
  • 000090 c0 66 89 44 0c 88 f0 f6 26 11 00 88 cf 88 eb c0
  • 0000a0 ef 06 81 e1 3f 00 01 c8 48 89 c7 a1 13 00 f7 26
  • 0000b0 11 00 f7 e3 01 f8 81 d2 00 00 89 44 08 89 54 0a
  • 0000c0 58 30 c0 8a 16 10 00 e8 0c 00 88 26 03 00 61 a1
  • 0000d0 02 00 1f ca 02 00 9c ff 1e 22 00 c3 80 fa 8f 7f
  • 0000e0 04 88 16 2d 06 be 87 07 e8 8d 00 be be 07 31 c0
  • 0000f0 b9 04 00 f6 04 80 74 03 40 89 f5 81 c6 10 00 e2
  • 000100 f2 48 74 02 cd 18 bf 05 00 be 1d 06 c7 44 02 01
  • 000110 00 66 8b 46 08 66 89 44 08 b8 00 42 8a 16 2d 06
  • 000120 cd 13 73 0d 4f 74 49 30 e4 8a 16 2d 06 cd 13 eb
  • 000130 d8 a1 fe 7d 3d 55 aa 75 37 fa 66 a1 4c 00 66 a3
  • 000140 3f 06 be 13 04 8b 04 48 89 04 c1 e0 06 8e c0 31
  • 000150 ff be 1d 06 b9 60 00 fc f3 a5 c7 06 4c 00 17 00
  • 000160 a3 4e 00 fb 8a 16 2d 06 89 ee fa ea 00 7c 00 00
  • 000170 be aa 07 e8 02 00 eb fe ac 20 c0 74 09 b4 0e bb
  • 000180 07 00 cd 10 eb f2 c3 53 74 61 72 74 20 62 6f 6f
  • 000190 74 69 6e 67 20 66 72 6f 6d 20 55 53 42 20 64 65
  • 0001a0 76 69 63 65 2e 2e 2e 0d 0a 00 42 6f 6f 74 20 66
  • 0001b0 61 69 6c 65 64 00 00 00 ea eb d4 ca 00 00 00 00
  • 0001c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  • *
  • 0001e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 01
  • 0001f0 01 00 0b fe ff cc 3f 00 00 00 81 b9 ee 00 55 aa
  • 用写的程序可以分析出蓝色部分,分区的结果。可以看到各分区的filetype,起始位置,结束位置等信息。

    执行结果为:
    主引导扇区MBR的解析


    参考文献:
    1 维基百科
    2 Linux那些事儿
    光荣属于前辈。

    相关文章: