对一个典型的 MBR 的详尽分析

发布于 2022-09-18 17:29:13 字数 24589 浏览 9 评论 0

这两天饶有兴趣地对 xp 的 MBR 详尽地分析了一番,当作是温故知新。若有不对,敬请指出

下面是摘自实际 Xp 的磁盘 image 里的 windows XP MBR。

----------------------------------------------------------------------------------------
00000000  33C0              xor ax,ax
00000002  8ED0              mov ss,ax
00000004  BC007C            mov sp,0x7c00
00000007  FB                sti
00000008  50                push ax
00000009  07                pop es
0000000A  50                push ax
0000000B  1F                pop ds
0000000C  FC                cld

0000000D  BE1B7C            mov si,0x7c1b        /* 从 1b 开始到 1FF 区域 */
00000010  BF1B06            mov di,0x61b
00000013  50                push ax
00000014  57                push di
00000015  B9E501            mov cx,0x1e5
00000018  F3A4              rep movsb              /* 将 1B ~ 1FF 复制到 0x061B */
0000001A  CB                retf                   /* 跳到 061B 处执行 */

0000001B  BDBE07            mov bp,0x7be           /* DPT1 */
0000001E  B104              mov cl,0x4
00000020  386E00            cmp [bp+0x0],ch        /* 测试 DPT1 是否为可启动分区 */
00000023  7C09              jl 0x2e                /* DPT1[0] = 80h, 是就跳转到 0x2e */
00000025  7513              jnz 0x3a               /* DPT1[0] != 80 && DPT1[0] != 0,即:出错 */

00000027  83C510            add bp,byte +0x10
0000002A  E2F4              loop 0x20
0000002C  CD18              int 0x18

0000002E  8BF5              mov si,bp
00000030  83C610            add si,byte +0x10        /* next DPT,即:DPT2 */
00000033  49                dec cx                   /* 判断下一个分区 */
00000034  7419              jz 0x4f
00000036  382C              cmp [si],ch              /* DPT2[0] */
00000038  74F6              jz 0x30                  /* DPT2[0] == 0, goto 0x30 */
                                                     /* 循环判断每个分区 */
                                                     /* 如果 DPT2[0] != 0,转到出错处理 */

/*********** 下面这段是分区标志不符的出错处理 **************/

0000003A  A0B507            mov al,[0x7b5]           /* 取 mbr 数据区: mbr_data[0] */
0000003D  B407              mov ah,0x7               
0000003F  8BF0              mov si,ax                /* ax = 0x072c, 即:mbr_str 区域 */

print_msg:          /* 打印信息,最终死循环 */

00000041  AC                lodsb                    
00000042  3C00              cmp al,0x0
00000044  74FC              jz 0x42                  
00000046  BB0700            mov bx,0x7
00000049  B40E              mov ah,0xe
0000004B  CD10              int 0x10
0000004D  EBF2              jmp short 0x41

/*  通过了每个分区检查后的后续处理 */

0000004F  884E10            mov [bp+0x10],cl          /* DPT2[0] = 0 */
00000052  E84600            call word 0x9b            /* int13_read_sector_to_mem() */

00000055  732A              jnc 0x81                  /* succssed */

/* 磁盘参数失败后 */
00000057  FE4610            inc byte [bp+0x10]        /* DPT2[0]++ */
0000005A  807E040B          cmp byte [bp+0x4],0xb     /* 检查分区的 系统类型ID */
0000005E  740B              jz 0x6b
00000060  807E040C          cmp byte [bp+0x4],0xc
00000064  7405              jz 0x6b
00000066  A0B607            mov al,[0x7b6]
00000069  75D2              jnz 0x3d                 /* 打印 "Error loading operation system"  */

0000006B  80460206          add byte [bp+0x2],0x6
0000006F  83460806          add word [bp+0x8],byte +0x6
00000073  83560A00          adc word [bp+0xa],byte +0x0
00000077  E82100            call word 0x9b           /* int13_read_sector_to_mem() */
0000007A  7305              jnc 0x81
0000007C  A0B607            mov al,[0x7b6]
0000007F  EBBC              jmp short 0x3d         /* 打印 "Error loading operation system"  */

00000081  813EFE7D55AA      cmp word [0x7dfe],0xaa55            /* 检查 mbr 标记 0xaa55 */
00000087  740B              jz 0x94

00000089  807E1000          cmp byte [bp+0x10],0x0
0000008D  74C8              jz 0x57
0000008F  A0B707            mov al,[0x7b7]
00000092  EBA9              jmp short 0x3d        /* 打印 "Error loading operation system"  */

00000094  8BFC              mov di,sp          /* sp = 0x7c00 */
00000096  1E                push ds
00000097  57                push di
00000098  8BF5              mov si,bp
0000009A  CB                retf               /* 回到 0x7c00 */

int13_read_sector_to_mem:

0000009B  BF0500            mov di,0x5
0000009E  8A5600            mov dl,[bp+0x0]             /* 硬盘 */
000000A1  B408              mov ah,0x8                  
000000A3  CD13              int 0x13                    /* 获取磁盘参数 */

000000A5  7223              jc 0xca   
000000A7  8AC1              mov al,cl
000000A9  243F              and al,0x3f             /* max sector */
000000AB  98                cbw
000000AC  8ADE              mov bl,dh               /* max header */
000000AE  8AFC              mov bh,ah               /* ah = 00 */
000000B0  43                inc bx
000000B1  F7E3              mul bx                  /* sector * header */
000000B3  8BD1              mov dx,cx
000000B5  86D6              xchg dl,dh
000000B7  B106              mov cl,0x6
000000B9  D2EE              shr dh,cl
000000BB  42                inc dx
000000BC  F7E2              mul dx
000000BE  39560A            cmp [bp+0xa],dx
000000C1  7723              ja 0xe6
000000C3  7205              jc 0xca
000000C5  394608            cmp [bp+0x8],ax
000000C8  731C              jnc 0xe6

000000CA  B80102            mov ax,0x201
000000CD  BB007C            mov bx,0x7c00              /* 读进 0x7c00 */
000000D0  8B4E02            mov cx,[bp+0x2]            /* 起始 cylinder,起始 sector */
000000D3  8B5600            mov dx,[bp+0x0]            /* 起始 header */
000000D6  CD13              int 0x13                  
000000D8  7351              jnc 0x12b                  /* return */

000000DA  4F                dec di
000000DB  744E              jz 0x12b
000000DD  32E4              xor ah,ah
000000DF  8A5600            mov dl,[bp+0x0]
000000E2  CD13              int 0x13
000000E4  EBE4              jmp short 0xca

000000E6  8A5600            mov dl,[bp+0x0]
000000E9  60                pushaw
000000EA  BBAA55            mov bx,0x55aa
000000ED  B441              mov ah,0x41
000000EF  CD13              int 0x13
000000F1  7236              jc 0x129
000000F3  81FB55AA          cmp bx,0xaa55
000000F7  7530              jnz 0x129
000000F9  F6C101            test cl,0x1
000000FC  742B              jz 0x129
000000FE  61                popaw
000000FF  60                pushaw
00000100  6A00              push byte +0x0
00000102  6A00              push byte +0x0
00000104  FF760A            push word [bp+0xa]
00000107  FF7608            push word [bp+0x8]
0000010A  6A00              push byte +0x0
0000010C  68007C            push word 0x7c00
0000010F  6A01              push byte +0x1
00000111  6A10              push byte +0x10
00000113  B442              mov ah,0x42
00000115  8BF4              mov si,sp
00000117  CD13              int 0x13
00000119  61                popaw
0000011A  61                popaw
0000011B  730E              jnc 0x12b
0000011D  4F                dec di
0000011E  740B              jz 0x12b
00000120  32E4              xor ah,ah
00000122  8A5600            mov dl,[bp+0x0]
00000125  CD13              int 0x13
00000127  EBD6              jmp short 0xff
00000129  61                popaw
0000012A  F9                stc
0000012B  C3                ret

/********** 下面的区域是 mbr 常量符: mbr_str **************/

/*
char *mbr_str = "Invalid partition table."
               "Error loading operation system."
               "Missing operation system."
*/

0000012C  496E7661 6C696420 70617274 6974696F
0000013C  6E207461 626C6500 4572726F 72206C6F
0000014C  6164696E 67206F70 65726174 696E6720
0000015C  73797374 656D004D 69737369 6E67206F
0000016C  70657261 74696E67 20737973 74656D

/********** 下面是空白区域 *****************/

0000017B  00000000           
0000017F  00000000           
00000183  00000000
00000187  00000000
0000018B  00000000
0000018F  00000000
00000193  00000000
00000197  00000000
0000019B  00000000
0000019F  00000000
000001A3  00000000
000001A7  00000000
000001AB  00000000
000001AF  00000000
000001B3  00000000
000001B4  00

/*** 下面这段是 MBR 用到的数据区:mbr_data ***/

000001B5  2C           /* 指向 "Invalid partition table." */
000001B6 44           /* 指向 "Error loading operation system." */
000001B7  63           /* 指向 "Missing operation system." */
000001B8 61
000001B9 A2
000001BA  61
000001BB  A2
000001BC  00
000001BD  00

/* 1BE - 1FD = disk partion table */

/* 1BE - 1CD = DPT1 */
000001BE  80          /* boot indicator */
                      /* 00:  不可启动分区 */
                      /* 80:  可启动分区(只可有1个启动分区)*/

000001BF  01           /* 起始 header 号 */
000001C0  01           /* 起始 sector 号 */
000001C1  00           /* 起始 cylinder 号 */
000001C2  07           /* 系统属性 ID 标记
                       00h:未知操作系统
                       01h:DOS FAT12(16位扇区数)
                       02h:XENIX
                       04h:DOS FAT16(16位扇区数)
                       05h:DOS 扩展分区(DOS 3.3+)
                       06h:DOS 4.0 (Compaq 3.31), 32位扇区数
                       07h:HPFS/NTFS
                       0ah:OS/2
                       0bh:win95 fat32
                       0ch:win95 fat32 (LBA)
                       ... ...
                       */
000001C3  FE           /* 结束 header 号 */
000001C4  FF           /* 结束 sector 号 */
000001C5  FF           /* 结束 cylinder 号 */
000001C6  3F000000     /* 此分区前的扇区总数 */           
000001CA  D9A63F01     /* 此分区的扇区总数 */

/* 1CE - 1DD = DPT2 */
000001CE  00              
000001CF  00
000001D0  00              
000001D1  00
000001D2  00
000001D3  00
000001D4  00
000001D5  00
000001D6  00000000
000001DA  00000000

/* 1DE - 1ED = DPT3 */
000001DE  00
000001DF  00
000001E0  00
000001E1  00
000001E2  00
000001E3  00
000001E4  00
000001E5  00
000001E6  00000000
000001EA  00000000

/* 1EE - 1FD = DPT4 */
000001EE  00
000001EF  00
000001F0  00
000001F1  00
000001F2  00
000001F3  00
000001F4  00
000001F5  00
000001F6  00000000
000001FA  00000000

000001FE  55AA            /* MBR 标记 */

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

调妓 2022-09-25 17:29:13

整个 512 bytes 的 MBR 主要分三大部分:

1、0000h ~ 012Bh 是代码区域
2、012Ch ~ 01FDh 是数据区域
3、01FEh ~ 01FFh 是 2 bytes 的 MBR 标记 "0x55AA"

一、代码部分:主要又分 5 个部分

第1部分:

00000000  33C0              xor ax,ax
00000002  8ED0              mov ss,ax
00000004  BC007C            mov sp,0x7c00
00000007  FB                sti
00000008  50                push ax
00000009  07                pop es
0000000A  50                push ax
0000000B  1F                pop ds
0000000C  FC                cld

0000000D  BE1B7C            mov si,0x7c1b
00000010  BF1B06            mov di,0x61b
00000013  50                push ax
00000014  57                push di
00000015  B9E501            mov cx,0x1e5
00000018  F3A4              rep movsb              /* 将 1B ~ 1FF 复制到 0x061B */
0000001A  CB                retf                   /* 跳到 061B 处执行 */

-----------------------------------------------------------------------------
  主要是设置环境:ds=ss=es=00,sp=0x7c00,将 sp 设 0x7c00 作为栈底,是与 0x7c00 代码区分割开。

  接下来,将 MBR 中的 01Bh ~ 1FFh 区域复制到 061B ~ 7FFh 区域。然后跳到 0x061b 继续执行下面的代码。跳到 0x061b 处执行,实际上就是接着执行 MBR 中的 01Bh 开始的代码。

第 2 部分:

0000001B  BDBE07            mov bp,0x7be           /* DPT1 */
0000001E  B104              mov cl,0x4
00000020  386E00            cmp [bp+0x0],ch        /* 测试 DPT1 是否为可启动分区 */
00000023  7C09              jl 0x2e                /* DPT1[0] = 80h, 是就跳转到 0x2e */
00000025  7513              jnz 0x3a               /* DPT1[0] != 80 && DPT1[0] != 0,即:出错 */
00000027  83C510            add bp,byte +0x10
0000002A  E2F4              loop 0x20
0000002C  CD18              int 0x18

0000002E  8BF5              mov si,bp
00000030  83C610            add si,byte +0x10        /* next DPT,即:DPT2 */
00000033  49                dec cx                   /* 判断下一个分区 */
00000034  7419              jz 0x4f
00000036  382C              cmp [si],ch              /* DPT2[0] */
00000038  74F6              jz 0x30                  /* DPT2[0] == 0, goto 0x30 */
                                                     /* 循环判断每个分区 */
                                                     /* 如果 DPT2[0] != 0,转到出错处理 */

---------------------------------------------------------------------------------------
  0x061b 也就是接下面的 01bh 处的代码。

* 0x7be 实际上就是 MBR 中的 1BEh,这是第1个 DPT(Disk Partition Table)的数据起始地方。
  在整个 MBR 代码中  bp 都等于 0x7be(也即 1bEh)。

* mov cl, 4   是要对 4 个分区表进行检查。

* cmp [bp+0x0], ch   是检查分区表 1  是否为 80h 标志,若 DPT1[0] 即不是 80h,也不是 00h,这样的结果是,打印出错信息,然后最终进入死循环。

* 如查 DPT1 是可启动分区,那么 MBR 还要检查其余的 3 个分区的合法性,其余 3 个分区必须是 00h 标志。

第 3 部分:

/*********** 下面这段是分区标志不符的出错处理 **************/
0000003A  A0B507            mov al,[0x7b5]           /* 取 mbr 数据区: mbr_data[0] */
0000003D  B407              mov ah,0x7               
0000003F  8BF0              mov si,ax                /* ax = 0x072c, 即:mbr_str 区域 */

print_msg:          /* 打印信息,最终死循环 */
00000041  AC                lodsb                    
00000042  3C00              cmp al,0x0
00000044  74FC              jz 0x42                  
00000046  BB0700            mov bx,0x7
00000049  B40E              mov ah,0xe
0000004B  CD10              int 0x10
0000004D  EBF2              jmp short 0x41

------------------------------------------------------------------------------------------
  接下来的第3 部分,主要是检查了 4 个分区,发现都不合法后的处理例程。

下面的代码:

0000003A  A0B507            mov al,[0x7b5]           /* 取 mbr 数据区: mbr_data[0] */
0000003D  B407              mov ah,0x7               
0000003F  8BF0              mov si,ax                /* ax = 0x072c, 即:mbr_str 区域 */

* 0x7b5 也就是 MBR 中的 1b5,这个地方实际上是放着一个 string 指针。这个指针指向出错信息字符串。下面会讲到。

第 4 部分:

/*  通过了每个分区检查后的后续处理 */
0000004F  884E10            mov [bp+0x10],cl          /* DPT2[0] = 0 */
00000052  E84600            call word 0x9b            /* int13_read_sector_to_mem() */
00000055  732A              jnc 0x81                  /* succssed */
/* 磁盘参数失败后 */
00000057  FE4610            inc byte [bp+0x10]        /* DPT2[0]++ */
0000005A  807E040B          cmp byte [bp+0x4],0xb     /* 检查分区的 系统类型ID */
0000005E  740B              jz 0x6b
00000060  807E040C          cmp byte [bp+0x4],0xc
00000064  7405              jz 0x6b
00000066  A0B607            mov al,[0x7b6]
00000069  75D2              jnz 0x3d                 /* 打印 "Error loading operation system"  */
0000006B  80460206          add byte [bp+0x2],0x6
0000006F  83460806          add word [bp+0x8],byte +0x6
00000073  83560A00          adc word [bp+0xa],byte +0x0
00000077  E82100            call word 0x9b           /* int13_read_sector_to_mem() */
0000007A  7305              jnc 0x81
0000007C  A0B607            mov al,[0x7b6]
0000007F  EBBC              jmp short 0x3d         /* 打印 "Error loading operation system"  */

00000081  813EFE7D55AA      cmp word [0x7dfe],0xaa55            /* 检查 mbr 标记 0xaa55 */
00000087  740B              jz 0x94
00000089  807E1000          cmp byte [bp+0x10],0x0
0000008D  74C8              jz 0x57
0000008F  A0B707            mov al,[0x7b7]
00000092  EBA9              jmp short 0x3d        /* 打印 "Error loading operation system"  */

00000094  8BFC              mov di,sp          /* sp = 0x7c00 */
00000096  1E                push ds
00000097  57                push di
00000098  8BF5              mov si,bp
0000009A  CB                retf               /* 回到 0x7c00 */

------------------------------------------------------------------------
  这部分稍长一些,主要是通过了 4 个分区的检查后,进行的后续处理。包括失败后仍将打印出错信息,进入死循环。

下面代码:
00000052  E84600            call word 0x9b            /* int13_read_sector_to_mem() */
00000055  732A              jnc 0x81                  /* succssed */
--------------------------------------------
  调用 MBR 的读磁盘例程,最终,它使用 int13 /02h 号功能进行读入 memory 中。

并转到:
00000081  813EFE7D55AA      cmp word [0x7dfe],0xaa55            /* 检查 mbr 标记 0xaa55 */
00000087  740B              jz 0x94
----------------------------------
  检查 MBR 的标记 0x55aa

最终:
00000094  8BFC              mov di,sp          /* sp = 0x7c00 */
00000096  1E                push ds
00000097  57                push di
00000098  8BF5              mov si,bp
0000009A  CB                retf               /* 回到 0x7c00 */
------------------------------------------------------------------
  重新返回到 0x7c00 执行,但是,这里的 0x7c00 已不是原来的 MBR 了,而是正确的 boot sector 代码,这个 boot sector 应该是分区1 的 bootsector。
  这个 bootsector 就是由刚刚的 int13 /02 读入 0x7c00 的。

* 上面的检查中,任何一个出错,最终都会进入死循环。

第 5 部分,是整段 MBR 代码中最复杂,最长的从磁盘读扇区代码。涉及到具体的 bios int13 使用。

  这个部分主要还是要参考 int13 的使用方法。知道大概流程就行了。具体自己分析。

:wink:

[ 本帖最后由 mik 于 2009-6-9 00:52 编辑 ]

阳光下的泡沫是彩色的 2022-09-25 17:29:13

第二大部分是:MBR 的数据区域。

又分为 3 个部分:
1、空白未用的区域和一个指针区域
2、出错信息字会串。
3、disk partition table 磁盘分区表

第1部分:

/*** 下面这段是 MBR 用到的数据区:mbr_data ***/

000001B5  2C           /* 指向 "Invalid partition table." */
000001B6 44           /* 指向 "Error loading operation system." */
000001B7  63           /* 指向 "Missing operation system." */
000001B8 61
000001B9 A2
000001BA  61
000001BB  A2
000001BC  00
000001BD  00
-----------------------------------------------------------------------------
  这相当于指针,或者说是索引,用来索引出错的字符串信息。

第2部分:  

/*
char *mbr_str = "Invalid partition table."
               "Error loading operation system."
               "Missing operation system."
*/

0000012C  496E7661 6C696420 70617274 6974696F
0000013C  6E207461 626C6500 4572726F 72206C6F
0000014C  6164696E 67206F70 65726174 696E6720
0000015C  73797374 656D004D 69737369 6E67206F
0000016C  70657261 74696E67 20737973 74656D
------------------------------------------------------------------------------
  存放着出错信息字符串。

第3部分是最重要的 DPT:

/* 1BE - 1FD = disk partion table */

/* 1BE - 1CD = DPT1 */
000001BE  80          /* boot indicator */
                      /* 00:  不可启动分区 */
                      /* 80:  可启动分区(只可有1个启动分区)*/

000001BF  01           /* 起始 header 号 */
000001C0  01           /* 起始 sector 号 */
000001C1  00           /* 起始 cylinder 号 */
000001C2  07           /* 系统属性 ID 标记
                       00h:未知操作系统
                       01h:DOS FAT12(16位扇区数)
                       02h:XENIX
                       04h:DOS FAT16(16位扇区数)
                       05h:DOS 扩展分区(DOS 3.3+)
                       06h:DOS 4.0 (Compaq 3.31), 32位扇区数
                       07h:HPFS/NTFS
                       0ah:OS/2
                       0bh:win95 fat32
                       0ch:win95 fat32 (LBA)
                       ... ...
                       */
000001C3  FE           /* 结束 header 号 */
000001C4  FF           /* 结束 sector 号 */
000001C5  FF           /* 结束 cylinder 号 */
000001C6  3F000000     /* 此分区前的扇区总数 */           
000001CA  D9A63F01     /* 此分区的扇区总数 */

/* 1CE - 1DD = DPT2 */
000001CE  00              
000001CF  00
000001D0  00              
000001D1  00
000001D2  00
000001D3  00
000001D4  00
000001D5  00
000001D6  00000000
000001DA  00000000

/* 1DE - 1ED = DPT3 */
000001DE  00
000001DF  00
000001E0  00
000001E1  00
000001E2  00
000001E3  00
000001E4  00
000001E5  00
000001E6  00000000
000001EA  00000000

/* 1EE - 1FD = DPT4 */
000001EE  00
000001EF  00
000001F0  00
000001F1  00
000001F2  00
000001F3  00
000001F4  00
000001F5  00
000001F6  00000000
000001FA  00000000

-----------------------------------------------------------------------
  在这个磁盘映象里,只使用了1个分区,故 DPT2~DPT4 是空白的。

* DPT1[0]:可启动标志,只能是 00h 或 80h
* DPT1[4]:这指示分区的系统文件类型,这里的 07 表示 NTFS 文件类型。
  所有的具体的文件类型,可以在 linux 下使用 fdisk 工具查看。

梦年海沫深 2022-09-25 17:29:13

整个 MBR 流程是:

INT19h (BIOS 自检后,int19 读 MBR 到 0x7c00)
 |
 |
   |
   V

0x7c00  ----> 自我复制到 0x061b ------+
                                                       |
                                                       |
                                                       |
  --------------------------------------+
  |
  |
  V                                                        failure
检查 4 个分区  ----->  检查标志 0x55aa     --------->  死循环
                                     |
                                     |
                                     |
   ------------------------+  
   |
   |
   V
bootsector 读进 0x7c00  -----> 重新执行 0x7c00

猥琐帝 2022-09-25 17:29:13

原帖由 mik 于 2009-6-9 00:11 发表
这两天饶有兴趣地对 xp 的 MBR 详尽地分析了一番,当作是温故知新。若有不对,敬请指出

下面是摘自实际 Xp 的磁盘 image 里的 windows XP MBR。

------------------------------------------------------ ...

版主真是厉害
分析windows的MBR,
linux的MBR也是一样的吧。

清泪尽 2022-09-25 17:29:13

汇编啊,先mark一下,等有毅力了再来学习

缪败 2022-09-25 17:29:13

我觉得写这个mbr的时候应该不是汇编吧,你这个是反汇编的吧。
不过这样理解比较清楚。

可遇━不可求 2022-09-25 17:29:13

原帖由 emmoblin 于 2009-6-9 09:48 发表
我觉得写这个mbr的时候应该不是汇编吧,你这个是反汇编的吧。
不过这样理解比较清楚。

MBR运行时只有BIOS中断可调用,而且MBR中存放代码的空间有限,只能用汇编。

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文