吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 67824|回复: 204
收起左侧

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

    [复制链接]
冰琥珀 发表于 2015-4-19 23:20
本帖最后由 冰琥珀 于 2015-4-27 12:19 编辑

    关于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,在弹出的对话框进行如下设置
1.jpg
    启动虚拟机后,再点击IDA弹出的对话框的"OK"按钮,选择第一个进程,点"OK",如下图
2.jpg
    进入调试窗口后,转到0x7c00处,按"F2"下断点,然后按"F9"运行程序,当程序断下来之后,按"Alt+s",选择16位编码,这时反汇编可能会变成一堆数据,我们只要将其选中(446个字节),然后按“C”,选择“Force”,将数据强行转换成代码即可。
3.jpg
    接下来就开始我们的调试了,先看下面的代码
[Asm] 纯文本查看 复制代码
MEMORY:7C00 loc_7C00:                               ; CODE XREF: MEMORY:loc_7CAEJ
MEMORY:7C00                 cli
MEMORY:7C01                 cld
MEMORY:7C02                 xor     ax, ax
MEMORY:7C04                 mov     ss, ax
MEMORY:7C06                 mov     ds, ax
MEMORY:7C08                 mov     bp, 7C00h
MEMORY:7C0B                 lea     sp, [bp-20h]
MEMORY:7C0E                 sti
MEMORY:7C0F                 mov     ax, 1FE0h
MEMORY:7C12                 mov     es, ax
MEMORY:7C14                 assume es:nothing
MEMORY:7C14                 mov     si, bp
MEMORY:7C16                 mov     di, bp
MEMORY:7C18                 mov     cx, 100h
MEMORY: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:7C1DJ
MEMORY:27A22                 mov     ds, ax
MEMORY:27A24                 assume ds:MEMORY
MEMORY:27A24                 mov     ss, ax
MEMORY:27A26                 assume ss:MEMORY
MEMORY:27A26                 xor     ax, ax
MEMORY:27A28                 mov     es, ax
MEMORY:27A2A                 lea     di, [bp+1BEh]   ; 获取分区表地址
MEMORY:27A2E                 test    byte ptr [di], 80h ; 是否是活动分区
MEMORY:27A31                 jnz     short loc_7AA0
MEMORY: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_7AB3
MEMORY:27AA3                 jb      short loc_7A5B
MEMORY:27AA5                 cmp     es:word_7DFE, 0AA55h
MEMORY:27AAC                 jnz     short loc_7A7F
MEMORY:27AAE                 jmp     far ptr loc_7C00

    跳转过来就是一个call,我们跟进去看看。
[Asm] 纯文本查看 复制代码
27AB3                 mov     bx, 55AAh
MEMORY:27AB6                 mov     ah, 41h ; 'A'
MEMORY:27AB8                 int     13h             ; DISK - Check for INT 13h Extensions
MEMORY:27AB8                                         ; BX = 55AAh, DL = drive number
MEMORY:27AB8                                         ; Return: CF set if not supported
MEMORY:27AB8                                         ; AH = extensions version
MEMORY:27AB8                                         ; BX = AA55h
MEMORY:27AB8                                         ; CX = Interface support bit map
MEMORY:27ABA                 jb      short loc_7AEE
MEMORY:27ABC                 cmp     bx, 0AA55h
MEMORY:27AC0                 jnz     short loc_7AEE
MEMORY:27AC2                 test    cl, 1
MEMORY:27AC5                 jz      short loc_7AEE
MEMORY:27AC7                 jmp     short loc_7AD9

    这里其实是检测int 13h的拓展功能可不可以用,如果可用,则跳转到1FE0h:7AD9h处,否则跳转到1FE0h:7AEEh处。我们先来看1FE0h:7AEEh处的代码
[Asm] 纯文本查看 复制代码
MEMORY:27AEE                 mov     ax, 204h
MEMORY:27AF1                 mov     bx, 7C00h
MEMORY:27AF4                 mov     cx, [di+2]     ;di为分区表首地址
MEMORY:27AF7                 mov     dh, [di+1]
MEMORY:27AFA                 int     13h             ; DISK - READ SECTORS INTO MEMORY
MEMORY:27AFA                                         ; AL = number of sectors to read, CH = track, CL = sector
MEMORY:27AFA                                         ; DH = head, DL = drive, ES:BX -> buffer to fill
MEMORY:27AFA                                         ; Return: CF set on error, AH = status, AL = number of sectors read
MEMORY: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  10h
MEMORY:27ACA                 db    0
MEMORY:27ACB                 db    4
MEMORY:27ACC                 db    0
MEMORY:27ACD                 db    0
MEMORY:27ACE                 db  7Ch ; |
MEMORY:27ACF                 db    0
MEMORY:27AD0                 db    0
MEMORY:27AD1 word_27AD1      dw 0                    ; DATA XREF: MEMORY:7CDCw
MEMORY:27AD3 word_27AD3      dw 0                    ; DATA XREF: MEMORY:loc_7CE2w
MEMORY:27AD5                 db    0
MEMORY:27AD6                 db    0
MEMORY:27AD7                 db    0
MEMORY:27AD8                 db    0
MEMORY:27AD9 ; ---------------------------------------------------------------------------
MEMORY:27AD9                 mov     ax, [di+8]
MEMORY:27ADC                 mov     word_7CD1, ax
MEMORY:27ADF                 mov     ax, [di+0Ah]
MEMORY:27AE2                 mov     word_7CD3, ax
MEMORY:27AE5                 mov     ax, 4200h
MEMORY:27AE8                 mov     si, 7CC9h
MEMORY: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_7A5B
MEMORY:27AA5                 cmp     es:word_7DFE, 0AA55h
MEMORY:27AAC                 jnz     short loc_7A7F
MEMORY:27AAE                 jmp     far ptr loc_7C00

      这里其实是检测分区引导扇区是否正确读取,如果正确读取则跳转去执行分区引导扇区的代码(这里是jmp far ptr loc_7C00)。
      二、PBR调试
     我们先来认识下PBR
DBR.jpg

    下面我们再来看下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, 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 [bp+40h], 0FFh ; 检测磁盘物理驱动号是否正确
MEMORY:7C6D                 jnz     short loc_7C73  ; 判断分区文件系统是fat12/fat16还是fat32
MEMORY:7C6F                 mov     [bp+40h], dl
MEMORY:7C73
MEMORY:7C73 loc_7C73:                               ; CODE XREF: MEMORY:7C6Dj
MEMORY:7C73                 cmp     word ptr [bp+16h], 0 ; 判断分区文件系统是fat12/fat16还是fat32
MEMORY:7C78                 jnz     short loc_7C89  ; 如果是fat12/fat16则跳转
MEMORY:7C7A                 cmp     dword ptr [bp+11h], 0 ; 判断分区文件系统是fat12/fat16还是fat32
MEMORY:7C80                 jnz     short loc_7C89  ; 如果是fat12/fat16则跳转
MEMORY:7C82                 cmp     word ptr [bp+2Ah], 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的情况。
[Asm] 纯文本查看 复制代码
MEMORY:7C8C loc_7C8C:                               ; CODE XREF: MEMORY:7C87j
MEMORY:7C8C                 mov     ax, 800h
MEMORY:7C8F                 mov     dl, [bp+40h]
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处的代码
[Asm] 纯文本查看 复制代码
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, [bp+1Ch]       ; 计算第二个引导扇区的绝对偏移
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里面的代码
[Asm] 纯文本查看 复制代码
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, [bp+40h]
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的拓展功能来读取扇区。代码如下
[Asm] 纯文本查看 复制代码
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, [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_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处去执行第二启动扇区的代码。
   在第二启动引导代码中,先获取根目录簇号,然后检测这个值是否正确,代码如下
[Asm] 纯文本查看 复制代码
MEMORY:7E00                                         ; MEMORY:7E5Bj ...
MEMORY:7E00                 mov     eax, [bp+2Ch]   ; 获取根目录簇号
MEMORY:7E05                 cmp     eax, 0FFFFFF8h
MEMORY:7E0B                 jb      short loc_7E10

    如果正确则跳转到0x7E10处,下面我们来看0x7E10处的代码
[Asm] 纯文本查看 复制代码
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 的代码
[Asm] 纯文本查看 复制代码
MEMORY:7F3E                 dec     eax
MEMORY:7F40                 dec     eax
MEMORY:7F42                 xor     edx, edx
MEMORY:7F45                 movzx   ebx, byte ptr [bp+0Dh] ; 获取每簇扇区数
MEMORY:7F4B                 mul     ebx
MEMORY:7F4E                 push    eax
MEMORY:7F50                 xor     edx, edx
MEMORY: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, ebx
MEMORY:7F67                 add     eax, [bp+1Ch]   ; 加上隐藏扇区数
MEMORY:7F6C                 pop     ebx
MEMORY:7F6E                 add     eax, ebx
MEMORY:7F71                 xor     bx, bx
MEMORY:7F73                 movzx   cx, byte ptr [bp+0Dh]
MEMORY:7F78                 call    sub_7CDB
MEMORY:7F7B                 retn

    在这里面进行了一些计算,其实是计算fat32文件系统中数据区的偏移,然后就调用了call    sub_7CDB,这个call在前面有看到过,是一个读取扇区的call,这里其实是读取fat32文件系统的数据区数据,读取大小为一个簇,读取后存放位置为2000h:0000h。读取完之后,函数返回。接下来我们来看call    loc_7F3E之后的代码
[Asm] 纯文本查看 复制代码
MEMORY:7E18                 xor     bx, bx
MEMORY:7E1A                 mov     bl, [bp+0Dh]    ; 获取每簇扇区数
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
    通过上面的代码可以看出是在循环查找那个文件名,接下来我们看找到的情况
[Asm] 纯文本查看 复制代码
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,我们进去看看
[Asm] 纯文本查看 复制代码
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

    这个函数的功能其实就是把si指向的地址中存放的字符串显示到屏幕上。就是这个效果
7.jpg
    接下来就是对数据区数据的解析,先来看目录项的介绍(短文件名目录项)
short_dir.jpg
    然后我们再来看接下来的代码
[Asm] 纯文本查看 复制代码
MEMORY:7E65 loc_7E65:                               ; CODE XREF: MEMORY:7DEFj
MEMORY:7E65                 xor     dx, dx
MEMORY:7E67                 mov     ax, es:[di+14h]     ;取出文件起始簇号的高两个字节
MEMORY:7E6B                 shl     eax, 10h            
MEMORY:7E6F                 mov     ax, es:[di+1Ah]     ;取出文件起始簇号的低两个字节
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处的代码
[Asm] 纯文本查看 复制代码
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处的代码
[Asm] 纯文本查看 复制代码
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干了些啥
[Asm] 纯文本查看 复制代码
MEMORY:7F3E                 dec     eax
MEMORY:7F40                 dec     eax             ; 这里是该簇的簇号-2
MEMORY:7F42                 xor     edx, edx
MEMORY:7F45                 movzx   ebx, byte ptr [bp+0Dh] ; 获取每簇扇区数
MEMORY:7F4B                 mul     ebx
MEMORY:7F4E                 push    eax
MEMORY:7F50                 xor     edx, edx
MEMORY: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, ebx
MEMORY:7F67                 add     eax, [bp+1Ch]   ; 加上隐藏扇区数
MEMORY:7F6C                 pop     ebx
MEMORY:7F6E                 add     eax, ebx
MEMORY:7F71                 xor     bx, bx
MEMORY:7F73                 movzx   cx, byte ptr [bp+0Dh]
MEMORY:7F78                 call    sub_7CDB
MEMORY:7F7B                 retn

    这段代码看着挺熟悉,上面的一大堆计算,其实可以总结成以下公式(这里计算的是绝对扇区号)
    某簇起始扇区号 = 隐藏扇区数 + 保留扇区数 + 每个FAT表大小扇区数 × FAT表个数 + (该簇簇号 - 2) × 每簇扇区数
    然后读取该簇的数据到0F80h:0000h处(call    sub_7CDB)。我们接着看call    near ptr unk_7F3E之后的代码
[Asm] 纯文本查看 复制代码
MEMORY:7E9C                 pop     es
MEMORY:7E9D                 assume es:MEMORY
MEMORY:7E9D                 xor     bx, bx
MEMORY:7E9F                 mov     bl, [bp+0Dh]
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内部的代码
[Asm] 纯文本查看 复制代码
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 [bp+0Bh] ; 获取每扇区字节数
MEMORY:7ED2                 push    ebx
MEMORY:7ED4                 div     ebx
MEMORY:7ED7                 movzx   ebx, word ptr [bp+0Eh] ; 获取保留扇区数
MEMORY:7EDD                 add     eax, ebx
MEMORY:7EE0                 mov     ebx, [bp+1Ch]   ; 获取隐藏扇区数
MEMORY:7EE5                 add     eax, ebx
MEMORY:7EE8                 pop     ebx
MEMORY:7EEA                 dec     ebx
MEMORY:7EEC                 and     ecx, ebx
MEMORY:7EEF                 movzx   ebx, word ptr [bp+28h] ; 获取FAT表镜像标志
MEMORY:7EF5                 and     bx, 0Fh         ; 值为0表示系统保存2份互为备份的FAT表,值为1表示系统仅保存1份FAT表
MEMORY:7EF8                 jz      short loc_7F12
MEMORY:7EFA                 cmp     bl, [bp+10h]
MEMORY:7EFE                 jb      short loc_7F03
MEMORY: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:7EFEj
MEMORY:7F03                 push    eax
MEMORY:7F05                 mov     eax, [bp+24h]
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:[ecx]
MEMORY:7F33                 and     eax, 0FFFFFFFh
MEMORY:7F39                 retn

    这里则是读取该簇号所在的扇区数据,然后获取该簇号在fat中的值,如果一个文件占用几个簇,那么该簇号在fat中的值就是下一个簇的簇号,如果文件结束,则该簇号在fat表中的值为0x0fffffff。这个函数结束了之后程序又会跳回上面的loc_7E8C,判断文件是否结束,如果没有结束则继续读取数据,如果结束,则程序跳转去执行loc_7EB5的代码。
[Asm] 纯文本查看 复制代码
MEMORY:7EB5 loc_7EB5:                               ; CODE XREF: MEMORY:7E92j
MEMORY:7EB5                 mov     dl, [bp+40h]
MEMORY:7EB9                 mov     dh, byte ptr loc_7DFD
MEMORY: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:7EBDJ
MEMORY:F800                                         ; MEMORY:F853j
MEMORY:F800                 jmp     loc_FA00

    在loc_F800中,只有一个跳转,我们接着去看loc_FA00处的代码
[Asm] 纯文本查看 复制代码
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 的代码
[Asm] 纯文本查看 复制代码
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

    这段代码的功能其实就是开启A20地址线,call    sub_FC07这个函数其实是等待8042的Inputbuffer为空,我们看看它的代码
[Asm] 纯文本查看 复制代码
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 locret_FC15:                            ; CODE XREF: sub_FC07+8j
MEMORY:FC15                 retn

    具体的就不在这里赘述,大家可以自己去百度下关于A20地址线的相关资料。开启了A20之后,我们接着看程序又干了些啥
[Asm] 纯文本查看 复制代码
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:[eax+10h]
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里,至于这个数值干啥用,我们接着看
[Asm] 纯文本查看 复制代码
MEMORY:FA7C loc_FA7C:                               ; CODE XREF: MEMORY:FA3Fj
MEMORY:FA7C                 cli
MEMORY:FA7D                 mov     word_FAAE, sp
MEMORY:FA81                 lgdt    fword ptr byte_FAD8
MEMORY:FA86                 mov     eax, cr0
MEMORY:FA89                 or      eax, 1
MEMORY:FA8D                 mov     cr0, eax

    上面这段代码先是将fword ptr byte_FAD8加载到GDT表的寄存器中,然后开启保护模式。保护模式是否开启是由cr0的第0位控制的,为1表示开启保护模式,为0表示不开启。
    开启了A20和保护模式之后,下面的代码就变成32位的了,至于后面都干了写啥,后期分析之后会分享出来,以上只是我个人的一些分析过程,有分析错误或者描述不对的地方,还希望大家能提出来,我们共同进步

免费评分

参与人数 46吾爱币 +13 热心值 +44 收起 理由
sharkNet + 1 + 1 用心讨论,共获提升!
fen3641 + 1 我很赞同!
Tim-52Pojie + 1 + 1 org 0x7c00
liutao1896 + 1 + 1 我很赞同!
zsyhn + 1 + 1 谢谢@Thanks!
siuhoapdou + 1 + 1 谢谢@Thanks!
1131860091 + 1 我看不懂,但是为你们辛苦开贴给个赞,希望你们再接再厉给需要的人更多帮助
GNUBD + 1 + 1 谢谢@Thanks!
paradroid + 1 + 1 谢谢@Thanks!
wwwbbbccc + 1 + 1 很详细 学习了,谢谢@Thanks!
sgc199310 + 1 热心回复!
终南余雪 + 1 + 1 用心讨论,共获提升!
shuobatian + 1 + 1 我很赞同!
ysdyueding + 1 我很赞同!
ysz + 1 + 1 谢谢@Thanks!
那时花开789 + 1 谢谢@Thanks!
山人文轩 + 1 谢谢@Thanks!
yunws + 1 谢谢@Thanks!
lzq0521 + 1 我很赞同!
小朋友呢 + 1 出第二集吧,正好学习下
basicbird + 1 谢谢@Thanks!
_琥珀i + 1 找到失散多年的大哥~…………!!!
怎去优雅 + 1 谢谢@Thanks!
524287547 + 1 我很赞同!
o297 + 1 谢谢@Thanks!
icevsfire + 1 感谢发布原创作品,吾爱破解论坛因你更精彩.
anyucompany + 1 大神!!
sgf20212 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩.
yhxing + 1 太详细了
ehardware + 1 谢谢@Thanks!
华夏小荧虫 + 1 谢谢@Thanks!
凡凡之呗 + 1 楼主加油 评分给你 为什么我只能给一分
左小指 + 1 我很赞同!
iMichael + 1 谢谢@Thanks!
a110world + 1 我很赞同!
gujinyimeng + 1 我很赞同!
evido + 1 谢谢@Thanks!
qwuiop789 + 1 我很赞同!
波风雨泽 + 1 我很赞同!
heyteng + 1 热心回复!
x_kotaku + 1 我很赞同!
速皮尔 + 1 小白不懂,混个眼熟,大神
as125566 + 1 我很赞同!
aikuimail + 1 我很赞同!
无痕软件 + 1 暂时对MBR还不是很了解,留着以后看。MARK
YsGer + 1 请问法克论坛去哪了?

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| 冰琥珀 发表于 2015-4-20 19:49
本帖最后由 冰琥珀 于 2015-4-26 00:41 编辑
Hmily 发表于 2015-4-19 23:49
@冰琥珀 你把图片打包上传到到网盘给我个地址,我测试下是什么问题,是不是防火墙误拦截了导致的,还有说下 ...

http://pan.baidu.com/s/1HacGm
这是图片地址,看下是怎么回事,如果能上传了,我再去添加,还有些图片需要添加

点评

我这一下就传上去了没什么提示,你看看?要么你不能传的时候给我个截图看看是什么提示。  详情 回复 发表于 2015-4-21 11:29
Hmily 发表于 2015-4-21 11:29
冰琥珀 发表于 2015-4-20 19:49
http://pan.baidu.com/s/1HacGm
这是图片地址,看下是怎么回事,如果能上传了,我再去添加,还有些图片 ...

我这一下就传上去了没什么提示,你看看?要么你不能传的时候给我个截图看看是什么提示。
北漂小子 发表于 2015-4-19 23:45
看着好高大上。。。。。。不过。。。。。干啥这是?调试他干啥?
Hmily 发表于 2015-4-19 23:49
@冰琥珀 你把图片打包上传到到网盘给我个地址,我测试下是什么问题,是不是防火墙误拦截了导致的,还有说下图片位置,我给你插进去。
少年好学 发表于 2015-4-19 23:52
谢谢楼主分享!!!!!
Perry 发表于 2015-4-20 00:13
LZ可以申精哦
ZMLoveLH 发表于 2015-4-20 00:16
楼主牛人啊,看了这个帖子长见识了
green_puffer 发表于 2015-4-20 09:11
感谢分享~
雅瑟 发表于 2015-4-20 09:39 来自手机
看这个是真的学习了~感谢楼主分享~
 楼主| 冰琥珀 发表于 2015-4-20 09:57
Hmily 发表于 2015-4-19 23:49
@冰琥珀 你把图片打包上传到到网盘给我个地址,我测试下是什么问题,是不是防火墙误拦截了导致的,还有说下 ...

嗯,晚上回去弄
 楼主| 冰琥珀 发表于 2015-4-20 09:58
北漂小子 发表于 2015-4-19 23:45
看着好高大上。。。。。。不过。。。。。干啥这是?调试他干啥?

理解windows的启动引导过程
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-4-26 06:34

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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