标签:
搞了三天,总算把那个虫子找到了,可以写出来了。
引导扇区只有 512 字节,太小,基本啥也干不了,我们只能利用引倒扇区把我们的操作系统内核载入内存。但是一下子把内核全部载入进来也不靠谱,还有很多事情没做呢——起码就还没转到安全模式,内核大的话,实模式可装不下。所以正确的姿势是:引导扇区载入一个装载程序,装载程序负责做好准备工作后,再载入真正的内核。
那么引导扇区的任务就很明确了:找到装载程序(Loader.bin),然后把它载入内存。第十天初识FAT12时提到了:通过根目录表项找到文件的第 1 个扇区,再从 FAT 表中找到其他的扇区。代码有很详细的注释:
; BootSector.nas ; 引导扇区 ; 四彩 ; 2015-11-11 ; ======================================================================================== ; 电脑的启动过程: ; 1、PC 通电启动后,CPU 马上跳到系统 BIOS 中的启动代码处。 ; 2、系统 BIOS 的启动代码首先进行硬件检查,并加载相关硬件设备。 ; 3、检查完成后,把用户指定磁盘的第一个扇区读到内存 0x7C000 处,然后转交控制权。 ; 4、操作系统就从内存 0x7C00 处开始接管电脑。 ; 5、内存0x7E00 ~ 0x9FBFF 未定义,由操作系统使用。 ; **************************************************************************************** [SECTION .text] ; ======================================================================================== ; 头文件及常量定义 ; ---------------------------------------------------------------------------------------- %include "./Boot/INC/FAT12.inc" ; ---------------------------------------------------------------------------------------- AbsMemAddrOfBoot equ 0x7C00 ; BootSector 被加载到内存的绝对地址 SegAddrOfLoader equ 0x7E00 ; LOADER.BIN、临时数据被加载到内存的段地址 OffsetOfLoadLoader equ 1024 ; LOADER.BIN 被加载到内存的偏移量 OffsetOfLoadTemp equ 0 ; 临时数据被加载到内存的偏移量(最多 2 个扇区) ; ---------------------------------------------------------------------------------------- org AbsMemAddrOfBoot ; **************************************************************************************** ; ======================================================================================== ; FAT12 文件系统引导扇区的头部(前 62 字节) FAT12Head _main, "NASM+GCC", "TestX_v0.01" ; **************************************************************************************** ; ======================================================================================== ; FAT12 文件系统引导扇区的引导代码(从第 62 字节开始) ; ---------------------------------------------------------------------------------------- ; 程序入口 _main: ; 初始化寄存器 mov ax, cs mov bp, ax mov ds, ax mov ax, SegAddrOfLoader mov es, ax cld ; 寻找 Loader.bin call SearchLoaderFirstSector ; 加载 Loader.bin mov bx, OffsetOfLoadLoader call LoadLoader ; 控制权交给已加载到内存的 loader jmp SegAddrOfLoader : OffsetOfLoadLoader ; 以下定义子函数 ; ---------------------------------------------------------------------------------------- ; 函数功能:寻找 loader 文件的起始扇区 ; 入口参数:ds : si = loader 文件名的存放地址 ; 出口参数:eax = loader 文件的起始逻辑扇区号 ; 寄存器:ax、bx、cx、dx、si SearchLoaderFirstSector: push bp mov bp, sp sub sp, 2 * 4 ; 32 位通用寄存器长 4 字节 ; 待读取的根目录区逻辑扇区号 mov ax, IRootDirectoryFirstSector mov [bp + 2 * 4], ax ; 待查找的根目录区扇区数 mov ax, IDataFirstSector - IRootDirectoryFirstSector mov [bp + 3 * 4], ax ; 逐个扇区寻找 .Search_NextSector: mov ax, [bp + 2 * 4] mov bx, OffsetOfLoadTemp call Read1Sector ; cx 统计一个扇区内未匹配的表项数 mov cx, 16 ; = [BPB_BytsPerSec] / DirectoryItem_size .Search_ThisSector: ; 匹配文件名 mov si, LoaderFileName mov dx, 11 ; dx 统计未匹配的文件名字符数 .Match_FileName: mov al, byte[ds : si] mov ah, byte[es : bx] cmp al, ah jnz .Match_NextItem dec dx cmp dx, 0 jz .Found inc bx inc si jmp .Match_FileName .Match_NextItem: and bx, 0b1111111111100000 ; 回当前表项的开始处 add bx, 32 ; 指向下一个表项(一个表项 32 字节,占用 5 位) loop .Search_ThisSector ; 判断是否读完根目录区所有扇区:读完说明没找到,没读完就继续下一个 dec word[bp + 3 * 4] cmp word[bp + 3 * 4], 0 jz .NotFound inc word[bp + 2 * 4] jmp .Search_NextSector .NotFound: call PrintMSG db "Failed to search Loader.bin !", `\r\n`, 0 jmp $ .Found: mov ax, word[es : bx + 16] ; 指向当前表项中的 .DIR_FstClus(26 - 11 + 1) add ax, IDataFirstSector - 2 add sp, 2 * 4 pop bp ret ; ---------------------------------------------------------------------------------------- ; 函数功能:从软盘装载文件到内存 ; 入口参数:ax = 该文件第一个逻辑扇区号 ; es : bx = 存放数据的内存缓冲区地址 ; 出口参数:无 ; 寄存器:ax、bx,cx、dx LoadLoader: push bx push ax call Read1Sector pop ax call GetNextSector pop bx cmp ax, 0xFF8 ; FAT 表项的值大于等于 0xFF8,表示文件结束 jae .Return add ax, IDataFirstSector - 2 ; FAT 表项的序号 2 对应数据区第 1 个扇区 add bx, [BPB_BytsPerSec] jmp LoadLoader .Return: ret ; ---------------------------------------------------------------------------------------- ; 函数功能:取得逻辑扇区在 FAT 表中的表项值 ; 入口参数:ax = 逻辑扇区号 ; 出口参数:ax = 对应的 FAT 表项值(即下一个扇区的序号) ; 寄存器:ax、bx、dx,cx GetNextSector: push bp mov bp, sp sub sp, 4 ; 保存 FAT 表项号的奇偶性(0 = 偶数,1 = 奇数) mov dword[bp + 2 * 4], 0 ; 计算逻辑扇区号 ax 在 FAT 表中的表项号(ax * 12 / 8) xor dx, dx sub ax, IDataFirstSector - 2 mov bx, 12 mul bx mov bx, 8 div bx ; 校验 FAT 表项号的奇偶性 cmp dx, 0 jz .Label_GetNextSector_1 mov dword[bp + 2 * 4], 1 .Label_GetNextSector_1: ; 计算该表项号所在的逻辑扇区号和在该扇区的偏移量 xor dx, dx mov bx, [BPB_BytsPerSec] div bx push dx add ax, [BPB_RsvdSecCnt] ; 读取连续 2 个扇区(表项可能跨扇区) push ax mov bx, OffsetOfLoadTemp call Read1Sector pop ax inc ax add bx, [BPB_BytsPerSec] call Read1Sector ; 根据偏移量读出 16 位,奇数项去掉低 4 位,偶数项去掉高 4 位,得到相应的 12 位项值 ; —— FAT 表前面 3 个字节记录信息占用了 2 个 序号(第一个有效序号 2 从字节 3 开始) pop bx ; 上面压进去的 dx 值(偏移量) mov ax, [es : bx] cmp dword[bp + 2 * 4], 0 jz .Label_GetNextSector_2 shr ax, 4 .Label_GetNextSector_2: and ax, 0b0000111111111111 ; 奇数项高 4 位已为 0 执行此操作值也不变 add sp, 4 pop bp ret ; ---------------------------------------------------------------------------------------- ; 函数功能:从软盘读取 1 个逻辑扇区 ; 入口参数:ax = 起始逻辑扇区号 ; es : bx = 存放数据的内存缓冲区地址(同 int 0x13、ah = 2) ; 出口参数:同 int 0x13、ah = 2 ; 寄存器:ax、cx、dx Read1Sector: ; 由 LBA 计算 CHS mov dl, 18 div dl mov ch, al mov dh, al mov cl, ah shr ch, 1 inc cl and dh, 1 ; 读一个扇区 mov ax, 0x0201 xor dl, dl int 0x13 ; cmp ah, 0 ; 虚拟软盘不会出错 ; jz .Return ; call PrintMSG ; db "Error to read Floppy Disk !", `\r\n`, 0 ; jmp $ ;.Return: ret ; ---------------------------------------------------------------------------------------- ; 函数功能:显示紧跟在调用指令后定义的字符串 ; 入口参数:无 ; 出口参数:无 ; 寄存器:ax、bx、si PrintMSG: mov ah, 0x0e ; 功能号:0x0E 显示字符,光标跟随字符移动 xor bx, bx ; bh = 页码,bl = 前景色(图形模式) .Loop: ; 逐个取字符 pop si lodsb push si cmp al, 0 ; 字符串以 0 结尾 je .Return int 0x10 jmp .Loop .Return: ret ; **************************************************************************************** ; ======================================================================================== ; FAT12 文件系统引导扇区引导代码的剩余部分用 0 填满 times 497 - ($ - $$) db 0 LoaderFileName db "LOADER BIN", 0, 0 ; loader 文件名(8 + 3格式,长度不够的填空格) ; **************************************************************************************** ; ======================================================================================== ; FAT12 文件系统引导扇区的的结束标志(最后 2 字节,必须是 0xAA55) dw 0xAA55 ; ****************************************************************************************
; FAT12.inc ; FAT12 文件系统常量及宏定义 ; 四彩 ; 2015-11-08 ; ======================================================================================== IRootDirectoryFirstSector equ 19 ; 根目录区的起始逻辑扇区号 IDataFirstSector equ 33 ; 数据区的起始逻辑扇区号 ; **************************************************************************************** ; ======================================================================================== ; FAT12 文件系统的引导扇区头部(前 62 字节)格式宏 ; 调用格式:FAT12Head Label_RealEntry, OEMName, VolLab ; Label_RealEntry : 程序入口标签 ; OEMName : 厂商名称(8 字节长,不够的填空格) ; VolLab : 卷标(11 字节长,不够的填空格) %macro FAT12Head 3 ; 名称 偏移 长度 内容 3.5英寸软盘值 jmp %1 ; 0 3 跳转指令,指向程序入口 jmp Label_RealEntry nop BS_OEMName db %2 ; 3 8 厂商名称 自行定义 BPB_BytsPerSec dw 512 ; 11 2 每扇区字节数 512 BPB_SecPerClus db 1 ; 13 1 每簇扇区数 1 BPB_RsvdSecCnt dw 1 ; 14 2 保留扇区数 1 BPB_NumFATs db 2 ; 16 1 FAT表份数 2 BPB_RootEntCnt dw 224 ; 17 2 根目录中最多容纳的文件数 224 BPB_TotSec16 dw 2880 ; 19 2 扇区总数 (FAT12、16) 2880 BPB_Media db 0xF0 ; 21 1 介质描述符 0xF0 BPB_FATSz16 dw 9 ; 22 2 每个FAT表所占的扇区数 9 BPB_SecPerTrk dw 18 ; 24 2 每磁道扇区数 18 BPB_NumHeads dw 2 ; 26 2 磁头数 2 BPB_HiddSec dd 0 ; 28 4 隐藏扇区数 0 BPB_TotSec32 dd 2880 ; 32 4 扇区总数(FAT32) 2880 BS_DrvNum db 0 ; 36 1 磁盘驱动器号 0 BS_Reserved1 db 0 ; 37 1 保留(供NT使用) 0 BS_BootSig db 0x29 ; 38 1 扩展引导标记 0x29 BS_VolD dd 0 ; 39 4 卷标序列号 0 BS_VolLab db %3 ; 43 11 卷标 自行定义 BS_FileSysType db ‘FAT12‘ ; 54 8 文件系统类型名 FAT12 ; 62 448 引导代码、数据及其他填充字符 ; 510 2 结束标志 0xAA55 ; ; BPB:BIOS Parameter Block,BIOS 参数块;BS:Boot Sector,引导扇区 %endmacro ; **************************************************************************************** ; ======================================================================================== ; 目录表项结构 struc DirectoryItem .DIR_Name resb 11 ; 文件名 8 字节,扩展名 3 字节 .DIR_Attr resb 1 ; 文件属性 resb 10 ; 保留 .DIR_WrtTime resw 2 ; 最后修改时间 .DIR_WrtDate resw 2 ; 最后修改日期 .DIR_FstClus resw 2 ; 此条目对应的开始簇号 .DIR_FileSize resd 4 ; 文件大小 endstruc ; ****************************************************************************************
标签:
原文地址:http://my.oschina.net/u/580100/blog/528955