主引导记录(MBR)的反汇编分析

来源:互联网 发布:新开淘宝店怎么推广 编辑:程序博客网 时间:2024/05/18 03:28
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; 主引导记录(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
0 0
原创粉丝点击