对一个典型的 MBR 的详尽分析
这两天饶有兴趣地对 xp 的 MBR 详尽地分析了一番,当作是温故知新。若有不对,敬请指出下面是摘自实际 Xp 的磁盘 image 里的 windows XP MBR。
----------------------------------------------------------------------------------------
0000000033C0 xor ax,ax
000000028ED0 mov ss,ax
00000004BC007C mov sp,0x7c00
00000007FB sti
0000000850 push ax
0000000907 pop es
0000000A50 push ax
0000000B1F pop ds
0000000CFC cld
0000000DBE1B7C mov si,0x7c1b /* 从 1b 开始到 1FF 区域 */
00000010BF1B06 mov di,0x61b
0000001350 push ax
0000001457 push di
00000015B9E501 mov cx,0x1e5
00000018F3A4 rep movsb /* 将 1B ~ 1FF 复制到 0x061B */
0000001ACB retf /* 跳到 061B 处执行 */
0000001BBDBE07 mov bp,0x7be /* DPT1 */
0000001EB104 mov cl,0x4
00000020386E00 cmp ,ch /* 测试 DPT1 是否为可启动分区 */
000000237C09 jl 0x2e /* DPT1 = 80h, 是就跳转到 0x2e */
000000257513 jnz 0x3a /* DPT1 != 80 && DPT1 != 0,即:出错 */
0000002783C510 add bp,byte +0x10
0000002AE2F4 loop 0x20
0000002CCD18 int 0x18
0000002E8BF5 mov si,bp
0000003083C610 add si,byte +0x10 /* next DPT,即:DPT2 */
0000003349 dec cx /* 判断下一个分区 */
000000347419 jz 0x4f
00000036382C cmp ,ch /* DPT2 */
0000003874F6 jz 0x30 /* DPT2 == 0, goto 0x30 */
/* 循环判断每个分区 */
/* 如果 DPT2 != 0,转到出错处理 */
/*********** 下面这段是分区标志不符的出错处理 **************/
0000003AA0B507 mov al, /* 取 mbr 数据区: mbr_data */
0000003DB407 mov ah,0x7
0000003F8BF0 mov si,ax /* ax = 0x072c, 即:mbr_str 区域 */
print_msg: /* 打印信息,最终死循环 */
00000041AC lodsb
000000423C00 cmp al,0x0
0000004474FC jz 0x42
00000046BB0700 mov bx,0x7
00000049B40E mov ah,0xe
0000004BCD10 int 0x10
0000004DEBF2 jmp short 0x41
/*通过了每个分区检查后的后续处理 */
0000004F884E10 mov ,cl /* DPT2 = 0 */
00000052E84600 call word 0x9b /* int13_read_sector_to_mem() */
00000055732A jnc 0x81 /* succssed */
/* 磁盘参数失败后 */
00000057FE4610 inc byte /* DPT2++ */
0000005A807E040B cmp byte ,0xb /* 检查分区的 系统类型ID */
0000005E740B jz 0x6b
00000060807E040C cmp byte ,0xc
000000647405 jz 0x6b
00000066A0B607 mov al,
0000006975D2 jnz 0x3d /* 打印 "Error loading operation system"*/
0000006B80460206 add byte ,0x6
0000006F83460806 add word ,byte +0x6
0000007383560A00 adc word ,byte +0x0
00000077E82100 call word 0x9b /* int13_read_sector_to_mem() */
0000007A7305 jnc 0x81
0000007CA0B607 mov al,
0000007FEBBC jmp short 0x3d /* 打印 "Error loading operation system"*/
00000081813EFE7D55AA cmp word ,0xaa55 /* 检查 mbr 标记 0xaa55 */
00000087740B jz 0x94
00000089807E1000 cmp byte ,0x0
0000008D74C8 jz 0x57
0000008FA0B707 mov al,
00000092EBA9 jmp short 0x3d /* 打印 "Error loading operation system"*/
000000948BFC mov di,sp /* sp = 0x7c00 */
000000961E push ds
0000009757 push di
000000988BF5 mov si,bp
0000009ACB retf /* 回到 0x7c00 */
int13_read_sector_to_mem:
0000009BBF0500 mov di,0x5
0000009E8A5600 mov dl, /* 硬盘 */
000000A1B408 mov ah,0x8
000000A3CD13 int 0x13 /* 获取磁盘参数 */
000000A57223 jc 0xca
000000A78AC1 mov al,cl
000000A9243F and al,0x3f /* max sector */
000000AB98 cbw
000000AC8ADE mov bl,dh /* max header */
000000AE8AFC mov bh,ah /* ah = 00 */
000000B043 inc bx
000000B1F7E3 mul bx /* sector * header */
000000B38BD1 mov dx,cx
000000B586D6 xchg dl,dh
000000B7B106 mov cl,0x6
000000B9D2EE shr dh,cl
000000BB42 inc dx
000000BCF7E2 mul dx
000000BE39560A cmp ,dx
000000C17723 ja 0xe6
000000C37205 jc 0xca
000000C5394608 cmp ,ax
000000C8731C jnc 0xe6
000000CAB80102 mov ax,0x201
000000CDBB007C mov bx,0x7c00 /* 读进 0x7c00 */
000000D08B4E02 mov cx, /* 起始 cylinder,起始 sector */
000000D38B5600 mov dx, /* 起始 header */
000000D6CD13 int 0x13
000000D87351 jnc 0x12b /* return */
000000DA4F dec di
000000DB744E jz 0x12b
000000DD32E4 xor ah,ah
000000DF8A5600 mov dl,
000000E2CD13 int 0x13
000000E4EBE4 jmp short 0xca
000000E68A5600 mov dl,
000000E960 pushaw
000000EABBAA55 mov bx,0x55aa
000000EDB441 mov ah,0x41
000000EFCD13 int 0x13
000000F17236 jc 0x129
000000F381FB55AA cmp bx,0xaa55
000000F77530 jnz 0x129
000000F9F6C101 test cl,0x1
000000FC742B jz 0x129
000000FE61 popaw
000000FF60 pushaw
000001006A00 push byte +0x0
000001026A00 push byte +0x0
00000104FF760A push word
00000107FF7608 push word
0000010A6A00 push byte +0x0
0000010C68007C push word 0x7c00
0000010F6A01 push byte +0x1
000001116A10 push byte +0x10
00000113B442 mov ah,0x42
000001158BF4 mov si,sp
00000117CD13 int 0x13
0000011961 popaw
0000011A61 popaw
0000011B730E jnc 0x12b
0000011D4F dec di
0000011E740B jz 0x12b
0000012032E4 xor ah,ah
000001228A5600 mov dl,
00000125CD13 int 0x13
00000127EBD6 jmp short 0xff
0000012961 popaw
0000012AF9 stc
0000012BC3 ret
/********** 下面的区域是 mbr 常量符: mbr_str **************/
/*
char *mbr_str = "Invalid partition table."
"Error loading operation system."
"Missing operation system."
*/
0000012C496E7661 6C696420 70617274 6974696F
0000013C6E207461 626C6500 4572726F 72206C6F
0000014C6164696E 67206F70 65726174 696E6720
0000015C73797374 656D004D 69737369 6E67206F
0000016C70657261 74696E67 20737973 74656D
/********** 下面是空白区域 *****************/
0000017B00000000
0000017F00000000
0000018300000000
0000018700000000
0000018B00000000
0000018F00000000
0000019300000000
0000019700000000
0000019B00000000
0000019F00000000
000001A300000000
000001A700000000
000001AB00000000
000001AF00000000
000001B300000000
000001B400
/*** 下面这段是 MBR 用到的数据区:mbr_data ***/
000001B52C /* 指向 "Invalid partition table." */
000001B6 44 /* 指向 "Error loading operation system." */
000001B763 /* 指向 "Missing operation system." */
000001B8 61
000001B9 A2
000001BA61
000001BBA2
000001BC00
000001BD00
/* 1BE - 1FD = disk partion table */
/* 1BE - 1CD = DPT1 */
000001BE80 /* boot indicator */
/* 00:不可启动分区 */
/* 80:可启动分区(只可有1个启动分区)*/
000001BF01 /* 起始 header 号 */
000001C001 /* 起始 sector 号 */
000001C100 /* 起始 cylinder 号 */
000001C207 /* 系统属性 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)
... ...
*/
000001C3FE /* 结束 header 号 */
000001C4FF /* 结束 sector 号 */
000001C5FF /* 结束 cylinder 号 */
000001C63F000000 /* 此分区前的扇区总数 */
000001CAD9A63F01 /* 此分区的扇区总数 */
/* 1CE - 1DD = DPT2 */
000001CE00
000001CF00
000001D000
000001D100
000001D200
000001D300
000001D400
000001D500
000001D600000000
000001DA00000000
/* 1DE - 1ED = DPT3 */
000001DE00
000001DF00
000001E000
000001E100
000001E200
000001E300
000001E400
000001E500
000001E600000000
000001EA00000000
/* 1EE - 1FD = DPT4 */
000001EE00
000001EF00
000001F000
000001F100
000001F200
000001F300
000001F400
000001F500
000001F600000000
000001FA00000000
000001FE55AA /* MBR 标记 */ 整个 512 bytes 的 MBR 主要分三大部分:
1、0000h ~ 012Bh 是代码区域
2、012Ch ~ 01FDh 是数据区域
3、01FEh ~ 01FFh 是 2 bytes 的 MBR 标记 "0x55AA"
一、代码部分:主要又分 5 个部分
第1部分:
0000000033C0 xor ax,ax
000000028ED0 mov ss,ax
00000004BC007C mov sp,0x7c00
00000007FB sti
0000000850 push ax
0000000907 pop es
0000000A50 push ax
0000000B1F pop ds
0000000CFC cld
0000000DBE1B7C mov si,0x7c1b
00000010BF1B06 mov di,0x61b
0000001350 push ax
0000001457 push di
00000015B9E501 mov cx,0x1e5
00000018F3A4 rep movsb /* 将 1B ~ 1FF 复制到 0x061B */
0000001ACB retf /* 跳到 061B 处执行 */
-----------------------------------------------------------------------------
主要是设置环境:ds=ss=es=00,sp=0x7c00,将 sp 设 0x7c00 作为栈底,是与 0x7c00 代码区分割开。
接下来,将 MBR 中的 01Bh ~ 1FFh 区域复制到 061B ~ 7FFh 区域。然后跳到 0x061b 继续执行下面的代码。跳到 0x061b 处执行,实际上就是接着执行 MBR 中的 01Bh 开始的代码。
第 2 部分:
0000001BBDBE07 mov bp,0x7be /* DPT1 */
0000001EB104 mov cl,0x4
00000020386E00 cmp ,ch /* 测试 DPT1 是否为可启动分区 */
000000237C09 jl 0x2e /* DPT1 = 80h, 是就跳转到 0x2e */
000000257513 jnz 0x3a /* DPT1 != 80 && DPT1 != 0,即:出错 */
0000002783C510 add bp,byte +0x10
0000002AE2F4 loop 0x20
0000002CCD18 int 0x18
0000002E8BF5 mov si,bp
0000003083C610 add si,byte +0x10 /* next DPT,即:DPT2 */
0000003349 dec cx /* 判断下一个分区 */
000000347419 jz 0x4f
00000036382C cmp ,ch /* DPT2 */
0000003874F6 jz 0x30 /* DPT2 == 0, goto 0x30 */
/* 循环判断每个分区 */
/* 如果 DPT2 != 0,转到出错处理 */
---------------------------------------------------------------------------------------
0x061b 也就是接下面的 01bh 处的代码。
* 0x7be 实际上就是 MBR 中的 1BEh,这是第1个 DPT(Disk Partition Table)的数据起始地方。
在整个 MBR 代码中bp 都等于 0x7be(也即 1bEh)。
* mov cl, 4 是要对 4 个分区表进行检查。
* cmp , ch 是检查分区表 1是否为 80h 标志,若 DPT1 即不是 80h,也不是 00h,这样的结果是,打印出错信息,然后最终进入死循环。
* 如查 DPT1 是可启动分区,那么 MBR 还要检查其余的 3 个分区的合法性,其余 3 个分区必须是 00h 标志。
第 3 部分:
/*********** 下面这段是分区标志不符的出错处理 **************/
0000003AA0B507 mov al, /* 取 mbr 数据区: mbr_data */
0000003DB407 mov ah,0x7
0000003F8BF0 mov si,ax /* ax = 0x072c, 即:mbr_str 区域 */
print_msg: /* 打印信息,最终死循环 */
00000041AC lodsb
000000423C00 cmp al,0x0
0000004474FC jz 0x42
00000046BB0700 mov bx,0x7
00000049B40E mov ah,0xe
0000004BCD10 int 0x10
0000004DEBF2 jmp short 0x41
------------------------------------------------------------------------------------------
接下来的第3 部分,主要是检查了 4 个分区,发现都不合法后的处理例程。
下面的代码:
0000003AA0B507 mov al, /* 取 mbr 数据区: mbr_data */
0000003DB407 mov ah,0x7
0000003F8BF0 mov si,ax /* ax = 0x072c, 即:mbr_str 区域 */
* 0x7b5 也就是 MBR 中的 1b5,这个地方实际上是放着一个 string 指针。这个指针指向出错信息字符串。下面会讲到。
第 4 部分:
/*通过了每个分区检查后的后续处理 */
0000004F884E10 mov ,cl /* DPT2 = 0 */
00000052E84600 call word 0x9b /* int13_read_sector_to_mem() */
00000055732A jnc 0x81 /* succssed */
/* 磁盘参数失败后 */
00000057FE4610 inc byte /* DPT2++ */
0000005A807E040B cmp byte ,0xb /* 检查分区的 系统类型ID */
0000005E740B jz 0x6b
00000060807E040C cmp byte ,0xc
000000647405 jz 0x6b
00000066A0B607 mov al,
0000006975D2 jnz 0x3d /* 打印 "Error loading operation system"*/
0000006B80460206 add byte ,0x6
0000006F83460806 add word ,byte +0x6
0000007383560A00 adc word ,byte +0x0
00000077E82100 call word 0x9b /* int13_read_sector_to_mem() */
0000007A7305 jnc 0x81
0000007CA0B607 mov al,
0000007FEBBC jmp short 0x3d /* 打印 "Error loading operation system"*/
00000081813EFE7D55AA cmp word ,0xaa55 /* 检查 mbr 标记 0xaa55 */
00000087740B jz 0x94
00000089807E1000 cmp byte ,0x0
0000008D74C8 jz 0x57
0000008FA0B707 mov al,
00000092EBA9 jmp short 0x3d /* 打印 "Error loading operation system"*/
000000948BFC mov di,sp /* sp = 0x7c00 */
000000961E push ds
0000009757 push di
000000988BF5 mov si,bp
0000009ACB retf /* 回到 0x7c00 */
------------------------------------------------------------------------
这部分稍长一些,主要是通过了 4 个分区的检查后,进行的后续处理。包括失败后仍将打印出错信息,进入死循环。
下面代码:
00000052E84600 call word 0x9b /* int13_read_sector_to_mem() */
00000055732A jnc 0x81 /* succssed */
--------------------------------------------
调用 MBR 的读磁盘例程,最终,它使用 int13 /02h 号功能进行读入 memory 中。
并转到:
00000081813EFE7D55AA cmp word ,0xaa55 /* 检查 mbr 标记 0xaa55 */
00000087740B jz 0x94
----------------------------------
检查 MBR 的标记 0x55aa
最终:
000000948BFC mov di,sp /* sp = 0x7c00 */
000000961E push ds
0000009757 push di
000000988BF5 mov si,bp
0000009ACB 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 ***/
000001B52C /* 指向 "Invalid partition table." */
000001B6 44 /* 指向 "Error loading operation system." */
000001B763 /* 指向 "Missing operation system." */
000001B8 61
000001B9 A2
000001BA61
000001BBA2
000001BC00
000001BD00
-----------------------------------------------------------------------------
这相当于指针,或者说是索引,用来索引出错的字符串信息。
第2部分:
/*
char *mbr_str = "Invalid partition table."
"Error loading operation system."
"Missing operation system."
*/
0000012C496E7661 6C696420 70617274 6974696F
0000013C6E207461 626C6500 4572726F 72206C6F
0000014C6164696E 67206F70 65726174 696E6720
0000015C73797374 656D004D 69737369 6E67206F
0000016C70657261 74696E67 20737973 74656D
------------------------------------------------------------------------------
存放着出错信息字符串。
第3部分是最重要的 DPT:
/* 1BE - 1FD = disk partion table */
/* 1BE - 1CD = DPT1 */
000001BE80 /* boot indicator */
/* 00:不可启动分区 */
/* 80:可启动分区(只可有1个启动分区)*/
000001BF01 /* 起始 header 号 */
000001C001 /* 起始 sector 号 */
000001C100 /* 起始 cylinder 号 */
000001C207 /* 系统属性 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)
... ...
*/
000001C3FE /* 结束 header 号 */
000001C4FF /* 结束 sector 号 */
000001C5FF /* 结束 cylinder 号 */
000001C63F000000 /* 此分区前的扇区总数 */
000001CAD9A63F01 /* 此分区的扇区总数 */
/* 1CE - 1DD = DPT2 */
000001CE00
000001CF00
000001D000
000001D100
000001D200
000001D300
000001D400
000001D500
000001D600000000
000001DA00000000
/* 1DE - 1ED = DPT3 */
000001DE00
000001DF00
000001E000
000001E100
000001E200
000001E300
000001E400
000001E500
000001E600000000
000001EA00000000
/* 1EE - 1FD = DPT4 */
000001EE00
000001EF00
000001F000
000001F100
000001F200
000001F300
000001F400
000001F500
000001F600000000
000001FA00000000
-----------------------------------------------------------------------
在这个磁盘映象里,只使用了1个分区,故 DPT2~DPT4 是空白的。
* DPT1:可启动标志,只能是 00h 或 80h
* DPT1:这指示分区的系统文件类型,这里的 07 表示 NTFS 文件类型。
所有的具体的文件类型,可以在 linux 下使用 fdisk 工具查看。 整个 MBR 流程是:
INT19h (BIOS 自检后,int19 读 MBR 到 0x7c00)
|
|
|
V
0x7c00----> 自我复制到 0x061b ------+
|
|
|
--------------------------------------+
|
|
V failure
检查 4 个分区----->检查标志 0x55aa --------->死循环
|
|
|
------------------------+
|
|
V
bootsector 读进 0x7c00-----> 重新执行 0x7c00 原帖由 mik 于 2009-6-9 00:11 发表 http://linux.chinaunix.net/bbs/images/common/back.gif
这两天饶有兴趣地对 xp 的 MBR 详尽地分析了一番,当作是温故知新。若有不对,敬请指出
下面是摘自实际 Xp 的磁盘 image 里的 windows XP MBR。
------------------------------------------------------ ...
版主真是厉害
分析windows的MBR,
linux的MBR也是一样的吧。 汇编啊,先mark一下,等有毅力了再来学习 我觉得写这个mbr的时候应该不是汇编吧,你这个是反汇编的吧。
不过这样理解比较清楚。
顶 原帖由 emmoblin 于 2009-6-9 09:48 发表 http://linux.chinaunix.net/bbs/images/common/back.gif
我觉得写这个mbr的时候应该不是汇编吧,你这个是反汇编的吧。
不过这样理解比较清楚。
顶
MBR运行时只有BIOS中断可调用,而且MBR中存放代码的空间有限,只能用汇编。
页:
[1]