百度空间 | 百度首页 
 
查看文章
 
[转]比较详细的MBR的分析
2008-07-18 16:07

版权说明:本文为网上收集,转载时请注明原作者及保留原始链接

说明:硬盘主引导记录独立于操作系统,但又和操作系统息息相关——很多时候它又是由

; 操作系统所提供的工具所生成(例外的情况是您使用了其他的分区工具,不过它又运行在

; 什么操作系统中呢?;()。

;

; 如果您安装了Windows 98(我现在暂时不能接触95下的主引导记录,总不能用95重装我的

; 系统吧?)操作系统,那您机器上的主引导记录已经与以前的大有不同了,通过下面的分析

; 您一定能对Windows 98为什么要更改主引导记录有所了解——它已经开始支持扩展Int13h

; 了!并且这个主引导记录的编程技巧更是我们应该学习的。

;

; 主引导记录包括代码、数据两部分。它在被BIOS中断Int19h装入内存后获得控制权。数据

; 部分最重要的当然是分区表了!彻底熟悉主引导记录,可以帮助我们了解系统的引导过程,

; 处理因主引导记录损坏所造成的无法引导故障,消除引导型计算机病毒,更使我们能通过

; 修改主引导记录完成我们希望的工作:如多重引导,系统加软锁等...

;

; BIOS中断总是把主引导记录所在扇区(硬盘的0头0道1扇区)的内容(包括代码和数据)

; 装入内存0000:7C00起始的区域,然后检验该扇区内容的最后两个字节是不是“AA55”,

; 如果不是,那么对不起,Int19h将不把控制权交给主引导记录;若是,则下面的主引导记录

; 才能获得了控制权了(Int19通过跳转指令交转控制权):

; 反汇编结果

;

; 0000:7C00~0000:7C1A:初始化各个段寄存器、堆栈指针,最后将主引导记录在内存中搬家,腾出其所占内

; 存空间以供装入分区引导记录。

0000:7C00 33C0        XOR     AX,AX          ;AX寄存器清0

0000:7C02 8ED0        MOV     SS,AX          ;SS=0

0000:7C04 BC007C      MOV     SP,7C00        ;装填栈指针——SS:SP=0000:7C00

0000:7C07 FB          STI                   ;开中断(装填栈指针时为避免硬件中断引起栈混乱应关中断)

0000:7C08 50          PUSH    AX             ;

0000:7C09 07          POP     ES             ;装填附加数据段寄存器ES=0

0000:7C0A 50          PUSH    AX             ;

0000:7C0B 1F          POP     DS             ;装填数据段寄存器DS=0

0000:7C0C FC          CLD                   ;规定其后的串操作为正向串操作

0000:7C0D BE1B7C      MOV     SI,7C1B        ;源指针

0000:7C10 BF1B06      MOV     DI,061B        ;目的指针

0000:7C13 50          PUSH    AX             ;

0000:7C14 57          PUSH    DI             ;看看0000:7C1A——构造一个跳转

0000:7C15 B9E501      MOV     CX,01E5        ;

0000:7C18 F3          REPZ                  ;

0000:7C19 A4          MOVSB                 ;0000:7C1B起始的CX字节传送至0000:061B起始的区域

0000:7C1A CB          RETF                  ;跳转到0000:061B(这是一种技巧跳转)

;

; 为直观起见,下面的地址按实际运行时的地址给出。

; 0000:061B~0000:062B:对分区表进行初步检验,一旦检测到某分区表项状态字节大于等于80h,就通过(当

; 然,在此之前如果检测到某项分区表的状态字节小于80h,就转错误处理。当然,如果四个分区项的状态字节

; 都为零,主引导记录就会调用BIOS-ROM的INT 18h,显示"PRESS A KEY TO REBOOT"信息等待你的操作。

0000:061B BEBE07      MOV     SI,07BE        ;SI指向第一个分区表项,这时CX=0

0000:061E B104        MOV     CL,04          ;分区表共四个表项

0000:0620 382C        CMP     [SI],CH        ;

0000:0622 7C09        JL      062D           ;大于等于80h转[注意JL指令:(SF xor OF)=1则转]

0000:0624 7515        JNZ     063B           ;不为0则[SI]一定小于80h,只能转错误处理了!

0000:0626 83C610      ADD     SI,+10         ;为零则检查下一表项

0000:0629 E2F5        LOOP    0620           ;检查下一表项

0000:062B CD18        INT     18             ;四表项的状态字节都为0,则系统只好调用INT 18h了!

;

; 0000:062D~0000:0639:检查剩余的分区表项——状态字节必须为零,否则显示错误信息“分区表无效”然

; 后当机!拜托,微软搞错没有,怎么用中文提示信息?真TM傻得可爱!

; 这里还有个小BUG,前面放行原则是只要状态字节大于等于80h,那么如果这个字节是诸如A0h、E5h之类数值

; 呢?嘿嘿,这个引导记录统统认为是有效的可引导分区了!

0000:062D 8B14        MOV     DX,[SI]        ;为读分区引导记录做准备:磁头号→DH,驱动器号→DL

0000:062F 8BEE        MOV     BP,SI          ;SI→BP,保存可引导分区表项的指针

;

0000:0631 83C610      ADD     SI,+10         ;其余的分区表项还要检查检查的

0000:0634 49          DEC     CX             ;

0000:0635 7416        JZ      064D           ;CX=0则检查顺利通过,转继续

0000:0637 382C        CMP     [SI],CH        ;

0000:0639 74F6        JZ      0631           ;为零,是合法表项,再查下一表项

;

; 0000:063B~0000:064B:执行错误处理——报告错误信息后当机

0000:063B BE1007      MOV     SI,0710        ;错误信息字符串偏移+1→SI

0000:063E 4E          DEC     SI             ;SI-1→SI

0000:063F AC          LODSB                 ;SI+1→SI

0000:0640 3C00        CMP     AL,00          ;

0000:0642 74FA        JZ      063E           ;AL=0则表明一条错误信息显示完毕,系统陷入一个死循环

0000:0644 BB0700      MOV     BX,0007        ;字符方式显示

0000:0647 B40E        MOV     AH,0E          ;

0000:0649 CD10        INT     10             ;以写电传方式显示信息(只显示一个字符)

0000:064B EBF2        JMP     063F           ;显示下一个字符,直到遇到提示信息结束为止

;

; 0000:064D~0000:0662:判断可引导分区的分区类型,然后转相应处理程序。

0000:064D 894625      MOV     [BP+25],AX     ;BP=指向第一个可引导分区表项的指针,这时AX=0000h

                                          ;使用长度最短的指令将[BP+25]起始的两个单元清零

                                          ;这两个单元将被用来存放中间变量

0000:0650 96          XCHG    SI,AX          ;此时SI清零的最佳指令选择(仅1字节),将服务于0000:06B8

0000:0651 8A4604      MOV     AL,[BP+04]     ;取分区类型(本例是“06”喽——FAT16主DOS分区)

0000:0654 B406        MOV     AH,06          ;为扩展INT 13h无法使用做好更改分区类型的准备

0000:0656 3C0E        CMP     AL,0E          ;0Eh:需要用扩展INT 13h访问的FAT16主DOS分区

0000:0658 7411        JZ      066B           ;0Eh类型的分区转066Bh

0000:065A B40B        MOV     AH,0B          ;

0000:065C 3C0C        CMP     AL,0C          ;0Ch:需要用扩展INT 13h访问的FAT32分区

0000:065E 7405        JZ      0665           ;0Ch类型的分区转0665h先行预处理

0000:0660 3AC4        CMP     AL,AH          ;0Bh:用传统INT 13h就可以访问的FAT32分区

0000:0662 752B        JNZ     068F           ;其他类型的分区转068Fh

;

; 0000:0664~0000:06A1:根据分区类型和分区表表项内容进行读取分区引导记录前的处理工作

0000:0664 40          INC     AX             ;★★★0Bh类型的分区由此开始处理,此条指令用意是清ZF位

0000:0665 C6462506    MOV     BYTE PTR [BP+25],06 ;★★★0Ch类型的分区由此开始处理

                                          ;为什么取值06,一时没有自圆我说的解释,请耐心几天吧。

0000:0669 7524        JNZ     068F           ;请注意上面指令对ZF位的影响:0Bh类型分区转,0Ch则不转

; 0000:066B~0000:068C这段代码仅当分区类型是0Ch、0Eh才有获得执行的机会

0000:066B BBAA55      MOV     BX,55AA        ;★★★0Eh类型的分区由此开始处理

0000:066E 50          PUSH    AX             ;

0000:066F B441        MOV     AH,41          ;扩展INT 13h功能,检测BIOS是否已经支持扩展INT13h

0000:0671 CD13        INT     13             ;入口参数:BX=55AAh,DL=驱动器号,AH=41h

0000:0673 58          POP     AX             ;执行完恢复AX为060Eh

0000:0674 7216        JB      068C           ;不支持则转

0000:0676 81FB55AA    CMP     BX,AA55        ;

0000:067A 7510        JNZ     068C           ;扩展INT13h不可用也转

0000:067C F6C101      TEST    CL,01          ;测试扩展盘访问是否被支持

0000:067F 740B        JZ      068C           ;不支持还转

; 因为扩展INT13h方式读盘与标准INT13h方式读盘有很大差别,所以0000:0686处指令修改其后的代码以保证按

; 照扩展读方式读分区引导扇区时能正确跳转到相应的处理程序中。

0000:0681 8AE0        MOV     AH,AL          ;分区类型→AH

0000:0683 885624      MOV     [BP+24],DL     ;保存驱动器号→[BP+24]

0000:0686 C706A106EB1E MOV     WORD PTR [06A1],1EEB ;修改0000:06A1处代码为"JMP 06C1"

0000:068C 886604      MOV     [BP+04],AH     ;注意:如果扩展INT13h不能使用则A改分区类型为06,但如果

                                          ;扩展INT13h能使用,则仍保持原分区类型不变

0000:068F BF0A00      MOV     DI,000A        ;★★★其它类型分区由此开始处理。此条指令初始化计数器

0000:0692 B80102      MOV     AX,0201        ;AH:读操作,AL:读取1个扇区的内容

0000:0695 8BDC        MOV     BX,SP          ;SP=7C00→BX,指定分区引导记录装入内存的位置偏移

0000:0697 33C9        XOR     CX,CX          ;CX清零

0000:0699 83FF05      CMP     DI,+05         ;注意5

0000:069C 7F03        JG      06A1           ;大于则转去读由分区表指定的分区引导扇区

0000:069E 8B4E25      MOV     CX,[BP+25]     ;小于则证明所读分区表指定的引导扇区无合法的引导记录,

                                          ;改按???再读,毕竟多一种选择多一次机会嘛!;)

; 以下标有①②者请注意它们的地址都是一样的,就是说实际运行中只可能是二者之一,但为了分析之方便,我

; 把两者都列了出来以供对比,阅读时千万别看成是两条指令了啊!

①0000:06A1 034E02      ADD     CX,[BP+02]     ;获取分区引导扇区所在的柱面号和物理扇区号

②0000:06A1 EB1E        JMP     06C1           ;如果分区类型是0Ch、0Eh而且扩展读能使用则执行该指令

;

; 0000:06A4:将可引导分区的分区引导记录装入内存指定区域

; 入口参数:AH=功能号,02为读盘操作;AL=一次读取的扇区数

;           ES:BX=读入内存的起始地址

;           CH=10位柱面号的低8位;CL:高两位是10位柱面号的高两位,低6位是物理扇区号

;           DH=磁头号;DL=驱动器号,最高位(即位7)为0是软盘,为1是硬盘

0000:06A4 CD13        INT     13             ;读分区引导记录到0000:7C00起始的区域

;

;

0000:06A6 7229        JB      06D1           ;不成功转

0000:06A8 BE2D07      MOV     SI,072D        ;错误信息字符串偏移→SI

0000:06AB 813EFE7D55AA CMP     WORD PTR [7DFE],AA55 ;分区引导记录合法吗?

0000:06B1 745A        JZ      070D           ;合法则转(这是主引导记录唯一的正常出口)

0000:06B3 83EF05      SUB     DI,+05         ;不合法则为换读其他扇区做准备

0000:06B6 7FDA        JG      0692           ;只有一次换读扇区的机会!

;

; 0000:06B8~0000:06BF:错误预处理

0000:06B8 85F6        TEST    SI,SI          ;测试SI值是否为0,其意义在于确定该显示哪条信息

0000:06BA 7583        JNZ     063F           ;不为0则转错误处理,显示“Missing operating system”

0000:06BC BE1A07      MOV     SI,071A        ;错误信息字符串偏移→SI

0000:06BF EB8A        JMP     064B           ;转错误处理,显示“加载操作系统时出错”

;

; 0000:06C1~0000:06CF:整理扩展读所需入口参数,然后调用扩展读子程序

; 这段代码只有在以扩展读方式读取分区引导记录时才有机会获得执行

0000:06C1 98          CBW                   ;转换字节AL为字AX,执行后,AX中是一次要读的扇区数

0000:06C2 91          XCHG    CX,AX          ;AX→CX,CX→AX,执行后,CX中是一次要读的扇区数

0000:06C3 52          PUSH    DX             ;

0000:06C4 99          CWD                   ;将字AX转换为双字→DX,AX

0000:06C5 034608      ADD     AX,[BP+08]     ;

0000:06C8 13560A      ADC     DX,[BP+0A]     ;执行后,DX:AX=LBA绝对物理扇区号

0000:06CB E81200      CALL    06E0           ;调用扩展读子程序

0000:06CE 5A          POP     DX             ;

0000:06CF EBD5        JMP     06A6           ;

;

; 0000:06D1~0000:06D8分区引导记录装入失败时的处理

0000:06D1 4F          DEC     DI             ;计数器减1

0000:06D2 74E4        JZ      06B8           ;五次读盘均未成功则转错误处理(注意这时SI=0)

0000:06D4 33C0        XOR     AX,AX          ;置功能号

0000:06D6 CD13        INT     13             ;复位磁盘系统

0000:06D8 EBB8        JMP     0692           ;再读

;

;

0000:06DA 00 00 80 49 12 00 ...I..

;

; 0000:06E0~0000:070C:使用扩展INT 13h功能读取分区引导记录的子程序

; 调用时,SP=7BFE。这段程序利用压栈寄存器方式构造了一个磁盘地址包,请注意体会。另外,0000:06FC处

; 的一条指令就释放了几乎全部由本段程序占用的栈空间,构思之巧妙,绝对需要我们学习!

; 所以,分析该段程序,一个重点应放在栈的变化上。

0000:06E0 56          PUSH    SI             ;保存SI——注意,这次压栈并不构造磁盘地址包

0000:06E1 33F6        XOR     SI,SI          ;清零

0000:06E3 56          PUSH    SI             ;

0000:06E4 56          PUSH    SI             ;

0000:06E5 52          PUSH    DX             ;

0000:06E6 50          PUSH    AX             ;以上四条指令压栈的是扇区LBA号码*2

0000:06E7 06          PUSH    ES             ;压栈内存目标缓冲区首址段址

0000:06E8 53          PUSH    BX             ;压栈内存目标缓冲区首址偏移

0000:06E9 51          PUSH    CX             ;压栈所读扇区数

0000:06EA BE1000      MOV     SI,0010        ;注意SI的高8位对应着磁盘地址包的保留字节,必须为0

0000:06ED 56          PUSH    SI             ;压栈磁盘地址包包长,执行完本条指令一个包已经构造完毕

0000:06EE 8BF4        MOV     SI,SP          ;规定磁盘地址包偏移指针,这时SP=7BEA

0000:06F0 50          PUSH    AX             ;保存AX

0000:06F1 52          PUSH    DX             ;保存DX

0000:06F2 B80042      MOV     AX,4200        ;置扩展读功能号

0000:06F5 8A5624      MOV     DL,[BP+24]     ;取驱动器号,参照0000:0683

; 入口参数:AH=功能号,02为读盘操作;DL=驱动器号

;           DS:SI=16字节磁盘地址包——第0字节:包长度(固定为10h);第1字节:保留,必须为0;

;           第2、3字节:所读扇区数;第4~5字节:内存目标缓冲区首址偏移;

;           第6~7字节:内存目标缓冲区首址段址; 第8~15字节:扇区LBA号码

; 出口参数:成功则AH=0;错误则AH=错误代码

0000:06F8 CD13        INT     13             ;执行扩展读操作

0000:06FA 5A          POP     DX             ;

0000:06FB 58          POP     AX             ;

0000:06FC 8D6410      LEA     SP,[SI+10]     ;7BEA+10h=7BFA→SP(注意是取偏移而不是取单元内容)

0000:06FF 720A        JB      070B           ;扩展读不成功转

0000:0701 40          INC     AX             ;

0000:0702 7501        JNZ     0705           ;

0000:0704 42          INC     DX             ;AX加1溢出时(比如0FFFFh+1)DX才加1

0000:0705 80C702      ADD     BH,02          ;调整BX,使偏移量增加512字节(刚好一扇区)

0000:0708 E2F7        LOOP    0701           ;0701~0708一段代码暂未明白其真实意图!

0000:070A F8          CLC                   ;

0000:070B 5E          POP     SI             ;

0000:070C C3          RET                   ;

;

; 0000:070D:中继跳转

0000:070D EB74        JMP     0783           ;

;

; 070F~0745是错误信息!果然是中文Windows98生成的主引导记录,所以我要特别

; “感谢”微软这个傻B,真难为它竟然用中文表述前两个信息!可惜真需显示的时

; 候鬼才能看懂是什么呢!!!我K!——耍弄我们耶!?

; 070F~0718:“分区表无效”中文信息

; 071A~072B:“加载操作系统时出错”中文信息

; 072D~0744:“Missing operating system”英文信息

0000:070F B7 .

0000:0710 D6 C7 F8 B1 ED CE DE D0-A7 00 BC D3 D4 D8 B2 D9 ................

0000:0720 D7 F7 CF B5 CD B3 CA B1-B3 F6 B4 ED 00 4D 69 73 .............Mis

0000:0730 73 69 6E 67 20 6F 70 65-72 61 74 69 6E 67 20 73 sing operating s

0000:0740 79 73 74 65 6D 00 00 00-00 00 00 00 00 00 00 00 system..........

0000:0750 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

0000:0760 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

0000:0770 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

0000:0780 00 00 00 ...

;

; 0000:0783~0000:0789:控制权移交

0000:0783 8BFC        MOV     DI,SP          ;

0000:0785 1E          PUSH    DS             ;

0000:0786 57          PUSH    DI             ;构造一个跳转地址

0000:0787 8BF5        MOV     SI,BP          ;

0000:0789 CB          RETF                  ;交控制权给分区引导记录(0000:7C00)

;

;

0000:078A 00 00 00 00 00 00 ......

0000:0790 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

0000:07A0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

;

; 07B8~07BB四个字节的内容用于什么呢?(不同机器此四字节均不同)

; 07BE~07FD为分区表,内含四个分区表项(每表项10h字节)

0000:07B0 00 00 00 00 00 00 00 00-86 D8 00 00 00 00 80 01 ................

0000:07C0 01 00 06 3F 3F FD 3F 00-00 00 41 A0 0F 00 00 00 ...??.?...A.....

0000:07D0 01 FE 05 3F FF FE 80 A0-0F 00 C0 4F 2F 00 00 00 ...?.......O/...

0000:07E0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

0000:07F0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 55 AA ..............U.

*1:因为物理扇区号总是从1排列而起

*2:由此可见,就是使用LBA扩展读的功能,主引导记录却限制了分区引导扇区必须在LBA绝对物理扇区

     0FFFFFFFFh之前才有可能从该分区引导系统!


类别:默认分类 | 添加到搜藏 | 浏览() | 评论 (0)
 
最近读者:
 
网友评论:
发表评论:
姓 名:
网址或邮箱: (选填)
内 容:
验证码: 请点击后输入四位验证码,字母不区分大小写
      

     

©2009 Baidu