免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5074 | 回复: 3
打印 上一主题 下一主题

[FreeBSD] boot0分析 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-10-14 18:10 |只看该作者 |倒序浏览
2007.8.26

今天我们通过bochs来分析boot0.

本文参考了《FreeBSD 5.2.1 boot0(启动扇区代码分析)》,转载请注明,谢谢!

源码位于:sys/boot/i386/boot0/boot0.S

安装bochs:
./configure --enable-debugger --enable-disasm
make; make install; rehash
# cp .bochsrc /root/

修改.bochsrc如下两行:
ata0-master: type=disk, mode=flat, path="/kerndebug/server.img", cylinders=0
vga: extension=none
其中/kerndebug/server.img为虚拟系统磁盘(可以用qemu的磁盘)

BIOS把引导扇区的512字节的内容读入到了0:0x7c00处,然后就跳转到0:0x7C00处去执行.
我们启动bochs,在0x7c00处设置断点。
# bochs -q -f /root/.bochsrc
========================================================================
                        Bochs x86 Emulator 2.3
              Build from CVS snapshot on August 27, 2006
========================================================================
00000000000i[     ] reading configuration from /root/.bochsrc
00000000000e[     ] /root/.bochsrc: ataX-master/slave CHS set to 0/0/0 - autodetection enabled
00000000000i[     ] installing x module as the Bochs GUI
00000000000i[     ] using log file bochsout.txt
Next at t=0
(0) [0xfffffff0] f000:fff0 (unk. ctxt): jmp far f000:e05b         ; ea5be000f0
<bochs:1> b 0x7c00
<bochs:2> c
(0) Breakpoint 1, 0x00007c00 in ?? ()
Next at t=981593
(0) [0x00007c00] 0000:7c00 (unk. ctxt): cld                       ; fc
<bochs:3> disassemble size = 16
<bochs:4> u/10
00007c00: (                    ): cld                       ; fc
00007c01: (                    ): xor ax, ax                ; 31c0
00007c03: (                    ): mov es, ax                ; 8ec0
00007c05: (                    ): mov ds, ax                ; 8ed8
00007c07: (                    ): mov ss, ax                ; 8ed0
00007c09: (                    ): mov sp, 0x7c00            ; bc007c
00007c0c: (                    ): mov si, sp                ; 89e6
00007c0e: (                    ): mov di, 0x0600            ; bf0006
00007c11: (                    ): mov cx, 0x0100            ; b90001
00007c14: (                    ): rep movsw word ptr es:[di], word ptr ds:[si] ; f3a5
这段代码把代码从0:7c00处的搬移到0:0x600-0x7ff处。
<bochs:6> b 0x7c16
<bochs:7> c
(0) Breakpoint 2, 0x00007c16 in ?? ()
Next at t=982113
(0) [0x00007c16] 0000:7c16 (unk. ctxt): mov bp, di                ; 89fd
<bochs:8> x/4x 0x7c00
[bochs]:
0x00007c00 <bogus+       0>:    0x8ec031fc      0x8ed88ec0      0x7c00bcd0      0x00bfe689
<bochs:9> x/4x 0x600
[bochs]:
0x00000600 <bogus+       0>:    0x8ec031fc      0x8ed88ec0      0x7c00bcd0      0x00bfe689
为什么要搬移呢?因为后面的boot2也会被加载到ox7c00。看来官僚无处不在。

接下来,把0x800开始的16个字节清0,第二个字节置为1,表示我们已经读取了一个分区.
后面会用到这块内存。然后跳转到搬运后的代码0x622处执行:
00007c16: (                    ): mov bp, di                ; 89fd
00007c18: (                    ): mov cl, 0x08              ; b108
00007c1a: (                    ): rep stosw word ptr es:[di], ax ; f3ab
00007c1c: (                    ): inc byte ptr ds:[di+0xfff2] ; fe45f2
00007c1f: (                    ): jmp .+0x8a00              ; e9008a

<bochs:15> info r
eax: 0x0        0
ecx: 0x120000   1179648
edx: 0x80       128
ebx: 0x80       128
esp: 0x7c00     31744
ebp: 0x800      2048
esi: 0x7e00     32256
edi: 0x810      2064
eip: 0x622
eflags 0x202
cs:  0x0
ss:  0x0
ds:  0x0
es:  0x0
fs:  0x0
gs:  0x0
注意,BIOS把磁盘的引导扇区读入到内存之后,其dl的内容表示启动设备,这里是0x80,代表的是第一个物理磁盘的第一个分区。
这里bp的值为0x800,也就是搬移后代码的尾端,我们后面会经常用它加上一个偏移页取值:
_NXTDRV,-0x48      00   # Next drive
_OPT,-0x47         00   # Default option
_SETDRV,-0x46      80   # Drive to force
_FLAGS,-0x45       0F   # Flags
_TICKS,-0x44       B6   # Timeout ticks

以下内容转至:
http://www.lslnet.com/linux/docs/linux-3232.htm

硬盘主引导扇区 = 硬盘主引导记录(MBR)+ 硬盘分区表(DPT)
--------------------------------------------------------------
物理位置:0面0道1扇区(clindyer 0, side 0, sector 1)
大小: 512字节
其中:MBR 446字节(0000--01BD),DPT 64字节(01BE--01FD),结束标志2字节(55 AA)
功能:MBR通过检查DPT分区信息引导系统跳转至DBR;

详解:
000H--08AH MBR启动程序(寻找开机分区)
08BH--0D9H MBR启动字符串
0DAH--1BCH 保留("0")
1BEH--1FDH 硬盘分区表
1FEH--1FFH 结束标志(55AA)


活动分区主引导扇区(DBR)
--------------------------
物理位置:1面0道1扇区(clindyer 0, side 1, sector 1)
大小: FAT16 1扇区 512字节
FAT32 3扇区 1536字节
功能:包含机器CMOS等信息(0000--0059), 核对该信息并引导指定的系统文件, 如NTLDR等;

详解:
000H--002H 3 BYTE的跳转指令(去启动程序, 跳到03EH)
003H--03DH BIOS参数区
03EH--19DH DOS启动程序
19EH--1E5H 开机字符串
1E6H--1FDH 文件名(IO.SYS, MSDOS.SYS)
1FEH--1FFH 结束标记(55AA)


硬盘分区表(DPT)
---------------------
偏移地址 字节数 含义分析
01BE 1 分区类型:00表示非活动分区:80表示活动分区;其他为无效分区。
01BF~01C1 3 *分区的起始地址(面/扇区/磁道),通常第一分区的起始地址开始
于1面0道1扇区,因此这三个字节应为010100
01C2 1 #分区的操作系统的类型。
01C3~01C5 3 *该分区的结束地址(面/扇/道)
01C6~01C9 4 该分区起始逻辑扇区
01CA~01CD 4 该分区占用的总扇区数

注释: * 注意分区的起始地址(面/扇区/磁道)和结束地址(面/扇/道)中字节分配:

00000000 01000001 00010101
~~~~~~~~ ==^^^^^^ ========

~ 面(磁头) 8 位
^ 扇区 6 位
= 磁道 10 位

# 分区的操作系统类型(文件格式标志码)
4---DOS FAT16<32M
5---EXTEND
6---DOS FAT16>32M
7---NTFS(OS/2)
83---LINUX>64M

DPT 总共64字节(01BE--01FD), 如上所示每个分区占16个字节, 所以可以表示四个分区, 这也
就是为什么一个磁盘的主分区和扩展分区之和总共只能有四个的原因.

以上是引导扇区的一些基础知识,我们需要关注的是DPT:
<bochs:43> x/16x 0x7dbe
[bochs]:
0x00007dbe <bogus+       0>:    0x00010180      0xffff0fa5      0x0000003f      0x001ffdc1
0x00007dce <bogus+      16>:    0x00000000      0x00000000      0x00000000      0x00000000
0x00007dde <bogus+      32>:    0x00000000      0x00000000      0x00000000      0x00000000
0x00007dee <bogus+      48>:    0x00000000      0x00000000      0x00000000      0x00000000
这里,我们可以看到,只有一个分区,而且是活动分区,操作系统的类型是a5,其它的我们暂时不用关注。
如果我们用hexdump查看系统的/boot/boot0,会发现在0x1be偏移处的64个字节都是0,难道是没有分区表吗?
不是的,因为真正用到的boot0是写在磁盘内的,分区表信息是fdisk写进去的。可以用dd来查看:
dd if=/dev/md0s1 of=log bs=512 count=1

好了,我们继续来看:
        testb $0x20,_FLAGS(%bp)     # Set drive number?
        jnz main.1          # Yes
        testb %dl,%dl           # Drive number valid?
        js main.2           # Possibly (0x80 set)
查看flag,其值为0x0F,不会跳转;bl的值为0x80,我们来看它的“笨猪跳”:

main.2: movb %dl,_FAKE(%bp)     # Save drive number
        callw putn          # To new line
        pushw %dx           # Save drive number
保存代表启动分区的0x80到0x800,在屏幕上打印一个换行

        movw $(partbl+0x4),%bx      # Partition table (+4)
        xorw %dx,%dx            # Item number
main.3:     movb %ch,-0x4(%bx)      # Zero active flag (ch == 0)
        btw %dx,_FLAGS(%bp)     # Entry enabled?
        jnc main.5          # No
现在要开始检测分区表了,partbl的基址是0x7BE,为什么要用它的值加4赋给bx呢?
这时为了在4次循环后能产生一个进位信号,从而退出循环,后面可以看到(0x7BE+4=0x7c2,每次循环加0x10)

main.3:     movb %ch,-0x4(%bx)      # Zero active flag (ch == 0)
        btw %dx,_FLAGS(%bp)     # Entry enabled?
        jnc main.5          # No
ch的值为0,我们把标志分区活动的位清0,因为后面我们还会重写该值。

        movb (%bx),%al          # Load type
        movw $tables,%di        # Lookup tables
        movb $TBL0SZ,%cl        # Number of entries
        repne               # Exclude
        scasb               #  partition?
        je main.5           # Yes
把操作系统的类型加载到al,值为0xa5,然后查表,来判断类型。tables(0x0787)定义如下:
tables:
        .byte 0x0, 0x5, 0xf
        .byte 0x1, 0x6, 0x7, 0xb, 0xc, 0xe, 0x83
        .byte 0x9f, 0xa5, 0xa6, 0xa9
        .byte os_dos-.          # DOS
        .byte os_dos-.          # DOS
        .byte os_dos-.          # Windows
        .byte os_dos-.          # Windows
        .byte os_dos-.          # Windows
        .byte os_dos-.          # Windows
        .byte os_linux-.        # Linux
        .byte os_bsd-.          # BSD/OS
        .byte os_freebsd-.      # FreeBSD
        .byte os_bsd-.          # OpenBSD
        .byte os_bsd-.          # NetBSD
        .byte os_misc-.         # Unknown
其中前3个是无效的,这里TBL0SZ为3,就是先看该类型是否无效,如果是就检测下一个分区。
我们是0xa5,不用怕!

        movb $TBL1SZ+1,%cl      # Number of entries
        repne               # Locate
        scasb               #  type
        addw $TBL1SZ-1, %di     # Adjust
        movb (%di),%cl          # Partition
        addw %cx,%di            #  description
        callw putx          # Display it
接下来检测有效的分区类型,scasb结束时di指向的是0xa6,TBL1SZ为11,加上9刚好指向os_freebsd。
os_freebsd: .ascii "Free"
os_bsd:     .ascii "BS";   .byte 'D'|0x80
<bochs:63> x/8c 0x7a9
[bochs]:
0x000007a9 <bogus+       0>:  F    r    e    e    B    S   \xC4  f
接着调用putx打印出如下一行:
F1   FreeBSD
这里有个技巧,最后一个字节保存的是'D'和0x80或的结果,这是为了打印字符串的时候标志结束。打印时会
把这个0x80给去掉的。

main.5:     incw %dx            # Next item
        addb $0x10,%bl          # Next entry
        jnc main.3          # Till done
dx用于标志Fx中的'x',需要加1;bl指向的是分区表,加上16个字节,如果没有进位,则跳转到main.3,继续
分析其它的分区表。这里我们可以知道,该循环会执行4次。由于后3个type都为0x0,所以会在无效类型处直接
进入下一个循环。

        popw %ax            # Drive number
        subb $0x80-0x1,%al      # Does next
        cmpb NHRDRV,%al         #  drive exist? (from BIOS?)
        jb main.6           # Yes
这里是为了检测磁盘是否有效。恢复先前保存的磁盘号(0x80),减去0x79得到1,NHRDRV(0x475)处是bios保存的
磁盘数目[FIXME],这里为1
<bochs:8> x/b 0x475
[bochs]:
0x00000475 <bogus+       0>:    0x01

        decw %ax            # Already drive 0?
        jz main.7           # Yes
判断是否为第0个磁盘,这里我们会跳转。

main.7:     movw $prompt,%si        # Display
        callw putstr            #  prompt
        movb _OPT(%bp),%dl      # Display
        decw %si            #  default
        callw putkey            #  key
这里打印Default:  F1


main.10:    movb $ASCII_BEL,%al     # Signal
        callw putchr            #  beep!
        xorb %ah,%ah            # BIOS: Get
        int $0x1a           #  system time
        movw %dx,%di            # Ticks when
        addw _TICKS(%bp),%di        #  timeout
beep一下,引起你的注意,然后取得当前系统时间,加上_TICKS(0xB6)作为循环等待结束的时间。
然后就是检测用户是否输入并判断是否有效,超时则启动default,不细说了。

main.13:    pushw %bx           # Save
        testb $0x40,_FLAGS(%bp)     # No updates?
        jnz main.14         # Yes
        movw $start,%bx         # Data to write
        movb $0x3,%ah           # Write sector
        callw intx13            #  to disk
main.14:    popw %si            # Restore
        popf                # Restore
这里把信息重新写入MBR,这样可以保存您选择的结果。

main.15:    movw $LOAD,%bx          # Address for read
        movb $0x2,%ah           # Read sector
        callw intx13            #  from disk
        jc main.10          # If error
        cmpw $MAGIC,0x1fe(%bx)      # Bootable?
        jne main.10         # No
        movw $crlf,%si          # Leave some
        callw puts          #  space
        jmp *%bx            # Invoke bootstrap
加载所选分区的bootsector(boot2)到0x7c00,检测最后一个world是否为0xaa55。
打印一个空格,然后跳转到0x7c00执行。

[ 本帖最后由 qiuhanty 于 2007-10-14 18:17 编辑 ]

论坛徽章:
0
2 [报告]
发表于 2007-10-14 23:25 |只看该作者
好文呀!必须要支持,以前关于boot0,看的都是源代码,没想过去调试它!

论坛徽章:
0
3 [报告]
发表于 2007-12-04 22:34 |只看该作者
顶一下,继续啊,搞个连载吧!

论坛徽章:
2
丑牛
日期:2013-09-29 09:47:222015七夕节徽章
日期:2015-08-21 11:06:17
4 [报告]
发表于 2007-12-05 08:11 |只看该作者
转载到www.bsdlover.cn,呵呵
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP