zoukankan      html  css  js  c++  java
  • 主引导扇区MBR的解析

    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设备

    1. #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)。


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


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

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

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


    1. #include<stdio.h>
    2. #include <unistd.h>
    3. #include<sys/types.h>
    4. #include<sys/stat.h>
    5. #include<fcntl.h>
    6. #define PT_OFFSET 446
    7. #define PT_LEN 16
    8. #define PT_N 4
    9. #define CHECK_POS 510 
    10. //Cylinder-Head-Sectoradderess type
    11. typedef struct
    12. {
    13.         unsigned char head:8;
    14.         unsigned char sector:6;
    15.         unsigned short cylinder:10;
    16. } CHS;
    17. void printPT(char *buf);
    18. int main(int argc, char *argv[])
    19. {
    20.         int fd = open(argv[1], O_RDONLY);
    21.         if(fd < 0)
    22.         {
    23.                 perror("open");
    24.                 exit(1);
    25.         }
    26.         if(lseek(fd,CHECK_POS,SEEK_SET) == -1)
    27.         {
    28.                 fprintf(stderr,"lseek to CHECK_POS err %m ");
    29.                 close(fd);
    30.                 return -1;
    31.         } 
    32.         unsigned char checkbuf[16] = {0};
    33.         if(read(fd,checkbuf,2) != 2)
    34.         {
    35.                 fprintf(stderr,"read check info failed %m ");
    36.                 close(fd);
    37.                 return -2;
    38.         }
    39.         if(checkbuf[0] != 0x55 || checkbuf[1] != 0xaa)
    40.         {
    41.                 fprintf(stderr, "not valid mbr format ");
    42.                 close(fd);
    43.                 return -3;
    44.         }
    45.         if(lseek(fd, PT_OFFSET, SEEK_SET) ==-1)
    46.         {
    47.                 close(fd);
    48.                 perror("lseek");
    49.                 exit(1);
    50.         }
    51.         char buf[PT_LEN];
    52.         int i;
    53.         for(i = 0; i < PT_N; i++)
    54.         {
    55.                 bzero(buf, PT_LEN);
    56.                 if(read(fd, buf, PT_LEN) !=PT_LEN)
    57.                 {
    58.                         printf("can't getfull partition table[%d] ", i);
    59.                         close(fd);
    60.                         exit(1);
    61.                 }
    62.                 if(buf[1] || buf[2] || buf[3])
    63.                         printPT(buf);
    64.         }
    65.         close(fd);
    66.         return 0;
    67. }
    68. void printPT(char *buf)
    69. {
    70.         switch((unsigned char)buf[0])
    71.         {
    72.                 case 0x80:
    73.                         printf("bootable ");
    74.                         break;
    75.                 case 0x00:
    76.                         printf("non-bootable ");
    77.                         break;
    78.                 default:
    79.                         printf("invalid ");
    80.         }
    81.         CHS chs;
    82.         memcpy(&chs, buf+1, 3); 
    83.         printf("from CHSAddr: ");
    84.         printf("%12s%12s%12s ","head","sector","cylinder");
    85.         printf("%12d%12d%12d ",chs.head,chs.sector,chs.cylinder);
    86.         memcpy(&chs, buf+5, 3);
    87.         printf("to CHSAddr: ");
    88.         printf("%12s%12s%12s ","head","sector","cylinder");
    89.         printf("%12d%12d%12d ",chs.head,chs.sector,chs.cylinder);
    90.         printf("partition type:%d ",(unsigned char)buf[4]);
    91.         printf("LENGTH:%d(sectors) ", *(unsigned int*)&buf[12]);
    92. }
        
    1. dd if=/dev/sdb of=mbr bs=512 count=1
    首先看一下我的U盘的MBR的庐山真面目:

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

    执行结果为:



    参考文献:
    1 维基百科
    2 Linux那些事儿
    光荣属于前辈。
  • 相关阅读:
    修改git提交的用户名和密码
    并发编程大师系列之:wait/notify/notifyAll/condition
    并发编程大师系列之:Synchronized的类锁和对象锁
    并发编程大师系列之:线程的定义和中断 interrupt
    SpringBoot项目mysql配置文件密码加密(jasypt)
    Linux下安装nginx实现伪分布
    idea远程debug调试阿里云ECS
    使用docker简单启动springboot项目
    用Navicat连接阿里云ECS服务器上的MySQL数据库
    Linux下安装JDK1.8
  • 原文地址:https://www.cnblogs.com/leaven/p/6360932.html
Copyright © 2011-2022 走看看