windows xp MBR结构分析
1、系统通电启动-->BIOS启动代码进行加电自检,包括显卡,内存,主板等-->根据用户指定的启动顺序。
从指定设备加载MBR(第一个扇区,0磁头0柱面1扇区)到内存地址0x7c00处。
2、用winhex软件打开磁盘,内容0x00-0x200总共512个字节为MBR。
0x0000-0x01BD, 446字节,引导代码和数据区域
0x01BE-0x01FD, 64字节,4个分区表,每个分区表占16个字节
0x01FE-0x01FF, 2字节,MBR结构标志,值为0xAA55
3、分区表结构(16字节):
0x1BE,1bytes; =0x00: 不可启动分区,=0x80:可启动分区
0x1BF-0x1C1, 3bytes; 0x1BF,分区起始磁头号
0x1C0-0xC01,分区起始扇区和柱面号,0x1C0低6位为起始扇区,0x1C0高2位加上0xC01组成10位为起始柱面号
0x1C2, 1bytest; =0x07,分区文件系统类型,07为ntfs,0x0B为FAT32,0x83为Linux等
0x1C3-0x1C5, 3bytes; 分区结束磁头号,结束扇区,结束柱面号,定义同前
0x1C6-0x1C9, 4bytes; 分区前扇区数,即此分区的起始扇区号
0x1CA-0x1CD,4bytes; 分区大小,即总扇区数
4、winxp mbr反汇编代码分析
利用工具ndisasmw生成MBR反汇编代码,命令
ndisasmw -o 0x7c00 mbr.bin >> dismbr.asm
4.1:第一步,MBR代码拷贝。(0x7c1b到0x61b)
00007C00 33C0 xor ax,ax ;ax=0 00007C02 8ED0 mov ss,ax ;ss=0 00007C04 BC007C mov sp,0x7c00 ;sp=0x7c00 00007C07 FB sti ;开中断 00007C08 50 push ax 00007C09 07 pop es ;es=0 00007C0A 50 push ax 00007C0B 1F pop ds ;ds=0 00007C0C FC cld ;CLD是使得si,di传送方向从低地址到高地址增长 00007C0D BE1B7C mov si,0x7c1b ;si=0x7c1b 00007C10 BF1B06 mov di,0x61b ;di=0x61b 00007C13 50 push ax 00007C14 57 push di 00007C15 B9E501 mov cx,0x1e5 ;200h-1bh=1e5,cx=485个字节拷贝 00007C18 F3A4 rep movsb ;[ds:si]=[0:0x7c1b], [es:di] =[0:0x61b],拷贝0x7c1b地址以上的485个字节的内容到0x61b内存地址中 00007C1A CB retf ;ip=0x61b,cs=0,跳转到内存地址0x61b处执行,即后面的代码
4.2:第二步,MBR查找分区表信息,找到启动分区表以后,读取第一个扇区内容,并跳转至启动分区执行相关代码。
00007C1B BDBE07 mov bp,0x7be ;bp=0x7be 4个分区表的开始地址 00007C1E B104 mov cl,0x4 ;cl=4 最多有4个分区表 00007C20 386E00 cmp [bp+0x0],ch ;判断分区表的第一个字节是否为0x80,和0比较 00007C23 7C09 jl 0x7c2e ;jl小于(有符号),0x80有符号是-128,小于0,成功表示找到启动分区,失败是普通分区 00007C25 7513 jnz 0x7c3a ;不等于0,跳转,显示分区表无效 00007C27 83C510 add bp,byte +0x10 ;bp指向下一个分区表 00007C2A E2F4 loop 0x7c20 ;cl不等于0,继续循环 00007C2C CD18 int 0x18 ;ROM BASIC中断 00007C2E 8BF5 mov si,bp ;si=0x7be 00007C30 83C610 add si,byte +0x10 ;si=0x7ce,下一个分区表 00007C33 49 dec cx ;cx减1 00007C34 7419 jz 0x7c4f ;cx=0,如果4个表项都检查完毕就跳转 00007C36 382C cmp [si],ch ;检查分区指示符 00007C38 74F6 jz 0x7c30 ;如果分区指示符是0就跳转,否则分区表是无效的 00007C3A A0B507 mov al,[0x7b5] ;0x1b5偏移地址处为2c,0x12c文件偏移地址处指向字符串"Invalid partition table" 00007C3D B407 mov ah,0x7 00007C3F 8BF0 mov si,ax ;si指向字符串 00007C41 AC lodsb ;读取一个字节到al 00007C42 3C00 cmp al,0x0 ;字符串是否显示完成 00007C44 74FC jz 0x7c42 ;如果是就跳转(跳转到上面那条指令,系统陷入死循环),否则就调用10h号中断显示字符 00007C46 BB0700 mov bx,0x7 00007C49 B40E mov ah,0xe 00007C4B CD10 int 0x10 ;显示字符 00007C4D EBF2 jmp short 0x7c41 00007C4F 884E10 mov [bp+0x10],cl ;cl=0,bp=0x7be 00007C52 E84600 call word 0x7c9b ;读取启动分区的第一个扇区(512字节)信息到0x7c00 00007C55 732A jnc 0x7c81 ;加载成功跳转 00007C57 FE4610 inc byte [bp+0x10] 00007C5A 807E040B cmp byte [bp+0x4],0xb ;0bh:用传统INT 13h就可以访问的FAT32分区 00007C5E 740B jz 0x7c6b 00007C60 807E040C cmp byte [bp+0x4],0xc ;0ch:需要用扩展INT 13h访问的FAT32分区 00007C64 7405 jz 0x7c6b 00007C66 A0B607 mov al,[0x7b6] ;0x1b6偏移地址处为0x44,0x144文件偏移地址处指向字符串"Error loading operating system" 00007C69 75D2 jnz 0x7c3d ;错误信息显示出来(显示完后,系统进入死循环) 00007C6B 80460206 add byte [bp+0x2],0x6 00007C6F 83460806 add word [bp+0x8],byte +0x6 00007C73 83560A00 adc word [bp+0xa],byte +0x0 00007C77 E82100 call word 0x7c9b 00007C7A 7305 jnc 0x7c81 00007C7C A0B607 mov al,[0x7b6] 00007C7F EBBC jmp short 0x7c3d 00007C81 813EFE7D55AA cmp word [0x7dfe],0xaa55 ;检查启动分区的头个扇区是不是0xaa55结尾 00007C87 740B jz 0x7c94 ;如果是,以0xaa55结尾就跳转 00007C89 807E1000 cmp byte [bp+0x10],0x0 00007C8D 74C8 jz 0x7c57 00007C8F A0B707 mov al,[0x7b7] ;0x1b7偏移地址处为0x63,0x163文件偏移地址处指向字符串"Missing operating system" 00007C92 EBA9 jmp short 0x7c3d ;错误信息显示出来(显示完后,系统进入死循环) 00007C94 8BFC mov di,sp 00007C96 1E push ds 00007C97 57 push di 00007C98 8BF5 mov si,bp 00007C9A CB retf ;代码回到0x7c00,0x7c00是启动分区的第一个扇区拷贝的代码,MBR引导代码结束 00007C9B BF0500 mov di,0x5 ;di=5,最多读取启动分区第一个扇区5次,如果5次都失败了,提示载入系统失败 00007C9E 8A5600 mov dl,[bp+0x0] ;dl=80H(00H~7FH:软盘;80H~0FFH:硬盘) 00007CA1 B408 mov ah,0x8 ;ah=0x8 08h表示读取驱动器参数 00007CA3 CD13 int 0x13 ;ah=08,int 13h 读取驱动器参数,是为了决定用CHS方式还是LBA方式读取磁盘数据 00007CA5 7223 jc 0x7cca ;jc跳转,CF=1,操作失败,跳转,采用CHS方式 00007CA7 8AC1 mov al,cl ;ch=柱面数的低8位 cl的位7~6=柱面数的高2位 CL的位5~0=扇区数 00007CA9 243F and al,0x3f ;获取扇区数 00007CAB 98 cbw 00007CAC 8ADE mov bl,dh ;磁头数 00007CAE 8AFC mov bh,ah 00007CB0 43 inc bx 00007CB1 F7E3 mul bx 00007CB3 8BD1 mov dx,cx 00007CB5 86D6 xchg dl,dh 00007CB7 B106 mov cl,0x6 00007CB9 D2EE shr dh,cl 00007CBB 42 inc dx ;dx柱面数 00007CBC F7E2 mul dx 00007CBE 39560A cmp [bp+0xa],dx ;分区前已用的扇区数(高2字节) 00007CC1 7723 ja 0x7ce6 ;超过了CHS访问方式所能表示的最大扇区数就采用LBA方式读取磁盘 00007CC3 7205 jc 0x7cca ;比CHS访问方式所能表示的最大扇区数小就采用CHS方式读取磁盘,否则的话[bp+0xa]与dx相等,继续判断 00007CC5 394608 cmp [bp+0x8],ax ;分区前已用的扇区数(低2字节) 00007CC8 731C jnc 0x7ce6 00007CCA B80102 mov ax,0x201 ;读取启动分区第一个扇区的数据,CHS方式读取,ah=2(功能读),al=1(一个扇区),int 13h读一个扇区 00007CCD BB007C mov bx,0x7c00 ;存储读取数据的内存地址0x7c00,相当于buffer 00007CD0 8B4E02 mov cx,[bp+0x2] ;从哪个sector扇区开始读,其中低6位是扇区,高2位是柱面 00007CD3 8B5600 mov dx,[bp+0x0] ;dl:硬盘,dh:从哪个磁头开始读 00007CD6 CD13 int 0x13 00007CD8 7351 jnc 0x7d2b ;CF=0就跳转(CF为0代表操作成功) 00007CDA 4F dec di 00007CDB 744E jz 0x7d2b ;操作失败 00007CDD 32E4 xor ah,ah ;ah=0,磁盘系统复位 00007CDF 8A5600 mov dl,[bp+0x0] ;要复位的磁盘驱动器号 00007CE2 CD13 int 0x13 00007CE4 EBE4 jmp short 0x7cca ;再次读取 00007CE6 8A5600 mov dl,[bp+0x0] ;LBA方式读取磁盘,先判断是否支持LBA方式访问磁盘 00007CE9 60 pushaw ;寄存器组压栈 00007CEA BBAA55 mov bx,0x55aa 00007CED B441 mov ah,0x41 ;检测BIOS是否已经支持扩展INT 13h功能 00007CEF CD13 int 0x13 ;bx=0x55aa,dl=驱动器号,ah=0x41 00007CF1 7236 jc 0x7d29 ;不支持跳转 00007CF3 81FB55AA cmp bx,0xaa55 00007CF7 7530 jnz 0x7d29 ;扩展INT 13h不可用也转 00007CF9 F6C101 test cl,0x1 ;测试扩展盘访问是否被支持 00007CFC 742B jz 0x7d29 ;不支持跳转 00007CFE 61 popaw ;寄存器组弹栈 00007CFF 60 pushaw ;LAB方式访问磁盘 00007D00 6A00 push byte +0x0 00007D02 6A00 push byte +0x0 00007D04 FF760A push word [bp+0xa] ;启动分区前已用的扇区数(高2字节) 00007D07 FF7608 push word [bp+0x8] ;启动区前已用的扇区数(低2字节) 00007D0A 6A00 push byte +0x0 ;存储数据目标缓冲区首址段址 00007D0C 68007C push word 0x7c00 ;存储数据目标缓冲区首址偏移 00007D0F 6A01 push byte +0x1 ;扇区数1 00007D11 6A10 push byte +0x10 ;包长度 00007D13 B442 mov ah,0x42 ;置扩展读功能号,以LBA方式读取 00007D15 8BF4 mov si,sp 00007D17 CD13 int 0x13 ;读取数据 00007D19 61 popaw 00007D1A 61 popaw 00007D1B 730E jnc 0x7d2b ;CF=0跳转,说明读取成功 00007D1D 4F dec di 00007D1E 740B jz 0x7d2b ;5次都没读取成功,CF=1 00007D20 32E4 xor ah,ah ;ah=0,磁盘系统复位 00007D22 8A5600 mov dl,[bp+0x0] ;复位的驱动器号 00007D25 CD13 int 0x13 00007D27 EBD6 jmp short 0x7cff 00007D29 61 popaw 00007D2A F9 stc ;设置CF=1 00007D2B C3 ret ;返回 后面指令略...
5. MBR的作用是检测分区表,找到启动分区,读取其中第一个扇区的指令代码,返回到0x7c00执行。