冰琥珀 发表于 2015-4-23 00:52:09

[红盟杯]Windows操作系统学习之——MBR调试(二)

本帖最后由 冰琥珀 于 2015-9-20 16:39 编辑

##########################################
#Title    : Windows操作系统学习之——MBR调试(二)
#Time   :2015年04月23日
#Team:ihonker Team
#Author : 冰琥珀
#首发   :ihonker.org
#######################################
        [红盟杯]Windows操作系统学习之——MBR调试(一)
        其实这个帖子已经不算MBR的调试了,MBR调试在上面给的链接的那个帖子已经完成,这里属于DBR(分区引导记录的调试)。在开始之前,我们先来认识下DBR

        下面我们再来看下BPB和EBPB的相关介绍
BPB结构:
0x0b~0x0c:        每扇区字节数
0x0d:                每簇扇区数
0x0e~0x0f:        保留扇区数
0x10:                fat表数
0x11~0x12:        根目录项数(只有FAT12/FAT16使用此字段,FAT32此字段为0)
0x13~0x14:        小扇区数(只有FAT12/FAT16使用此字段,FAT32此字段为0)       
0x15:                媒体描述符(0xf8表示硬盘,0xf0表示高密度3.5寸软盘)
0x16~0x17:        每fat扇区数(只有FAT12/FAT16使用此字段,FAT32此字段为0)
0x18~0x19:        每磁道扇区数
0x1a~0x1b:        磁头数
0x1c~0x1f:        隐藏扇区数
0x20~0x23:        总扇区数
0x24~0x27:        每fat扇区数(只被fat32使用)
0x28~0x29:        fat表镜像标志,值为0表示系统保存2份互为备份的fat表,值为1表示系统仅保存1份fat表
0x2a~0x2b:        文件系统版本(只供fat32使用)
0x2c~0x2f:        根目录簇号(只供fat32使用)
0x30~0x31:        文件系统信息扇区号(只供fat32使用)
0x32~0x33:        备份引导扇区(只供fat32使用)
0x34~0x3f:        保留

EBPB结构:
0x40:                物理驱动器号
0x41:                保留
0x42:                拓展引导标签
0x43~0x46:        分区序号
0x47~0x51:        卷标
0x52~0x59:        系统ID
        接下来,我们开始调试DBR了。在上一个帖子里,我们调玩MBR之后,程序跳转到DBR去执行,而从上面DBR的介绍可知,在开始处是一个跳转指令
MEMORY:7C00               jmp   short near ptr unk_7C5A
        我们直接看7C5A处的代码
MEMORY:7C5A               xor   ax, ax
MEMORY:7C5C               mov   ds, ax
MEMORY:7C5E               assume ds:MEMORY
MEMORY:7C5E               mov   es, ax
MEMORY:7C60               assume es:MEMORY
MEMORY:7C60               mov   ss, ax
MEMORY:7C62               mov   bp, 7C00h
MEMORY:7C65               mov   sp, 7C00h
MEMORY:7C68               cmp   byte ptr , 0FFh ; 检测磁盘物理驱动号是否正确
MEMORY:7C6D               jnz   short loc_7C73; 判断分区文件系统是fat12/fat16还是fat32
MEMORY:7C6F               mov   , dl
MEMORY:7C73
MEMORY:7C73 loc_7C73:                               ; CODE XREF: MEMORY:7C6Dj
MEMORY:7C73               cmp   word ptr , 0 ; 判断分区文件系统是fat12/fat16还是fat32
MEMORY:7C78               jnz   short loc_7C89; 如果是fat12/fat16则跳转
MEMORY:7C7A               cmp   dword ptr , 0 ; 判断分区文件系统是fat12/fat16还是fat32
MEMORY:7C80               jnz   short loc_7C89; 如果是fat12/fat16则跳转
MEMORY:7C82               cmp   word ptr , 0
MEMORY:7C87               jbe   short loc_7C8C; 如果是fat32则跳转
MEMORY:7C89
MEMORY:7C89 loc_7C89:                               ; CODE XREF: MEMORY:7C78j
MEMORY:7C89                                       ; MEMORY:7C80j
MEMORY:7C89               jmp   loc_7D93
        这里先检测分区文件系统是fat12/fat16还是fat32,如果是fat12/fat16,则输出一些信息,我们就不看了,只看fat32的情况。
MEMORY:7C8C loc_7C8C:                               ; CODE XREF: MEMORY:7C87j
MEMORY:7C8C               mov   ax, 800h
MEMORY:7C8F               mov   dl,
MEMORY:7C93               int   13h             ; DISK - DISK - GET CURRENT DRIVE PARAMETERS (XT,AT,XT286,CONV,PS)
MEMORY:7C93                                       ; DL = drive number
MEMORY:7C93                                       ; Return: CF set on error, AH = status code, BL = drive type
MEMORY:7C93                                       ; DL = number of consecutive drives
MEMORY:7C93                                       ; DH = maximum value for head number, ES:DI -> drive parameter
MEMORY:7C95               jnb   short loc_7C9C
MEMORY:7C97               mov   cx, 0FFFFh
MEMORY:7C9A               mov   dh, cl
        在这里,用int 13h,ah=08h来读取磁盘参数,我们看看这种读取方式的介绍

        从上面的介绍可知,如果读取失败,则cf标志位置1,那么jnb   short loc_7C9C就不会执行。反之,cf标志位为0,jnb   short loc_7C9C会被执行。我们接下来看0x7c9c处的代码
MEMORY:7C9C loc_7C9C:                               ; CODE XREF: MEMORY:7C95j
MEMORY:7C9C               mov   bl, ch          ; ch存放的是柱面数的低8位(柱面数总共有10位,高2位来自于cl的高2位)
MEMORY:7C9E               mov   bh, cl          ; cl的低6位存放的是没磁道扇区数(高2位和ch组合来表示柱面数)
MEMORY:7CA0               shr   bh, 6         ; 这里把bh的值右移6位,那么bh中只剩下cl的高2位,然后和bl的8位一起表示柱面数,所以bx的值就是柱面数
MEMORY:7CA3               and   cl, 3Fh         ; 这里取的是cl的低6位的值
MEMORY:7CA6               movzx   eax, dh         ; dh存放的是磁头数
MEMORY:7CAA               movzx   ebx, bx
MEMORY:7CAE               movzx   ecx, cl
MEMORY:7CB2               inc   eax             ; 因为磁头数是从0开始计数,所以这里要+1
MEMORY:7CB4               inc   ebx             ; 柱面数也是从0开始计数,这里也要+1
MEMORY:7CB6               mul   ecx             ; 这里是磁头数*每磁道扇区数
MEMORY:7CB9               mul   ebx             ; 上面得到的结果*柱面数,得到的值其实就是这个分区的大小
MEMORY:7CBC               mov   dword_7DB4, eax
MEMORY:7CC0               mov   eax, 0Eh
MEMORY:7CC6               add   eax,                 ; 计算第二个引导扇区的绝对偏移
MEMORY:7CCB               mov   cx, 1
MEMORY:7CCE               xor   bx, bx
MEMORY:7CD0               mov   es, bx
MEMORY:7CD2               mov   bx, 7E00h
MEMORY:7CD5               call    loc_7CDB
MEMORY:7CD8               jmp   loc_7E00
        这里先读取磁盘参数,然后通过计算得出磁盘大小,然后计算第二引导扇区的偏移,接下来有个call,我们看这个call里面的代码
MEMORY:7CDB loc_7CDB:                               ; CODE XREF: MEMORY:7CD5p
MEMORY:7CDB               push    es
MEMORY:7CDC               cmp   eax, dword_7DB4
MEMORY:7CE1               jnb   short loc_7CFF
MEMORY:7CE3               pushad
MEMORY:7CE5               mov   ah, 41h ; 'A'
MEMORY:7CE7               mov   bx, 55AAh
MEMORY:7CEA               mov   dl,
MEMORY:7CEE               int   13h             ; DISK - Check for INT 13h Extensions
MEMORY:7CEE                                       ; BX = 55AAh, DL = drive number
MEMORY:7CEE                                       ; Return: CF set if not supported
MEMORY:7CEE                                       ; AH = extensions version
MEMORY:7CEE                                       ; BX = AA55h
MEMORY:7CEE                                       ; CX = Interface support bit map
        这段代码在上一个帖子有讲过,就是检测int 13h的拓展功能是否可用,如果可用,接下来就会用int 13h的拓展功能来读取扇区。代码如下
MEMORY:7CF0               jb      short loc_7D49; 拓展功能不可用则跳转
MEMORY:7CF2               cmp   bx, 0AA55h
MEMORY:7CF6               jnz   short loc_7D49
MEMORY:7CF8               test    cl, 1
MEMORY:7CFB               jz      short loc_7D49
MEMORY:7CFD               popad
MEMORY:7CFF
MEMORY:7CFF loc_7CFF:                               ; CODE XREF: MEMORY:7CE1j
MEMORY:7CFF                                       ; MEMORY:7D41j
MEMORY:7CFF               pushad
MEMORY:7D01               cmp   cx, 40h ; '@'
MEMORY:7D04               jbe   short loc_7D09
MEMORY:7D06               mov   cx, 40h ; '@'
MEMORY:7D09
MEMORY:7D09 loc_7D09:                               ; CODE XREF: MEMORY:7D04j
MEMORY:7D09               mov   word ptr dword_7D45, cx
MEMORY:7D0D               push    0
MEMORY:7D0F               push    0
MEMORY:7D11               push    eax
MEMORY:7D13               push    es
MEMORY:7D14               push    bx
MEMORY:7D15               push    cx
MEMORY:7D16               push    10h
MEMORY:7D18               mov   si, sp
MEMORY:7D1A               mov   dl,
MEMORY:7D1E               mov   ah, 42h ; 'B'
MEMORY:7D20               int   13h             ; DISK - IBM/MS Extension - EXTENDED READ (DL - drive, DS:SI - disk address packet)
MEMORY:7D22               jb      short loc_7D8B
MEMORY:7D24               add   sp, 10h
MEMORY:7D27               popad
MEMORY:7D29               push    bx
MEMORY:7D2A               mov   ebx, dword_7D45
MEMORY:7D2F               add   eax, ebx
MEMORY:7D32               shl   ebx, 5
MEMORY:7D36               mov   dx, es
MEMORY:7D38               add   dx, bx
MEMORY:7D3A               mov   es, dx
MEMORY:7D3C               pop   bx
MEMORY:7D3D               sub   cx, word ptr dword_7D45
MEMORY:7D41               jnz   short loc_7CFF
MEMORY:7D43               pop   es
MEMORY:7D44               retn
        这里读取的是第二启动扇区代码,存放的位置为0x7e00,然后进行一些读取结果的检测,如果读取正确,则函数返回。返回之后,程序跳转到0x7e00处去执行第二启动扇区的代码。
        在第二启动引导代码中,先获取根目录簇号,然后检测这个值是否正确,代码如下
MEMORY:7E00                                       ; MEMORY:7E5Bj ...
MEMORY:7E00               mov   eax,    ; 获取根目录簇号
MEMORY:7E05               cmp   eax, 0FFFFFF8h
MEMORY:7E0B               jb      short loc_7E10
        如果正确则跳转到0x7E10处,下面我们来看0x7E10处的代码
MEMORY:7E10 loc_7E10:                               ; CODE XREF: MEMORY:7E0Bj
MEMORY:7E10               mov   bx, 2000h
MEMORY:7E13               mov   es, bx
MEMORY:7E15               assume es:nothing
MEMORY:7E15               call    loc_7F3E
        这里设置了es的值,然后就调用一个call,我们进去看看这个call 的代码
MEMORY:7F3E               dec   eax
MEMORY:7F40               dec   eax
MEMORY:7F42               xor   edx, edx
MEMORY:7F45               movzx   ebx, byte ptr ; 获取每簇扇区数
MEMORY:7F4B               mul   ebx
MEMORY:7F4E               push    eax
MEMORY:7F50               xor   edx, edx
MEMORY:7F53               movzx   eax, byte ptr ; 获取fat表数
MEMORY:7F59               mul   dword ptr ; 用fat表数*每fat扇区数
MEMORY:7F5E               movzx   ebx, word ptr ; 获取保留扇区数
MEMORY:7F64               add   eax, ebx
MEMORY:7F67               add   eax,    ; 加上隐藏扇区数
MEMORY:7F6C               pop   ebx
MEMORY:7F6E               add   eax, ebx
MEMORY:7F71               xor   bx, bx
MEMORY:7F73               movzx   cx, byte ptr
MEMORY:7F78               call    sub_7CDB
MEMORY:7F7B               retn
        在这里面进行了一些计算,其实是计算fat32文件系统中数据区的偏移,然后就调用了call    sub_7CDB,这个call在前面有看到过,是一个读取扇区的call,这里其实是读取fat32文件系统的数据区数据,读取大小为一个簇,读取后存放位置为2000h:0000h。读取完之后,函数返回。接下来我们来看call    loc_7F3E之后的代码
MEMORY:7E18               xor   bx, bx
MEMORY:7E1A               mov   bl,     ; 获取每簇扇区数
MEMORY:7E1E               shl   bx, 4                        ;这里计算有多少个短目录项(每个短目录项占32个字节)
MEMORY:7E21               mov   ax, 2000h
MEMORY:7E24               mov   es, ax
MEMORY:7E26               xor   di, di
MEMORY:7E28               mov   si, 7FA3h
MEMORY:7E2B               mov   cx, 0Bh
MEMORY:7E2E               repe cmpsb
MEMORY:7E30               jz      short loc_7E5D
MEMORY:7E32
MEMORY:7E32 loc_7E32:                               ; CODE XREF: MEMORY:7DBEj
MEMORY:7E32               dec   bx
MEMORY:7E33
MEMORY:7E33 loc_7E33:                               ; CODE XREF: MEMORY:7DCDj
MEMORY:7E33               jnz   short loc_7E38
        这里其实是在数据区中查找出和0x7FA3处相等的字符串(FREELDR SYS),其实是在根目录中查找文件名为FREELDR.SYS的文件,如果找到就跳转到0x7E5D处去执行,否则跳转到0x7E38处执行。我们先看没找到的情况,即0x7E38处的代码
MEMORY:7E38 loc_7E38:                               ; CODE XREF: MEMORY:loc_7E33j
MEMORY:7E38                                       ; MEMORY:7E4Cj
MEMORY:7E38               mov   ax, es
MEMORY:7E3A               add   ax, 2               
MEMORY:7E3D               mov   es, ax
MEMORY:7E3F               assume es:nothing
MEMORY:7E3F
MEMORY:7E3F loc_7E3F:                               ; CODE XREF: MEMORY:7DCBj
MEMORY:7E3F               xor   di, di
MEMORY:7E41
MEMORY:7E41 loc_7E41:                               ; CODE XREF: MEMORY:7DDAj
MEMORY:7E41               mov   si, 7FA3h
MEMORY:7E44
MEMORY:7E44 loc_7E44:                               ; CODE XREF: MEMORY:7DD3j
MEMORY:7E44               mov   cx, 0Bh
MEMORY:7E47               repe cmpsb
MEMORY:7E49               jz      short loc_7E5D
MEMORY:7E4B               dec   bx
MEMORY:7E4C               jnz   short loc_7E38
        通过上面的代码可以看出是在循环查找那个文件名,接下来我们看找到的情况
MEMORY:7E5D loc_7E5D:                               ; CODE XREF: MEMORY:7E30j
MEMORY:7E5D                                       ; MEMORY:7E49j
MEMORY:7E5D               mov   si, 7FAEh
MEMORY:7E60
MEMORY:7E60 loc_7E60:                               ; CODE XREF: MEMORY:7DECj
MEMORY:7E60               call    sub_7DA5
        查找到了,si指向0x7FAE,这里有一个call,我们进去看看
MEMORY:7DA5 sub_7DA5      proc near               ; CODE XREF: sub_7CDB+B3p
MEMORY:7DA5                                       ; sub_7CDB+BBp ...
MEMORY:7DA5               lodsb                        ;从si中读取字符,存放到al中
MEMORY:7DA6               or      al, al
MEMORY:7DA8               jz      short locret_7DB3
MEMORY:7DAA               mov   ah, 0Eh
MEMORY:7DAC               mov   bx, 7
MEMORY:7DAF               int   10h             ; - VIDEO - WRITE CHARACTER AND ADVANCE CURSOR (TTY WRITE)
MEMORY:7DAF                                       ; AL = character, BH = display page (alpha modes)
MEMORY:7DAF                                       ; BL = foreground color (graphics modes)
MEMORY:7DB1               jmp   short sub_7DA5
MEMORY:7DB3 ; ---------------------------------------------------------------------------
MEMORY:7DB3
MEMORY:7DB3 locret_7DB3:                            ; CODE XREF: sub_7DA5+3j
MEMORY:7DB3               retn
MEMORY:7DB3 sub_7DA5      endp
        这个函数的功能其实就是把si指向的地址中存放的字符串显示到屏幕上。就是这个效果

        接下来就是对数据区数据的解析,先来看目录项的介绍(短文件名目录项)

        然后我们再来看接下来的代码
MEMORY:7E65 loc_7E65:                               ; CODE XREF: MEMORY:7DEFj
MEMORY:7E65               xor   dx, dx
MEMORY:7E67               mov   ax, es:                ;取出文件起始簇号的高两个字节
MEMORY:7E6B               shl   eax, 10h                       
MEMORY:7E6F               mov   ax, es:                ;取出文件起始簇号的低两个字节
MEMORY:7E73               cmp   eax, 2
MEMORY:7E77               jnb   short loc_7E7C
MEMORY:7E79               jmp   loc_7D93
        从上面的代码可以看出,这里是取出文件起始簇号的高两个字节和低两个字节,并将他们组成文件的起始簇号,然后用文件起始簇号来和2做比较,为啥要和2做比较,是因为所有的簇都是从2开始编号的。在这里,eax的值大于2,所以执行 jnb   short loc_7E7C指令,我们接下来看loc_7E7C处的代码
MEMORY:7E7C loc_7E7C:                               ; CODE XREF: MEMORY:7E77j
MEMORY:7E7C               cmp   eax, 0FFFFFF8h
MEMORY:7E82               jb      short loc_7E87
MEMORY:7E84               jmp   loc_7D93
        这里只判断文件所谓的簇号是否大于最大值,这里是小于,所以 执行jb      short loc_7E87,我们接下来看loc_7E87处的代码
MEMORY:7E87 loc_7E87:                               ; CODE XREF: MEMORY:7E82j
MEMORY:7E87               mov   bx, 0F80h
MEMORY:7E8A               mov   es, bx
MEMORY:7E8C               assume es:nothing
MEMORY:7E8C
MEMORY:7E8C loc_7E8C:                               ; CODE XREF: MEMORY:7EB3j
MEMORY:7E8C               cmp   eax, 0FFFFFF8h
MEMORY:7E92               jnb   short loc_7EB5
MEMORY:7E94               push    eax
MEMORY:7E96               xor   bx, bx
MEMORY:7E98               push    es
MEMORY:7E99               call    near ptr unk_7F3E
        这里修改了下es的值,然后调用一个call,我们进去看这个call干了些啥
MEMORY:7F3E               dec   eax
MEMORY:7F40               dec   eax             ; 这里是该簇的簇号-2
MEMORY:7F42               xor   edx, edx
MEMORY:7F45               movzx   ebx, byte ptr ; 获取每簇扇区数
MEMORY:7F4B               mul   ebx
MEMORY:7F4E               push    eax
MEMORY:7F50               xor   edx, edx
MEMORY:7F53               movzx   eax, byte ptr ; 获取fat表个数
MEMORY:7F59               mul   dword ptr ; fat表个数*每fat扇区数
MEMORY:7F5E               movzx   ebx, word ptr ; 获取保留扇区数
MEMORY:7F64               add   eax, ebx
MEMORY:7F67               add   eax,    ; 加上隐藏扇区数
MEMORY:7F6C               pop   ebx
MEMORY:7F6E               add   eax, ebx
MEMORY:7F71               xor   bx, bx
MEMORY:7F73               movzx   cx, byte ptr
MEMORY:7F78               call    sub_7CDB
MEMORY:7F7B               retn
        这段代码看着挺熟悉,上面的一大堆计算,其实可以总结成以下公式(这里计算的是绝对扇区号)
        某簇起始扇区号 = 隐藏扇区数 + 保留扇区数 + 每个FAT表大小扇区数 × FAT表个数 + (该簇簇号 - 2) × 每簇扇区数 
        然后读取该簇的数据到0F80h:0000h处(call    sub_7CDB)。我们接着看call    near ptr unk_7F3E之后的代码
MEMORY:7E9C               pop   es
MEMORY:7E9D               assume es:MEMORY
MEMORY:7E9D               xor   bx, bx
MEMORY:7E9F               mov   bl,
MEMORY:7EA3               shl   bx, 5
MEMORY:7EA6               mov   ax, es
MEMORY:7EA8               add   ax, bx          ; 这里其实是把es的值设置到刚才读取的那一簇数据之后
MEMORY:7EAA               mov   es, ax
MEMORY:7EAC               pop   eax
MEMORY:7EAE               push    es
MEMORY:7EAF               call    loc_7EC2
MEMORY:7EB2               pop   es
MEMORY:7EB3               jmp   short loc_7E8C
        上面重新设置了下es的值,其实是让它指向刚才读取的那一簇数据之后,然后又是一个call,我们看call    loc_7EC2内部的代码
MEMORY:7EC2 loc_7EC2:                               ; CODE XREF: MEMORY:7E53p
MEMORY:7EC2                                       ; MEMORY:7EAFp
MEMORY:7EC2               shl   eax, 2          ; 在fat中,每个fat表项占4个字节,且其数值与数据区的簇号相同
MEMORY:7EC6               mov   ecx, eax
MEMORY:7EC9               xor   edx, edx
MEMORY:7ECC               movzx   ebx, word ptr ; 获取每扇区字节数
MEMORY:7ED2               push    ebx
MEMORY:7ED4               div   ebx
MEMORY:7ED7               movzx   ebx, word ptr ; 获取保留扇区数
MEMORY:7EDD               add   eax, ebx
MEMORY:7EE0               mov   ebx,    ; 获取隐藏扇区数
MEMORY:7EE5               add   eax, ebx
MEMORY:7EE8               pop   ebx
MEMORY:7EEA               dec   ebx
MEMORY:7EEC               and   ecx, ebx
MEMORY:7EEF               movzx   ebx, word ptr ; 获取FAT表镜像标志
MEMORY:7EF5               and   bx, 0Fh         ; 值为0表示系统保存2份互为备份的FAT表,值为1表示系统仅保存1份FAT表
MEMORY:7EF8               jz      short loc_7F12
MEMORY:7EFA               cmp   bl,
MEMORY:7EFE               jb      short loc_7F03
MEMORY:7F00               jmp   loc_7D93
        上面这段代码其实就是计算出含有该簇号的fat表所在的扇区偏移。因为每个簇号在fat中占4个字节,所以簇号*4就得出该簇号在fat表中的偏移,然后除以扇区大小就可以得知该簇号相对于fat表的扇区偏移,再加上保留扇区和隐藏扇区,就可以计算出该簇号所在扇区的绝对偏移值。然后检测这个文件系统中有几个fat表,如果有两个,则跳到 short loc_7F12处。接下来我们看 short loc_7F12处的代码
MEMORY:7F03 loc_7F03:                               ; CODE XREF: MEMORY:7EFEj
MEMORY:7F03               push    eax
MEMORY:7F05               mov   eax,
MEMORY:7F0A               mul   ebx
MEMORY:7F0D               pop   edx
MEMORY:7F0F               add   eax, edx
MEMORY:7F12
MEMORY:7F12 loc_7F12:                               ; CODE XREF: MEMORY:7EF8j
MEMORY:7F12               push    ecx
MEMORY:7F14               mov   bx, 9000h
MEMORY:7F17               mov   es, bx
MEMORY:7F19               assume es:nothing
MEMORY:7F19               cmp   eax, dword_7F3A
MEMORY:7F1E               jz      short loc_7F2C
MEMORY:7F20               mov   dword_7F3A, eax
MEMORY:7F24               xor   bx, bx
MEMORY:7F26               mov   cx, 1
MEMORY:7F29               call    sub_7CDB
MEMORY:7F2C
MEMORY:7F2C loc_7F2C:                               ; CODE XREF: MEMORY:7F1Ej
MEMORY:7F2C               pop   ecx
MEMORY:7F2E               mov   eax, es:
MEMORY:7F33               and   eax, 0FFFFFFFh
MEMORY:7F39               retn
        这里则是读取该簇号所在的扇区数据,然后获取该簇号在fat中的值,如果一个文件占用几个簇,那么该簇号在fat中的值就是下一个簇的簇号,如果文件结束,则该簇号在fat表中的值为0x0fffffff。这个函数结束了之后程序又会跳回上面的loc_7E8C,判断文件是否结束,如果没有结束则继续读取数据,如果结束,则程序跳转去执行loc_7EB5的代码。
MEMORY:7EB5 loc_7EB5:                               ; CODE XREF: MEMORY:7E92j
MEMORY:7EB5               mov   dl,
MEMORY:7EB9               mov   dh, byte ptr loc_7DFD
MEMORY:7EBD               jmp   far ptr loc_F800
        上面这段代码获取磁盘的驱动器号,然后程序跳转到loc_F800去执行,其实loc_F800就是刚才读取的FREELDR.SYS文件的数据,这里程序去执行FREELDR.SYS文件的代码。
MEMORY:F800 loc_F800:                               ; CODE XREF: MEMORY:7EBDJ
MEMORY:F800                                       ; MEMORY:F853j
MEMORY:F800               jmp   loc_FA00
        在loc_F800中,只有一个跳转,我们接着去看loc_FA00处的代码
MEMORY:FA00 loc_FA00:                               ; CODE XREF: MEMORY:loc_F800j
MEMORY:FA00               cli
MEMORY:FA01               xor   ax, ax
MEMORY:FA03               mov   ds, ax
MEMORY:FA05               mov   es, ax
MEMORY:FA07               assume es:MEMORY
MEMORY:FA07               mov   fs, ax
MEMORY:FA09               mov   gs, ax
MEMORY:FA0B               mov   ss, ax
MEMORY:FA0D               mov   sp, word_FAAE
MEMORY:FA11               call    sub_FC16
        这里设置一些段寄存器之后,调用了一个call,我们进去看这个call 的代码
MEMORY:FC16 sub_FC16      proc near               ; CODE XREF: MEMORY:FA11p
MEMORY:FC16               pusha
MEMORY:FC17               call    sub_FC07
MEMORY:FC1A               mov   al, 0D1h ; '        ;告诉键盘控制器我们要写命令
MEMORY:FC1C               out   64h, al         ; 8042 keyboard controller command register.
MEMORY:FC1C                                       ; Write output port (next byte to port 60h):
MEMORY:FC1C                                       ; 7:1=keyboard data line pulled low (inhibited)
MEMORY:FC1C                                       ; 6:1=keyboard clock line pulled low (inhibited)
MEMORY:FC1C                                       ; 5:enables IRQ 12 interrupt on mouse IBF
MEMORY:FC1C                                       ; 4:enables IRQ 1 interrupt on keyboard IBF
MEMORY:FC1C                                       ; 3:1=mouse clock line pulled low (inhibited)
MEMORY:FC1C                                       ; 2:1=mouse data line pulled low (inhibited)
MEMORY:FC1C                                       ; 1:A20 gate on/off
MEMORY:FC1C                                       ; 0:reset the PC (THIS BIT SHOULD ALWAYS BE SET TO 1)
MEMORY:FC1E               call    sub_FC07
MEMORY:FC21               mov   al, 0DFh ; '        ;告诉键盘控制器我们要开启A20
MEMORY:FC23               out   60h, al         ; 8042 keyboard controller data register.
MEMORY:FC25               call    sub_FC07
MEMORY:FC28               popa
MEMORY:FC29               retn
MEMORY:FC29 sub_FC16      endp
        这段代码的功能其实就是开启A20地址线,call    sub_FC07这个函数其实是等待8042的Inputbuffer为空,我们看看它的代码
MEMORY:FC07 sub_FC07      proc near               ; CODE XREF: sub_FC07+Cj
MEMORY:FC07                                       ; sub_FC16+1p ...
MEMORY:FC07               jmp   short $+2
MEMORY:FC09 ; ---------------------------------------------------------------------------
MEMORY:FC09
MEMORY:FC09 loc_FC09:                               ; CODE XREF: sub_FC07j
MEMORY:FC09               jmp   short $+2
MEMORY:FC0B ; ---------------------------------------------------------------------------
MEMORY:FC0B
MEMORY:FC0B loc_FC0B:                               ; CODE XREF: sub_FC07:loc_FC09j
MEMORY:FC0B               in      al, 64h         ; 8042 keyboard controller status register
MEMORY:FC0B                                       ; 7:PERR    1=parity error in data received from keyboard
MEMORY:FC0B                                       ;    +----------- AT Mode ----------+------------ PS/2 Mode ------------+
MEMORY:FC0B                                       ; 6: |RxTO    receive (Rx) timeout| TO      general timeout (Rx or Tx)|
MEMORY:FC0B                                       ; 5: |TxTO    transmit (Tx) timeout | MOBF    mouse output buffer full|
MEMORY:FC0B                                       ;    +------------------------------+-----------------------------------+
MEMORY:FC0B                                       ; 4:INH   0=keyboard communications inhibited
MEMORY:FC0B                                       ; 3:A2      0=60h was the port last written to, 1=64h was last
MEMORY:FC0B                                       ; 2:SYS   distinguishes reset types: 0=cold reboot, 1=warm reboot
MEMORY:FC0B                                       ; 1:IBF   1=input buffer full (keyboard can't accept data)
MEMORY:FC0B                                       ; 0:OBF   1=output buffer full (data from keyboard is available)
MEMORY:FC0D               cmp   al, 0FFh
MEMORY:FC0F               jz      short locret_FC15
MEMORY:FC11               test    al, 2
MEMORY:FC13               jnz   short sub_FC07
MEMORY:FC15
MEMORY:FC15 locret_FC15:                            ; CODE XREF: sub_FC07+8j
MEMORY:FC15               retn
MEMORY:FC15 sub_FC07      endp
        具体的就不在这里赘述,大家可以自己去百度下关于A20地址线的相关资料。开启了A20之后,我们接着看程序又干了些啥
MEMORY:FA14               mov   dword_6F00, 0FA41h
MEMORY:FA1D               mov   ax, 1000h
MEMORY:FA20               mov   es, ax
MEMORY:FA22               assume es:nothing
MEMORY:FA22               mov   eax, es:3Ch
MEMORY:FA27               add   eax, 18h
MEMORY:FA2B               mov   eax, es:
MEMORY:FA31               add   eax, 10000h
MEMORY:FA37               mov   dword_FA9B, eax
MEMORY:FA3B               xor   ax, ax
MEMORY:FA3D               mov   es, ax
MEMORY:FA3F               assume es:MEMORY
MEMORY:FA3F               jmp   short loc_FA7C
        这里则是从内存中读取一个数值,然后保存在dword_FA9B里,至于这个数值干啥用,我们接着看
MEMORY:FA7C loc_FA7C:                               ; CODE XREF: MEMORY:FA3Fj
MEMORY:FA7C               cli
MEMORY:FA7D               mov   word_FAAE, sp
MEMORY:FA81               lgdt    dword ptr byte_FAD8
MEMORY:FA86               mov   eax, cr0
MEMORY:FA89               or      eax, 1
MEMORY:FA8D               mov   cr0, eax
        上面这段代码先是将byte_FAD8加载到GDT中,然后开启保护模式。保护模式是否开启是由cr0的第0位控制的,为1表示开启保护模式,为0表示不开启。
        经过几天的调试,我们总算把前半部分的内容分析出来了,后面还有一些内容,找时间分析之后,再开一些帖子分享出来,不然篇幅太长了。

gscsd 发表于 2015-4-23 22:55:03

看得也好累....

ayang 发表于 2015-6-27 19:39:59

支持,看起来不错呢!

a136 发表于 2015-6-27 20:32:47

支持,看起来不错呢!

HUC-参谋长 发表于 2015-6-28 10:29:36

感谢楼主的分享~

云游者 发表于 2015-6-28 22:55:24

支持,看起来不错呢!

Micah 发表于 2015-6-30 00:28:57

学习学习技术,加油!

a136 发表于 2015-6-30 07:16:42

还是不错的哦,顶了

小路 发表于 2015-6-30 12:03:20

学习学习技术,加油!

wilist 发表于 2015-6-30 20:47:28

学习学习技术,加油!
页: [1]
查看完整版本: [红盟杯]Windows操作系统学习之——MBR调试(二)