中国DOS联盟论坛

中国DOS联盟

-- 联合DOS 推动DOS 发展DOS --

联盟域名:www.cn-dos.net  论坛域名:www.cn-dos.net/forum
DOS,代表着自由开放与发展,我们努力起来,学习FreeDOS和Linux的自由开放与GNU精神,共同创造和发展美好的自由与GNU GPL世界吧!

游客:  注册 | 登录 | 命令行 | 会员 | 搜索 | 上传 | 帮助 »
中国DOS联盟论坛 » DOS疑难解答 & 问题讨论 (解答室) » 【转载】别人写的新版MBR反汇编分析
作者:
标题: 【转载】别人写的新版MBR反汇编分析 上一主题 | 下一主题
starsky
初级用户




积分 191
发帖 22
注册 2004-7-30
状态 离线
『楼 主』:  【转载】别人写的新版MBR反汇编分析


发信人: SeaPeak (登老和兮小浙大), 信区: AsmDos
标  题: mbr 反汇编分析
发信站: 飘渺水云间 (Sun Jul  4 15:55:51 2004), 转信

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; 主引导记录(MBR)的反汇编分析
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
MBR代码分析网上早就有了,但我找到的都是针对老版MBR的分析。这里所谓的
老版MBR,指的是早期的MBR,那时大容量硬盘还没有出现,MBR使用传统的
Int 13h接口访问硬盘。随着硬盘容量越来越大,传统的Int 13h已经无法完全
访问硬盘上所有扇区(Int 13h接口理论上可访问的最大硬盘容量约为8G)。因此,
扩展Int 13h规范出台以适应这种变化。MBR的代码也必须相应改动,必要时采
用扩展Int 13h来加载引导扇区。我称之为新版MBR。本篇分析的就是新版MBR。

MBR其实并不复杂,但要完全理解也需要一些底层的系统知识。code里的一些
技巧值得借鉴。

seapeak@88                                           转载时就保持完整
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


                ;
                ; 设置栈SS:SP = 0:7C00
                ;
0000:7C00       xor     ax, ax
0000:7C02       mov     ss, ax
0000:7C04       mov     sp, 7C00h
0000:7C07       sti
                ;
                ; DS = ES = 0
                ;
0000:7C08       push    ax
0000:7C09       pop     es
0000:7C0A       push    ax
0000:7C0B       pop     ds
                ;
                ; 将后面的代码复制到低端内存,为加载
                ; 活动分区的引导扇区腾出空间,因为引导
                ; 扇区也必须加载到0:7C00
                ;
0000:7C0C       cld
0000:7C0D       mov     si, 7C1Bh
0000:7C10       mov     di, 61Bh

0000:7C13       push    ax
0000:7C14       push    di
0000:7C15       mov     cx, 1E5h
0000:7C18       repe movsb
                ;
                ; 跳到低端内存的代码继续执行
                ;
0000:7C1A       retf

                ;
                ; 开始扫描分区表(Partition Table),寻找活动分区
                ;
0000:061B       mov bp, 7BEh            ; 600h+1BEh,分区表起始偏移为1BEh
0000:061E       mov cl, 4               ; 分区表中有4个分区表项

          loc_620:
0000:0620       cmp [bp+0], ch          ; 是活动分区吗?(此时ch中的值为0)
0000:0623       jl loc_62E              ; 活动分区的标志是80h,如果解释成有符号
数,则小于0
0000:0625       jnz loc_63A             ; 引导标志的合法值只能是0和80h,其它的值
则出错
0000:0627       add bp, 10h             ; 指向下一个表项(每一个表项的长度为10h字

节)
0000:062A       loop loc_620            ; 依次扫描所有分区表项
                ;
                ; 没有发现活动分区,无法启动OS,按照规范调用Int 18h
                ; 早期的BIOS的Int 18h中断服务程序就是启动ROM-Basic,
                ; 现在的BIOS一般是打印错误信息
                ;
0000:062C       int 18h

                ;
                ; 找到活动分区后,还要检查剩余分区的启动标志是否为0
                ; 不允许存在多个活动分区
                ;
          loc_62E:
0000:062E       mov si, bp

          loc_630:
0000:0630       add si, 10h             ; 下一个分区表项
0000:0633       dec cx
0000:0634       jz loc_64F              ; 所以剩余分区都扫描完
0000:0636       cmp [si], ch            ; 启动标志是否为0?
0000:0638       jz loc_630              ; 是则合法,检查下一分区


                ;
                ; 分区启动标志不合法,打印错误信息
                ; "Invalid partition table"
                ;
          loc_63A:
0000:063A       mov al, byte_7B5

          loc_63D:
0000:063D       mov ah, 7
0000:063F       mov si, ax

          loc_641:
0000:0641       lodsb
0000:0642
0000:0642 loc_642:
0000:0642       cmp al, 0
0000:0644       jz loc_642              ; 打印完错误信息后,进入死循环
0000:0646       mov bx, 7
0000:0649       mov ah, 0Eh
0000:064B       int 10h                 ; 调用Int10h显示一个字符
0000:064D       jmp short loc_641


                ;
                ; 开始加载活动分区的引导扇区
                ;
          loc_64F:
                ;
                ; 将一个标志的初始值清0。这个标志表示是否尝试过备份的引导扇区
                ; [bp+10h]的字节肯定是没用的空间
                ;
0000:064F       mov [bp+10h], cl
0000:0652       call sub_69B
0000:0655       jnb loc_681

          loc_657:
0000:0657       inc byte ptr [bp+10h]           ; 标志已经尝试过加载备份的引导扇

                ;
                ; 如果活动分区是FAT32分区,尝试加载备份的引导扇区
                ;
0000:065A       cmp byte ptr [bp+4], 0Bh        ;FAT32
0000:065E       jz loc_66B
0000:0660       cmp byte ptr [bp+4], 0Ch        ;FAT32(需用扩展Int 13h访问)

0000:0664       jz loc_66B
                ;
                ; 加载引导扇区失败,显示错误信息
                ; "Error loading operating system"
                ;
0000:0666       mov al, byte_7B6
0000:0669       jnz loc_63D

          loc_66B:
                ;
                ; FAT32的备份引导扇区号=引导扇区号+6
                ;
0000:066B       add byte ptr [bp+2], 6
0000:066F       add word ptr [bp+8], 6
0000:0673       adc word ptr [bp+0Ah], 0
0000:0677       call sub_69B
0000:067A       jnb loc_681
                ;
                ; 连备份的引导扇区也坏了,就没辙了!
                ;
0000:067C       mov al, byte_7B6
0000:067F       jmp short loc_63D


                ;
                ; 在把控制权交给引导扇区前,要先检查引导扇区的签名(signature)
                ; 防止把控制权交给已经损坏的引导扇区
                ;
0000:0681 loc_681:
0000:0681       cmp word ptr ds:[7DFEh], 0AA55h ;签名就是扇区最后的2个字节
0000:0687       jz loc_694
                ;
                ; 引导扇区损坏,则尝试用备份引导扇区
                ;
0000:0689       cmp byte ptr [bp+10h], 0        ;已经是备份的引导扇区?
0000:068D       jz loc_657
                ;
                ; 备份引导扇区也坏了,死翘翘
                ;
0000:068F       mov al, byte_7B7
0000:0692       jmp short loc_63D

                ;
                ; 交权给引导扇区,让它去完成OS的引导
                ;

0000:0694 loc_694:
0000:0694       mov di, sp              ; di = sp = 7C00h
0000:0696       push ds
0000:0697       push di
0000:0698       mov si, bp              ; 把活动分区表项指针传给引导扇区
0000:069A       retf                    ; 跳到0:7C00

                ;
                ; 读取引导扇区的子过程
                ;
          sub_69B proc near
0000:069B       mov di, 5               ; 磁盘I/O错允许重试次数为5次
                ;
                ; 取硬盘的磁道参数
                ;
0000:069E       mov dl, [bp+0]          ; 分区的启动标志其实就是硬盘号
0000:06A1       mov ah, 8
0000:06A3       int 13h
0000:06A5       jb loc_6CA              ; 如果取参数失败,认为BIOS肯定不支持扩展
Int 13h
                                        ; 只好用传统Int 13h
                ;

                ; 计算用传统Int 13h能访问的最大逻辑扇区号
                ; 计算公式为:(最大磁头号+1)*每道扇区数*(最大磁道号+1)
                ; 注意这个计算次序是有讲究的,因为(最大磁头号+1)*每道扇区数
                ; 的结果可以用16位寄存器就可以存放。如果先用磁道号来计算,
                ; 乘的结果就必须用两个寄存器来存放,导致第二步乘计算复杂化
                ;
0000:06A7       mov al, cl
0000:06A9       and al, 3Fh
0000:06AB       cbw                     ; ax中为第道扇区数
0000:06AC       mov bl, dh
0000:06AE       mov bh, ah              ; bh = 0,ah肯定为0
0000:06B0       inc bx
0000:06B1       mul bx                  ; (最大磁头号+1)*每道扇区数
0000:06B3       mov dx, cx
0000:06B5       xchg dl, dh
0000:06B7       mov cl, 6
0000:06B9       shr dh, cl              ; dx中为(最大磁道号+1)
0000:06BB       inc dx
0000:06BC       mul dx                  ; (最大磁头号+1)*每道扇区数*(最大磁道号
+1)
                ;
                ; 判断引导扇区是否可以用传统Int 13h来访问

                ; 如果引导扇区的逻辑扇区号 >= 刚才算出的扇区号,必须用扩展Int
13h来读取
                ; 否则就用传统Int 13h来访问
                ;
                ; 注意一下双字数的比较方法!
                ;
0000:06BE       cmp [bp+0Ah], dx
0000:06C1       ja loc_6E6
0000:06C3       jb loc_6CA
0000:06C5       cmp [bp+8], ax
0000:06C8       jnb loc_6E6
0000:06CA       ;
                ; 用传统Int 13h来读引导扇区
                ;
          loc_6CA:
0000:06CA       mov ax, 201h
0000:06CD       mov bx, 7C00h
0000:06D0       mov cx, [bp+2]
0000:06D3       mov dx, [bp+0]
0000:06D6       int 13h
0000:06D8       jnb locret_72B
                ;

                ; 读取失败可以重试,试完规定的次数后还失败就没办法了
                ;
0000:06DA       dec di
0000:06DB       jz locret_72B
                ;
                ; 重试前重置一下磁盘系统
                ;
0000:06DD       xor ah, ah
0000:06DF       mov dl, [bp+0]
0000:06E2       int 13h
0000:06E4       jmp short loc_6CA

                ;
                ; 检查BIOS是否支持扩展Int 13h
                ;
0000:06E6 loc_6E6:
0000:06E6       mov dl, [bp+0]
0000:06E9       pusha
0000:06EA       mov bx, 55AAh
0000:06ED       mov ah, 41h
0000:06EF       int 13h
0000:06F1       jb loc_729

0000:06F3       cmp bx, 0AA55h
0000:06F7       jnz loc_729
0000:06F9       test cl, 1              ;必须支持Fixed disk access这个功能子集
0000:06FC       jz loc_729
0000:06FE       popa
                ;
                ; 扩展Int 13h读扇区
                ;
0000:06FF loc_6FF:
0000:06FF       pusha
                ;
                ; 在栈中构造磁盘地址包(Disk Address Packet)
                ;
0000:0700       push 0
0000:0702       push 0
0000:0704       push word ptr [bp+0Ah]
0000:0707       push word ptr [bp+8]    ; 要读扇区的LBA地址(4个word)
0000:070A       push 0
0000:070C       push 7C00h              ; 引导扇区读到0:7C00h
0000:070F       push 1                  ; 读一个扇区
0000:0711       push 10h                ; 包长度16个字节
0000:0713       mov ah, 42h

0000:0715       mov si, sp
0000:0717       int 13h
0000:0719       popa                    ; 这里用了一个小技巧,一下子从栈中弹出8
个word
                                        ; (地址包刚好是8个word)
0000:071A       popa                    ; 这才是真正的恢复保存的通用寄存器的值
0000:071B       jnb locret_72B
0000:071D       dec di                  ; 不成功有重试的机会
                                        ; 注意这里也有个小技巧:dec指令不改变CF
的状态
0000:071E       jz locret_72B           ; 直到所有重试次数用完
                ;
                ; 重试前重置磁盘系统
                ;
0000:0720       xor ah, ah
0000:0722       mov dl, [bp+0]
0000:0725       int 13h
0000:0727       jmp short loc_6FF

          loc_729:
0000:0729       popa
0000:072A       stc


          locret_72B:
0000:072B       retn
          sub_69B endp

0000:072C db 'Invalid partition table',0
0000:0744 db 'Error loading operating system',0
0000:0763 db 'Missing operating system',0

0000:07B5 byte_7B5 db 2Ch
0000:07B6 byte_7B6 db 44h
0000:07B7 byte_7B7 db 63h

0000:07FE       dw 0AA55h               ;MBR的signature

--------------------------------------------------------------------------------
---------
References:
* Enhanced Disk Drive Specification Ver 3.0,
  http://www.phoenix.com/resources/specs-edd30.pdf.
* BIOS Boot Specification Version 1.01,
  http://www.phoenix.com/resources/specs-bbs101.pdf.

------------------------------End of
file------------------------------------------------
--

实迷途其未远,觉今是而昨非




2004-8-7 00:00
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
starsky
初级用户




积分 191
发帖 22
注册 2004-7-30
状态 离线
『第 2 楼』:  

文章最后引用的两篇文章挺好的 感觉 ^_^

2004-8-7 00:00
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
nre
银牌会员

nre


积分 1210
发帖 361
注册 2002-12-28
状态 离线
『第 3 楼』:  

支持!!




Teamwork !
2004-8-8 00:00
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复

请注意:您目前尚未注册或登录,请您注册登录以使用论坛的各项功能,例如发表和回复帖子等。


可打印版本 | 推荐给朋友 | 订阅主题 | 收藏主题



论坛跳转: