12558网页游戏私服论坛

 找回密码
 立即注册
游戏开服表 申请开服
游戏名称 游戏描述 开服状态 游戏福利 运营商 游戏链接
攻城掠地-仿官 全新玩法,觉醒武将,觉醒技能 每周新区 经典复古版本,长久稳定 进入游戏
巅峰新版攻 攻城掠地公益服 攻城掠地SF 新兵种、新武将(兵种) 进入游戏
攻城掠地公 散人玩家的天堂 新开 进入游戏
改版攻城掠 上线即可国战PK 稳定新区 全新改版,功能强大 进入游戏
少年江山 高福利高爆率 刚开一秒 江湖水落潜蛟龙 进入游戏
太古封魔录 开服送10亿钻石 福利多多 不用充钱也可升级 进入游戏
神魔之道 签到送元宝 稳定开新区 送豪华签到奖励 进入游戏
神奇三国 统帅三军,招揽名将 免费玩新区 激情国战,征战四方 进入游戏
龙符 三日豪礼领到爽 天天开新区 助你征战无双 进入游戏
王者之师 免费领豪华奖励 免费玩新区 6元送6888元宝 进入游戏
查看: 477|回复: 0

Windows操作系统学习之——启动引导过程调试(一)

[复制链接]

282

主题

282

帖子

574

积分

实习版主

Rank: 7Rank: 7Rank: 7

积分
574
发表于 2019-8-20 10:50:25 | 显示全部楼层 |阅读模式
关于MBR的调试,论坛里也有好几篇帖子了,这个帖子也只是把我的学习过程分享出来,如果可以,我会从MBR开始,一步一步的去调试,去学习Windows操作系统,同时也把这个过程分享出来。闲话不多说了,开始进入主题。

    相关帖子链接:http://www.52pojie.cn/thread-173889-1-1.html

    一、MBR调试
    目前用到的工具:
    虚拟机:VMware
    系统:ReactOS.0.3.15(安装win7 32位或者XP系统也可以用这个方法调试,这里选择ReactOS是为了后面的调试做准备)
    调试工具:IDA    首先设置虚拟机。在VMware创建的系统文件夹下找到.vmx文件,用记事本打开,添加如下配置信息
[Asm] 纯文本查看 复制代码debugStub.listen.guest32 = "TRUE"debugStub.hideBreakpoints = "TRUE"bios.bootDelay = "3000"
    然后设置IDA。打开IDA,Debugger-->Attach-->Remote GDB debugger,在弹出的对话框进行如下设置

    启动虚拟机后,再点击IDA弹出的对话框的"OK"按钮,选择第一个进程,点"OK",如下图

    进入调试窗口后,转到0x7c00处,按"F2"下断点,然后按"F9"运行程序,当程序断下来之后,按"Alt+s",选择16位编码,这时反汇编可能会变成一堆数据,我们只要将其选中(446个字节),然后按“C”,选择“Force”,将数据强行转换成代码即可。

    接下来就开始我们的调试了,先看下面的代码
[Asm] 纯文本查看 复制代码MEMORY:7C00 loc_7C00:                               ; CODE XREF: MEMORY:loc_7CAEJMEMORY:7C00                 cliMEMORY:7C01                 cldMEMORY:7C02                 xor     ax, axMEMORY:7C04                 mov     ss, axMEMORY:7C06                 mov     ds, axMEMORY:7C08                 mov     bp, 7C00hMEMORY:7C0B                 lea     sp, [bp-20h]MEMORY:7C0E                 stiMEMORY:7C0F                 mov     ax, 1FE0hMEMORY:7C12                 mov     es, axMEMORY:7C14                 assume es:nothingMEMORY:7C14                 mov     si, bpMEMORY:7C16                 mov     di, bpMEMORY:7C18                 mov     cx, 100hMEMORY:7C1B                 rep movsw               ; 把MBR移动到1FE0h:7C00h处MEMORY:7C1D                 jmp     far ptr 1FE0h:7C22h
    这段代码很简单,就是把MBR拷贝到1FE0h:7C00h处,然后跳转到1FE0h:7C22h继续执行。接下来是在分区表中查找活动分区,看代码
[Asm] 纯文本查看 复制代码MEMORY:27A22 loc_27A22:                              ; CODE XREF: MEMORY:7C1DJMEMORY:27A22                 mov     ds, axMEMORY:27A24                 assume ds:MEMORYMEMORY:27A24                 mov     ss, axMEMORY:27A26                 assume ss:MEMORYMEMORY:27A26                 xor     ax, axMEMORY:27A28                 mov     es, axMEMORY:27A2A                 lea     di, [bp+1BEh]   ; 获取分区表地址MEMORY:27A2E                 test    byte ptr [di], 80h ; 是否是活动分区MEMORY:27A31                 jnz     short loc_7AA0MEMORY:27A33                 add     di, 10h         ; 每个分区表项大小为16个字节MEMORY:27A36                 cmp     di, 7DFEh       ; 分区表搜索是否结束MEMORY:27A3A                 jb      short loc_7A2E
    这里需要对MBR有所了解才行。MBR是磁盘的第一个扇区,占512个字节(每个扇区都是512个字节)。前446个字节是引导代码,接下来的64个字节是分区表,共四个表项,最后两个字节是结束标志0xAA55。分区表每个表项16个字节,第一个字节是分区标记,表示这个分区是不是活动分区(0x80为活动分区,否则为0)。上面这段代码就是检测每个分区表项的第一个字节是不是0x80,如果是就跳转。我们接下来看跳转过去的代码
[Asm] 纯文本查看 复制代码EMORY:27AA0                 call    loc_7AB3MEMORY:27AA3                 jb      short loc_7A5BMEMORY:27AA5                 cmp     es:word_7DFE, 0AA55hMEMORY:27AAC                 jnz     short loc_7A7FMEMORY:27AAE                 jmp     far ptr loc_7C00
    跳转过来就是一个call,我们跟进去看看。
[Asm] 纯文本查看 复制代码27AB3                 mov     bx, 55AAhMEMORY:27AB6                 mov     ah, 41h ; 'A'MEMORY:27AB8                 int     13h             ; DISK - Check for INT 13h ExtensionsMEMORY:27AB8                                         ; BX = 55AAh, DL = drive numberMEMORY:27AB8                                         ; Return: CF set if not supportedMEMORY:27AB8                                         ; AH = extensions versionMEMORY:27AB8                                         ; BX = AA55hMEMORY:27AB8                                         ; CX = Interface support bit mapMEMORY:27ABA                 jb      short loc_7AEEMEMORY:27ABC                 cmp     bx, 0AA55hMEMORY:27AC0                 jnz     short loc_7AEEMEMORY:27AC2                 test    cl, 1MEMORY:27AC5                 jz      short loc_7AEEMEMORY:27AC7                 jmp     short loc_7AD9
    这里其实是检测int 13h的拓展功能可不可以用,如果可用,则跳转到1FE0h:7AD9h处,否则跳转到1FE0h:7AEEh处。我们先来看1FE0h:7AEEh处的代码
[Asm] 纯文本查看 复制代码MEMORY:27AEE                 mov     ax, 204hMEMORY:27AF1                 mov     bx, 7C00hMEMORY:27AF4                 mov     cx, [di+2]     ;di为分区表首地址MEMORY:27AF7                 mov     dh, [di+1]MEMORY:27AFA                 int     13h             ; DISK - READ SECTORS INTO MEMORYMEMORY:27AFA                                         ; AL = number of sectors to read, CH = track, CL = sectorMEMORY:27AFA                                         ; DH = head, DL = drive, ES:BX -> buffer to fillMEMORY:27AFA                                         ; Return: CF set on error, AH = status, AL = number of sectors readMEMORY:27AFC                 retn
    这里其实是使用了int 13h来读取扇区数据(不是拓展功能),先来看看介绍:
int 13h,ah=02h 读扇区说明:
调用此功能将从磁盘上把一个或更多的扇区内容读进存贮器。因为这是一个
低级功能,在一个操作中读取的全部扇区必须在同一条磁道上(磁头号和磁道号
相同)。BIOS不能自动地从一条磁道末尾切换到另一条磁道开始,因此用户必须
把跨多条磁道的读操作分为若干条单磁道读操作。
入口参数:
AH=02H 指明调用读扇区功能。
AL 置要读的扇区数目,不允许使用读磁道末端以外的数值,也不允许
使该寄存器为0。
DL 需要进行读操作的驱动器号。
DH 所读磁盘的磁头号。
CH 磁道号的低8位数。
CL 低5位放入所读起始扇区号,位7-6表示磁道号的高2位。
ES:BX 读出数据的缓冲区地址。
返回参数:
如果CF=1,AX中存放出错状态。读出后的数据在ES:BX区域依次排列。
详情请参见磁盘错误状态返回码一文。
    由此可知,上面的代码是读取4个扇区的数据到1FE0h:7C00h处,读取的偏移由分区表的起始CHS确定。接下来我们来看1FE0h:7AD9h处的代码
[Asm] 纯文本查看 复制代码MEMORY:27AC9                 db  10hMEMORY:27ACA                 db    0MEMORY:27ACB                 db    4MEMORY:27ACC                 db    0MEMORY:27ACD                 db    0MEMORY:27ACE                 db  7Ch ; |MEMORY:27ACF                 db    0MEMORY:27AD0                 db    0MEMORY:27AD1 word_27AD1      dw 0                    ; DATA XREF: MEMORY:7CDCwMEMORY:27AD3 word_27AD3      dw 0                    ; DATA XREF: MEMORY:loc_7CE2wMEMORY:27AD5                 db    0MEMORY:27AD6                 db    0MEMORY:27AD7                 db    0MEMORY:27AD8                 db    0MEMORY:27AD9 ; ---------------------------------------------------------------------------MEMORY:27AD9                 mov     ax, [di+8]MEMORY:27ADC                 mov     word_7CD1, axMEMORY:27ADF                 mov     ax, [di+0Ah]MEMORY:27AE2                 mov     word_7CD3, axMEMORY:27AE5                 mov     ax, 4200hMEMORY:27AE8                 mov     si, 7CC9hMEMORY:27AEB                 int     13h             ; DISK - IBM/MS Extension - EXTENDED READ (DL - drive, DS:SI - disk address packet)MEMORY:27AED                 retn
    这里其实也是读取扇区数据,不过使用的是int 13h的拓展功能来读取。我们先来了解下int 13h的拓展功能怎么读取数据
入口:
AH = 42h
DL = 驱动器号
DS:SI = 磁盘地址数据包(Disk Address Packet)

返回:
CF = 0,AH = 0 成功
CF = 1,AH = 错误码

    这里涉及到一个结构体,我们先看这个结构体:
struct DAP{
        BYTE        PacketSize;                //数据包尺寸,固定为0x10
        BYTE        Reserved;                //保留
        WORD        BlockCount;                //要传输的扇区数
        WORD        BufferOffset;        //传输缓冲区偏移地址
        WORD        BufferSegment;        //传输缓冲区段地址
        DWORD        LBNLow;                //要读取数据的起始扇区号低位
        DWORD        LBNHigh;                //要读取数据的起始扇区号高位
};

    这个结构体就是上面MEMORY:27AC9开始的数据,在读取的时候,把这个结构体的地址传给si,然后调用int 13h来读取。上面这两段代码其实读取的是活动分区的引导扇区数据(每个分区的第一个扇区都分区引导扇区,这里要和MBR区分开来)。读完之后,程序反回继续前面的call下面的代码
[Asm] 纯文本查看 复制代码MEMORY:27AA3                 jb      short loc_7A5BMEMORY:27AA5                 cmp     es:word_7DFE, 0AA55hMEMORY:27AAC                 jnz     short loc_7A7FMEMORY:27AAE                 jmp     far ptr loc_7C00
      这里其实是检测分区引导扇区是否正确读取,如果正确读取则跳转去执行分区引导扇区的代码(这里是jmp far ptr loc_7C00)。
      二、PBR调试
     我们先来认识下PBR


    下面我们再来看下BPB和EBPB的相关介绍BPB结构:
0x0b~0x0c:        每扇区字节数
0x0d:                每簇扇区数3 k9 I7 E0 p" x2 E+ A" V
0x0e~0x0f:        保留扇区数
0x10:                fat表数$ u5 |& A- X9 G# \
0x11~0x12:        根目录项数(只有FAT12/FAT16使用此字段,FAT32此字段为0)  L+ v: W( R  o; d3 g5 R9 u8 F
0x13~0x14:        小扇区数(只有FAT12/FAT16使用此字段,FAT32此字段为0)        
0x15:                媒体描述符(0xf8表示硬盘,0xf0表示高密度3.5寸软盘)
0x16~0x17:        每fat扇区数(只有FAT12/FAT16使用此字段,FAT32此字段为0)
0x18~0x19:        每磁道扇区数
0x1a~0x1b:        磁头数
0x1c~0x1f:        隐藏扇区数) n. U' v+ x( l8 y8 m* s
0x20~0x23:        总扇区数
0x24~0x27:        每fat扇区数(只被fat32使用)) }" o) I# B0 k% ^# @( _. S
0x28~0x29:        fat表镜像标志,值为0表示系统保存2份互为备份的fat表,值为1表示系统仅保存1份fat表
0x2a~0x2b:        文件系统版本(只供fat32使用)8 C6 A1 j% [4 C* e3 w: K
0x2c~0x2f:        根目录簇号(只供fat32使用)
0x30~0x31:        文件系统信息扇区号(只供fat32使用)$ p0 {7 [1 d# J! W7 G6 L8 Z* ~9 g
0x32~0x33:        备份引导扇区(只供fat32使用)
0x34~0x3f:        保留+ U; h: s) w6 \, n8 ^$ E' p
7 T# K, n3 K4 _' C' J
EBPB结构:
0x40:                物理驱动器号
0x41:                保留
0x42:                拓展引导标签
0x43~0x46:        分区序号
0x47~0x51:        卷标% g" e+ S% v" g# _! l) k
0x52~0x59:        系统ID% Q, z6 e! D4 x
    接下来,我们开始调试PBR了。在上一个帖子里,我们调玩MBR之后,程序跳转到PBR去执行,而从上面PBR的介绍可知,在开始处是一个跳转指令
[Asm] 纯文本查看 复制代码MEMORY:7C00                 jmp     short near ptr unk_7C5A
   我们直接看7C5A处的代码
[Asm] 纯文本查看 复制代码MEMORY:7C5A                 xor     ax, axMEMORY:7C5C                 mov     ds, axMEMORY:7C5E                 assume ds:MEMORYMEMORY:7C5E                 mov     es, axMEMORY:7C60                 assume es:MEMORYMEMORY:7C60                 mov     ss, axMEMORY:7C62                 mov     bp, 7C00hMEMORY:7C65                 mov     sp, 7C00hMEMORY:7C68                 cmp     byte ptr [bp+40h], 0FFh ; 检测磁盘物理驱动号是否正确MEMORY:7C6D                 jnz     short loc_7C73  ; 判断分区文件系统是fat12/fat16还是fat32MEMORY:7C6F                 mov     [bp+40h], dlMEMORY:7C73MEMORY:7C73 loc_7C73:                               ; CODE XREF: MEMORY:7C6DjMEMORY:7C73                 cmp     word ptr [bp+16h], 0 ; 判断分区文件系统是fat12/fat16还是fat32MEMORY:7C78                 jnz     short loc_7C89  ; 如果是fat12/fat16则跳转MEMORY:7C7A                 cmp     dword ptr [bp+11h], 0 ; 判断分区文件系统是fat12/fat16还是fat32MEMORY:7C80                 jnz     short loc_7C89  ; 如果是fat12/fat16则跳转MEMORY:7C82                 cmp     word ptr [bp+2Ah], 0MEMORY:7C87                 jbe     short loc_7C8C  ; 如果是fat32则跳转MEMORY:7C89MEMORY:7C89 loc_7C89:                               ; CODE XREF: MEMORY:7C78jMEMORY:7C89                                         ; MEMORY:7C80jMEMORY:7C89                 jmp     loc_7D93
    这里先检测分区文件系统是fat12/fat16还是fat32,如果是fat12/fat16,则输出一些信息,我们就不看了,只看fat32的情况。
[Asm] 纯文本查看 复制代码MEMORY:7C8C loc_7C8C:                               ; CODE XREF: MEMORY:7C87jMEMORY:7C8C                 mov     ax, 800hMEMORY:7C8F                 mov     dl, [bp+40h]MEMORY:7C93                 int     13h             ; DISK - DISK - GET CURRENT DRIVE PARAMETERS (XT,AT,XT286,CONV,PS)MEMORY:7C93                                         ; DL = drive numberMEMORY:7C93                                         ; Return: CF set on error, AH = status code, BL = drive typeMEMORY:7C93                                         ; DL = number of consecutive drivesMEMORY:7C93                                         ; DH = maximum value for head number, ES:DI -> drive parameterMEMORY:7C95                 jnb     short loc_7C9CMEMORY:7C97                 mov     cx, 0FFFFhMEMORY:7C9A                 mov     dh, cl
    在这里,用int 13h,ah=08h来读取磁盘参数,我们看看这种读取方式的介绍

    从上面的介绍可知,如果读取失败,则cf标志位置1,那么jnb     short loc_7C9C就不会执行。反之,cf标志位为0,jnb     short loc_7C9C会被执行。我们接下来看0x7c9c处的代码
[Asm] 纯文本查看 复制代码MEMORY:7C9C loc_7C9C:                               ; CODE XREF: MEMORY:7C95jMEMORY: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, bxMEMORY:7CAE                 movzx   ecx, clMEMORY:7CB2                 inc     eax             ; 因为磁头数是从0开始计数,所以这里要+1MEMORY:7CB4                 inc     ebx             ; 柱面数也是从0开始计数,这里也要+1MEMORY:7CB6                 mul     ecx             ; 这里是磁头数*每磁道扇区数MEMORY:7CB9                 mul     ebx             ; 上面得到的结果*柱面数,得到的值其实就是这个分区的大小MEMORY:7CBC                 mov     dword_7DB4, eaxMEMORY:7CC0                 mov     eax, 0EhMEMORY:7CC6                 add     eax, [bp+1Ch]       ; 计算第二个引导扇区的绝对偏移MEMORY:7CCB                 mov     cx, 1MEMORY:7CCE                 xor     bx, bxMEMORY:7CD0                 mov     es, bxMEMORY:7CD2                 mov     bx, 7E00hMEMORY:7CD5                 call    loc_7CDBMEMORY:7CD8                 jmp     loc_7E00
    这里先读取磁盘参数,然后通过计算得出磁盘大小,然后计算第二引导扇区的偏移,接下来有个call,我们看这个call里面的代码
[Asm] 纯文本查看 复制代码MEMORY:7CDB loc_7CDB:                               ; CODE XREF: MEMORY:7CD5pMEMORY:7CDB                 push    esMEMORY:7CDC                 cmp     eax, dword_7DB4MEMORY:7CE1                 jnb     short loc_7CFFMEMORY:7CE3                 pushadMEMORY:7CE5                 mov     ah, 41h ; 'A'MEMORY:7CE7                 mov     bx, 55AAhMEMORY:7CEA                 mov     dl, [bp+40h]MEMORY:7CEE                 int     13h             ; DISK - Check for INT 13h ExtensionsMEMORY:7CEE                                         ; BX = 55AAh, DL = drive numberMEMORY:7CEE                                         ; Return: CF set if not supportedMEMORY:7CEE                                         ; AH = extensions versionMEMORY:7CEE                                         ; BX = AA55hMEMORY:7CEE                                         ; CX = Interface support bit map
    这段代码在上一个帖子有讲过,就是检测int 13h的拓展功能是否可用,如果可用,接下来就会用int 13h的拓展功能来读取扇区。代码如下
[Asm] 纯文本查看 复制代码MEMORY:7CF0                 jb      short loc_7D49  ; 拓展功能不可用则跳转MEMORY:7CF2                 cmp     bx, 0AA55hMEMORY:7CF6                 jnz     short loc_7D49MEMORY:7CF8                 test    cl, 1MEMORY:7CFB                 jz      short loc_7D49MEMORY:7CFD                 popadMEMORY:7CFFMEMORY:7CFF loc_7CFF:                               ; CODE XREF: MEMORY:7CE1jMEMORY:7CFF                                         ; MEMORY:7D41jMEMORY:7CFF                 pushadMEMORY:7D01                 cmp     cx, 40h ; '@'MEMORY:7D04                 jbe     short loc_7D09MEMORY:7D06                 mov     cx, 40h ; '@'MEMORY:7D09MEMORY:7D09 loc_7D09:                               ; CODE XREF: MEMORY:7D04jMEMORY:7D09                 mov     word ptr dword_7D45, cxMEMORY:7D0D                 push    0MEMORY:7D0F                 push    0MEMORY:7D11                 push    eaxMEMORY:7D13                 push    esMEMORY:7D14                 push    bxMEMORY:7D15                 push    cxMEMORY:7D16                 push    10hMEMORY:7D18                 mov     si, spMEMORY:7D1A                 mov     dl, [bp+40h]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_7D8BMEMORY:7D24                 add     sp, 10hMEMORY:7D27                 popadMEMORY:7D29                 push    bxMEMORY:7D2A                 mov     ebx, dword_7D45MEMORY:7D2F                 add     eax, ebxMEMORY:7D32                 shl     ebx, 5MEMORY:7D36                 mov     dx, esMEMORY:7D38                 add     dx, bxMEMORY:7D3A                 mov     es, dxMEMORY:7D3C                 pop     bxMEMORY:7D3D                 sub     cx, word ptr dword_7D45MEMORY:7D41                 jnz     short loc_7CFFMEMORY:7D43                 pop     esMEMORY:7D44                 retn
   这里读取的是第二启动扇区代码,存放的位置为0x7e00,然后进行一些读取结果的检测,如果读取正确,则函数返回。返回之后,程序跳转到0x7e00处去执行第二启动扇区的代码。
   在第二启动引导代码中,先获取根目录簇号,然后检测这个值是否正确,代码如下
[Asm] 纯文本查看 复制代码MEMORY:7E00                                         ; MEMORY:7E5Bj ...MEMORY:7E00                 mov     eax, [bp+2Ch]   ; 获取根目录簇号MEMORY:7E05                 cmp     eax, 0FFFFFF8hMEMORY:7E0B                 jb      short loc_7E10
    如果正确则跳转到0x7E10处,下面我们来看0x7E10处的代码
[Asm] 纯文本查看 复制代码MEMORY:7E10 loc_7E10:                               ; CODE XREF: MEMORY:7E0BjMEMORY:7E10                 mov     bx, 2000hMEMORY:7E13                 mov     es, bxMEMORY:7E15                 assume es:nothingMEMORY:7E15                 call    loc_7F3E
    这里设置了es的值,然后就调用一个call,我们进去看看这个call 的代码
[Asm] 纯文本查看 复制代码MEMORY:7F3E                 dec     eaxMEMORY:7F40                 dec     eaxMEMORY:7F42                 xor     edx, edxMEMORY:7F45                 movzx   ebx, byte ptr [bp+0Dh] ; 获取每簇扇区数MEMORY:7F4B                 mul     ebxMEMORY:7F4E                 push    eaxMEMORY:7F50                 xor     edx, edxMEMORY:7F53                 movzx   eax, byte ptr [bp+10h] ; 获取fat表数MEMORY:7F59                 mul     dword ptr [bp+24h] ; 用fat表数*每fat扇区数MEMORY:7F5E                 movzx   ebx, word ptr [bp+0Eh] ; 获取保留扇区数MEMORY:7F64                 add     eax, ebxMEMORY:7F67                 add     eax, [bp+1Ch]   ; 加上隐藏扇区数MEMORY:7F6C                 pop     ebxMEMORY:7F6E                 add     eax, ebxMEMORY:7F71                 xor     bx, bxMEMORY:7F73                 movzx   cx, byte ptr [bp+0Dh]MEMORY:7F78                 call    sub_7CDBMEMORY:7F7B                 retn
    在这里面进行了一些计算,其实是计算fat32文件系统中数据区的偏移,然后就调用了call    sub_7CDB,这个call在前面有看到过,是一个读取扇区的call,这里其实是读取fat32文件系统的数据区数据,读取大小为一个簇,读取后存放位置为2000h:0000h。读取完之后,函数返回。接下来我们来看call    loc_7F3E之后的代码
[Asm] 纯文本查看 复制代码MEMORY:7E18                 xor     bx, bxMEMORY:7E1A                 mov     bl, [bp+0Dh]    ; 获取每簇扇区数MEMORY:7E1E                 shl     bx, 4           ;这里计算有多少个短目录项(每个短目录项占32个字节)MEMORY:7E21                 mov     ax, 2000hMEMORY:7E24                 mov     es, axMEMORY:7E26                 xor     di, diMEMORY:7E28                 mov     si, 7FA3hMEMORY:7E2B                 mov     cx, 0BhMEMORY:7E2E                 repe cmpsbMEMORY:7E30                 jz      short loc_7E5DMEMORY:7E32MEMORY:7E32 loc_7E32:                               ; CODE XREF: MEMORY:7DBEjMEMORY:7E32                 dec     bxMEMORY:7E33MEMORY:7E33 loc_7E33:                               ; CODE XREF: MEMORY:7DCDjMEMORY:7E33                 jnz     short loc_7E38    通过上面的代码可以看出是在循环查找那个文件名,接下来我们看找到的情况
[Asm] 纯文本查看 复制代码MEMORY:7E5D loc_7E5D:                               ; CODE XREF: MEMORY:7E30jMEMORY:7E5D                                         ; MEMORY:7E49jMEMORY:7E5D                 mov     si, 7FAEhMEMORY:7E60MEMORY:7E60 loc_7E60:                               ; CODE XREF: MEMORY:7DECjMEMORY:7E60                 call    sub_7DA5
    查找到了,si指向0x7FAE,这里有一个call,我们进去看看
[Asm] 纯文本查看 复制代码MEMORY:7DA5 sub_7DA5        proc near               ; CODE XREF: sub_7CDB+B3pMEMORY:7DA5                                         ; sub_7CDB+BBp ...MEMORY:7DA5                 lodsb           ;从si中读取字符,存放到al中MEMORY:7DA6                 or      al, alMEMORY:7DA8                 jz      short locret_7DB3MEMORY:7DAA                 mov     ah, 0EhMEMORY:7DAC                 mov     bx, 7MEMORY: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_7DA5MEMORY:7DB3 ; ---------------------------------------------------------------------------MEMORY:7DB3MEMORY:7DB3 locret_7DB3:                            ; CODE XREF: sub_7DA5+3jMEMORY:7DB3                 retn
    这个函数的功能其实就是把si指向的地址中存放的字符串显示到屏幕上。就是这个效果

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

    然后我们再来看接下来的代码
[Asm] 纯文本查看 复制代码MEMORY:7E65 loc_7E65:                               ; CODE XREF: MEMORY:7DEFjMEMORY:7E65                 xor     dx, dxMEMORY:7E67                 mov     ax, es:[di+14h]     ;取出文件起始簇号的高两个字节MEMORY:7E6B                 shl     eax, 10h            MEMORY:7E6F                 mov     ax, es:[di+1Ah]     ;取出文件起始簇号的低两个字节MEMORY:7E73                 cmp     eax, 2MEMORY:7E77                 jnb     short loc_7E7CMEMORY:7E79                 jmp     loc_7D93
    从上面的代码可以看出,这里是取出文件起始簇号的高两个字节和低两个字节,并将他们组成文件的起始簇号,然后用文件起始簇号来和2做比较,为啥要和2做比较,是因为所有的簇都是从2开始编号的。在这里,eax的值大于2,所以执行 jnb     short loc_7E7C指令,我们接下来看loc_7E7C处的代码
[Asm] 纯文本查看 复制代码MEMORY:7E7C loc_7E7C:                               ; CODE XREF: MEMORY:7E77jMEMORY:7E7C                 cmp     eax, 0FFFFFF8hMEMORY:7E82                 jb      short loc_7E87MEMORY:7E84                 jmp     loc_7D93
    这里只判断文件所谓的簇号是否大于最大值,这里是小于,所以 执行jb      short loc_7E87,我们接下来看loc_7E87处的代码
[Asm] 纯文本查看 复制代码MEMORY:7E87 loc_7E87:                               ; CODE XREF: MEMORY:7E82jMEMORY:7E87                 mov     bx, 0F80hMEMORY:7E8A                 mov     es, bxMEMORY:7E8C                 assume es:nothingMEMORY:7E8CMEMORY:7E8C loc_7E8C:                               ; CODE XREF: MEMORY:7EB3jMEMORY:7E8C                 cmp     eax, 0FFFFFF8hMEMORY:7E92                 jnb     short loc_7EB5MEMORY:7E94                 push    eaxMEMORY:7E96                 xor     bx, bxMEMORY:7E98                 push    esMEMORY:7E99                 call    near ptr unk_7F3E
   这里修改了下es的值,然后调用一个call,我们进去看这个call干了些啥
[Asm] 纯文本查看 复制代码MEMORY:7F3E                 dec     eaxMEMORY:7F40                 dec     eax             ; 这里是该簇的簇号-2MEMORY:7F42                 xor     edx, edxMEMORY:7F45                 movzx   ebx, byte ptr [bp+0Dh] ; 获取每簇扇区数MEMORY:7F4B                 mul     ebxMEMORY:7F4E                 push    eaxMEMORY:7F50                 xor     edx, edxMEMORY:7F53                 movzx   eax, byte ptr [bp+10h] ; 获取fat表个数MEMORY:7F59                 mul     dword ptr [bp+24h] ; fat表个数*每fat扇区数MEMORY:7F5E                 movzx   ebx, word ptr [bp+0Eh] ; 获取保留扇区数MEMORY:7F64                 add     eax, ebxMEMORY:7F67                 add     eax, [bp+1Ch]   ; 加上隐藏扇区数MEMORY:7F6C                 pop     ebxMEMORY:7F6E                 add     eax, ebxMEMORY:7F71                 xor     bx, bxMEMORY:7F73                 movzx   cx, byte ptr [bp+0Dh]MEMORY:7F78                 call    sub_7CDBMEMORY:7F7B                 retn
    这段代码看着挺熟悉,上面的一大堆计算,其实可以总结成以下公式(这里计算的是绝对扇区号)
    某簇起始扇区号 = 隐藏扇区数 + 保留扇区数 + 每个FAT表大小扇区数 × FAT表个数 + (该簇簇号 - 2) × 每簇扇区数
    然后读取该簇的数据到0F80h:0000h处(call    sub_7CDB)。我们接着看call    near ptr unk_7F3E之后的代码
[Asm] 纯文本查看 复制代码MEMORY:7E9C                 pop     esMEMORY:7E9D                 assume es:MEMORYMEMORY:7E9D                 xor     bx, bxMEMORY:7E9F                 mov     bl, [bp+0Dh]MEMORY:7EA3                 shl     bx, 5MEMORY:7EA6                 mov     ax, esMEMORY:7EA8                 add     ax, bx          ; 这里其实是把es的值设置到刚才读取的那一簇数据之后MEMORY:7EAA                 mov     es, axMEMORY:7EAC                 pop     eaxMEMORY:7EAE                 push    esMEMORY:7EAF                 call    loc_7EC2MEMORY:7EB2                 pop     esMEMORY:7EB3                 jmp     short loc_7E8C
    上面重新设置了下es的值,其实是让它指向刚才读取的那一簇数据之后,然后又是一个call,我们看call    loc_7EC2内部的代码
[Asm] 纯文本查看 复制代码MEMORY:7EC2 loc_7EC2:                               ; CODE XREF: MEMORY:7E53pMEMORY:7EC2                                         ; MEMORY:7EAFpMEMORY:7EC2                 shl     eax, 2          ; 在fat中,每个fat表项占4个字节,且其数值与数据区的簇号相同MEMORY:7EC6                 mov     ecx, eaxMEMORY:7EC9                 xor     edx, edxMEMORY:7ECC                 movzx   ebx, word ptr [bp+0Bh] ; 获取每扇区字节数MEMORY:7ED2                 push    ebxMEMORY:7ED4                 div     ebxMEMORY:7ED7                 movzx   ebx, word ptr [bp+0Eh] ; 获取保留扇区数MEMORY:7EDD                 add     eax, ebxMEMORY:7EE0                 mov     ebx, [bp+1Ch]   ; 获取隐藏扇区数MEMORY:7EE5                 add     eax, ebxMEMORY:7EE8                 pop     ebxMEMORY:7EEA                 dec     ebxMEMORY:7EEC                 and     ecx, ebxMEMORY:7EEF                 movzx   ebx, word ptr [bp+28h] ; 获取FAT表镜像标志MEMORY:7EF5                 and     bx, 0Fh         ; 值为0表示系统保存2份互为备份的FAT表,值为1表示系统仅保存1份FAT表MEMORY:7EF8                 jz      short loc_7F12MEMORY:7EFA                 cmp     bl, [bp+10h]MEMORY:7EFE                 jb      short loc_7F03MEMORY:7F00                 jmp     loc_7D93
    上面这段代码其实就是计算出含有该簇号的fat表所在的扇区偏移。因为每个簇号在fat中占4个字节,所以簇号*4就得出该簇号在fat表中的偏移,然后除以扇区大小就可以得知该簇号相对于fat表的扇区偏移,再加上保留扇区和隐藏扇区,就可以计算出该簇号所在扇区的绝对偏移值。然后检测这个文件系统中有几个fat表,如果有两个,则跳到 short loc_7F12处。接下来我们看 short loc_7F12处的代码
[Asm] 纯文本查看 复制代码MEMORY:7F03 loc_7F03:                               ; CODE XREF: MEMORY:7EFEjMEMORY:7F03                 push    eaxMEMORY:7F05                 mov     eax, [bp+24h]MEMORY:7F0A                 mul     ebxMEMORY:7F0D                 pop     edxMEMORY:7F0F                 add     eax, edxMEMORY:7F12MEMORY:7F12 loc_7F12:                               ; CODE XREF: MEMORY:7EF8jMEMORY:7F12                 push    ecxMEMORY:7F14                 mov     bx, 9000hMEMORY:7F17                 mov     es, bxMEMORY:7F19                 assume es:nothingMEMORY:7F19                 cmp     eax, dword_7F3AMEMORY:7F1E                 jz      short loc_7F2CMEMORY:7F20                 mov     dword_7F3A, eaxMEMORY:7F24                 xor     bx, bxMEMORY:7F26                 mov     cx, 1MEMORY:7F29                 call    sub_7CDBMEMORY:7F2CMEMORY:7F2C loc_7F2C:                               ; CODE XREF: MEMORY:7F1EjMEMORY:7F2C                 pop     ecxMEMORY:7F2E                 mov     eax, es:[ecx]MEMORY:7F33                 and     eax, 0FFFFFFFhMEMORY:7F39                 retn
    这里则是读取该簇号所在的扇区数据,然后获取该簇号在fat中的值,如果一个文件占用几个簇,那么该簇号在fat中的值就是下一个簇的簇号,如果文件结束,则该簇号在fat表中的值为0x0fffffff。这个函数结束了之后程序又会跳回上面的loc_7E8C,判断文件是否结束,如果没有结束则继续读取数据,如果结束,则程序跳转去执行loc_7EB5的代码。
[Asm] 纯文本查看 复制代码MEMORY:7EB5 loc_7EB5:                               ; CODE XREF: MEMORY:7E92jMEMORY:7EB5                 mov     dl, [bp+40h]MEMORY:7EB9                 mov     dh, byte ptr loc_7DFDMEMORY:7EBD                 jmp     far ptr loc_F800
    上面这段代码获取磁盘的驱动器号,然后程序跳转到loc_F800去执行,其实loc_F800就是刚才读取的FREELDR.SYS文件的数据,这里程序去执行FREELDR.SYS文件的代码。到了这里,DBR的调试也结束了,接下来就是实行FREELDR.SYS文件中的代码了。(这里的文件名和Windows的有些出入,Windows的应该是NTLDR)
    三、FREELDR.SYS
    我们接着看下面的代码
[Asm] 纯文本查看 复制代码MEMORY:F800 loc_F800:                               ; CODE XREF: MEMORY:7EBDJMEMORY:F800                                         ; MEMORY:F853jMEMORY:F800                 jmp     loc_FA00
    在loc_F800中,只有一个跳转,我们接着去看loc_FA00处的代码
[Asm] 纯文本查看 复制代码MEMORY:FA00 loc_FA00:                               ; CODE XREF: MEMORY:loc_F800jMEMORY:FA00                 cliMEMORY:FA01                 xor     ax, axMEMORY:FA03                 mov     ds, axMEMORY:FA05                 mov     es, axMEMORY:FA07                 assume es:MEMORYMEMORY:FA07                 mov     fs, axMEMORY:FA09                 mov     gs, axMEMORY:FA0B                 mov     ss, axMEMORY:FA0D                 mov     sp, word_FAAEMEMORY:FA11                 call    sub_FC16
    这里设置一些段寄存器之后,调用了一个call,我们进去看这个call 的代码
[Asm] 纯文本查看 复制代码MEMORY:FC16 sub_FC16        proc near               ; CODE XREF: MEMORY:FA11pMEMORY:FC16                 pushaMEMORY:FC17                 call    sub_FC07MEMORY: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 IBFMEMORY:FC1C                                         ; 4:  enables IRQ 1 interrupt on keyboard IBFMEMORY: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/offMEMORY:FC1C                                         ; 0:  reset the PC (THIS BIT SHOULD ALWAYS BE SET TO 1)MEMORY:FC1E                 call    sub_FC07MEMORY:FC21                 mov     al, 0DFh ; '    ;告诉键盘控制器我们要开启A20MEMORY:FC23                 out     60h, al         ; 8042 keyboard controller data register.MEMORY:FC25                 call    sub_FC07MEMORY:FC28                 popaMEMORY:FC29                 retn
    这段代码的功能其实就是开启A20地址线,call    sub_FC07这个函数其实是等待8042的Inputbuffer为空,我们看看它的代码
[Asm] 纯文本查看 复制代码MEMORY:FC07 sub_FC07        proc near               ; CODE XREF: sub_FC07+CjMEMORY:FC07                                         ; sub_FC16+1p ...MEMORY:FC07                 jmp     short $+2MEMORY:FC09 ; ---------------------------------------------------------------------------MEMORY:FC09MEMORY:FC09 loc_FC09:                               ; CODE XREF: sub_FC07jMEMORY:FC09                 jmp     short $+2MEMORY:FC0B ; ---------------------------------------------------------------------------MEMORY:FC0BMEMORY:FC0B loc_FC0B:                               ; CODE XREF: sub_FC07:loc_FC09jMEMORY:FC0B                 in      al, 64h         ; 8042 keyboard controller status registerMEMORY:FC0B                                         ; 7:  PERR    1=parity error in data received from keyboardMEMORY: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 inhibitedMEMORY:FC0B                                         ; 3:  A2      0=60h was the port last written to, 1=64h was lastMEMORY:FC0B                                         ; 2:  SYS     distinguishes reset types: 0=cold reboot, 1=warm rebootMEMORY: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, 0FFhMEMORY:FC0F                 jz      short locret_FC15MEMORY:FC11                 test    al, 2MEMORY:FC13                 jnz     short sub_FC07MEMORY:FC15 locret_FC15:                            ; CODE XREF: sub_FC07+8jMEMORY:FC15                 retn
    具体的就不在这里赘述,大家可以自己去百度下关于A20地址线的相关资料。开启了A20之后,我们接着看程序又干了些啥
[Asm] 纯文本查看 复制代码MEMORY:FA14                 mov     dword_6F00, 0FA41hMEMORY:FA1D                 mov     ax, 1000hMEMORY:FA20                 mov     es, axMEMORY:FA22                 assume es:nothingMEMORY:FA22                 mov     eax, es:3ChMEMORY:FA27                 add     eax, 18hMEMORY:FA2B                 mov     eax, es:[eax+10h]MEMORY:FA31                 add     eax, 10000hMEMORY:FA37                 mov     dword_FA9B, eaxMEMORY:FA3B                 xor     ax, axMEMORY:FA3D                 mov     es, axMEMORY:FA3F                 assume es:MEMORYMEMORY:FA3F                 jmp     short loc_FA7C
    这里则是从内存中读取一个数值,然后保存在dword_FA9B里,至于这个数值干啥用,我们接着看
[Asm] 纯文本查看 复制代码MEMORY:FA7C loc_FA7C:                               ; CODE XREF: MEMORY:FA3FjMEMORY:FA7C                 cliMEMORY:FA7D                 mov     word_FAAE, spMEMORY:FA81                 lgdt    fword ptr byte_FAD8MEMORY:FA86                 mov     eax, cr0MEMORY:FA89                 or      eax, 1MEMORY:FA8D                 mov     cr0, eax
    上面这段代码先是将fword ptr byte_FAD8加载到GDT表的寄存器中,然后开启保护模式。保护模式是否开启是由cr0的第0位控制的,为1表示开启保护模式,为0表示不开启。
    开启了A20和保护模式之后,下面的代码就变成32位的了,至于后面都干了写啥,后期分析之后会分享出来,以上只是我个人的一些分析过程,有分析错误或者描述不对的地方,还希望大家能提出来,我们共同进步

来源:http://www.12558.net
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
楼主热帖
回复

使用道具 举报

*滑块验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|12558网页游戏私服论坛 |网站地图

GMT+8, 2024-5-6 06:52 , Processed in 0.187500 second(s), 31 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表