对一个典型的 MBR 的详尽分析
这两天饶有兴趣地对 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
整个 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 编辑 ]
第二大部分是: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 工具查看。
整个 MBR 流程是:
INT19h (BIOS 自检后,int19 读 MBR 到 0x7c00)
|
|
|
V
0x7c00 ----> 自我复制到 0x061b ------+
|
|
|
--------------------------------------+
|
|
V failure
检查 4 个分区 -----> 检查标志 0x55aa ---------> 死循环
|
|
|
------------------------+
|
|
V
bootsector 读进 0x7c00 -----> 重新执行 0x7c00
版主真是厉害
分析windows的MBR,
linux的MBR也是一样的吧。
汇编啊,先mark一下,等有毅力了再来学习
我觉得写这个mbr的时候应该不是汇编吧,你这个是反汇编的吧。
不过这样理解比较清楚。
顶
MBR运行时只有BIOS中断可调用,而且MBR中存放代码的空间有限,只能用汇编。