org 7c00h
segment .text
bits 16
start:
jmp short main
nop
首先两句定义整个代码的运行位置,org 7C00H指示整个代码的其实位置在7C00处,这样可以减少不必要的便宜运算。也就是整个MBR加载到系统之后不存在偏移。而后面的bits 16则是表明整个代码段都是16位对齐,start后面是MBR的开始,这一句通过汇编会生成两字节的调整指令和一跳空操作指令。紧跟三条跳转指令后面的是MBR当中的一些属性值。
OEMName db 'MSWIN4.0' ;厂商标志和OS版本号
BytesPerSector dw 512 ;每扇区的字节数
SectsPerCluster db 1 ;每簇的扇区数
ReservedSectors dw 1 ;第一个FAT开始之前的扇区数,包括引导扇区
NumberOfFats db 2 ;该分区上FAT的副本数
MaxRootEntries dw 0 ; 对FAT32分区而言,本字段必须设置为 0
TotalSectors dw 0 ; 对FAT32分区而言,本字段必须设置为 0
MediaDescriptor db 0f8h ; 媒体被类型信息,值0xF8表示硬盘
SectorsPerFat dw 0 ; 对FAT32分区而言,本字段必须设置为 0
SectorsPerTrack dw 18 ;包含使用INT13h的磁盘的“每道扇区数”几何结构值
NumberOfHeads dw 2 ;使用INT 13h的磁盘的“磁头数”几何结构值
HiddenSectors dd 0 ;分区上引导扇区之前的扇区数
TotalSectorsBig dd 0 ;全部扇区
SectorsPerFatBig dd 0 ;只被FAT32使用,该分区每个FAT所占的扇区数
ExtendedFlags dw 0 ;此域为FAT32特有。Bits0-3: 活动的FAT(active FAT)数目,只在镜像禁止时才效。Bits 4-6: 保留Bits 7: 0 表示FAT实时镜像到所的FAT表中
;1 表示只一个活动的FAT表。这个表就是Bits0-3所指定的那个
;Bits8-15: 保留
FSVersion dw 0 ;此域为FAT32特有
RootDirStartCluster dd 0 ;根目录所在第一个簇的簇号
FSInfoSector dw 0 ;只供FAT32使用, FAT32分区的保留区中的文件系统信息
BackupBootSector dw 6 ;如果不为0,表示在保留区中引导记录的备份数据所占的扇区数,通常为6
Reserved1 times 12 db 0 ;12个字节均为0x00 保留
BootDrive db 80 ;用于BIOS中断0x13得到磁盘驱动器参数,0x00为软盘,0x80为硬盘
Reserved db 0 ;保留
ExtendSig db 29h ;段必须要有能被Windows 2000所识别的值0x28或0x29
SerialNumber dd 00000000h ;在格式化磁盘时所产生的一个随机序号,它有助于区分磁盘
VolumeLabel db 'NO NAME ' ;卷标也作为一个特殊的文件(有文件名无文件内容)保存在根目录中
FileSystem db 'FAT32 ' ;通常设置为“FAT32”
通过后面的注释,还不能对整个属性有一个大概的了解。并且在在上面的属性当中实际有些数值是不正确的,比如BootDrive,实际上MBR有一些信息是在系统安装的时候进行填写,这里只是为了占位符,所以填入的是0,接下来是开头位置的jmp指令的main标号。(具体的FAT分析可以参考FAT手册)
main:
00007C5A 33C9 xor cx,cx
00007C5C 8ED1 mov ss,cx ;
00007C5E BCF47B mov sp,0x7bf4 ; 首先设置段寄存器和相应的堆栈,注意这里的堆栈式向下增长的,所以当sp设置为7c00的时候不会覆盖掉代码段
00007C61 8EC1 mov es,cx
00007C63 8ED9 mov ds,cx
00007C65 BD007C mov bp,0x7c00 ;这里SP不等于BP,其中BP和SP之间的数据用于局部变量
00007C68 884E02 mov [bp+0x2],cl ;这里bp+2实际上是最开头的第三个nop指令
;**********************************************************************
00007C6B 8A5640 mov dl,[bp+BootDrive]
00007C6E B408 mov ah,0x8
00007C70 CD13 int 0x13 ;获取整个磁盘的参数
00007C72 7305 jnc drive_param_ok ; 这一条跳转应该不陌生了吧,INT13调用会设置进位标志
drive_param_error:
00007C74 B9FFFF mov cx,0xffff ; We couldn't determine the drive parameters
00007C77 8AF1 mov dh,cl ; So just set the CHS to 0xff
drive_param_ok:
00007C79 660FB6C6 movzx eax,dh ;将获得的参数数据用于计算整个磁盘的大小,假设没有跳转的话,下面的inc指令将使得整个ax溢出,也就是ax为0,所以整个大小为0
00007C7D 40 inc ax ; BIOS的int 13进行读取磁盘的数据操作,功能08H 功能描述:读取驱动器参数
00007C7E 660FB6D1 movzx edx,cl ; 入口参数:AH=08H,DL=驱动器,00H~7FH:软盘;80H~0FFH:硬盘
00007C82 80E23F and dl,0x3f ; 出口参数:CF=1——操作失败,AH=状态代码,参见功能号01H中的说明,否则, BL=01H — 360K;=02H — 1.2M;=03H — 720K;=04H — 1.44M
00007C85 F7E2 mul dx ; CH=柱面数的低8位 ; CL的位7-6=柱面数的该2位 ;CL的位5-0=扇区数 ;DH=磁头数
;上面的mul指令执行之后,数据dx:ax存放的是磁头数目*扇区数目
00007C87 86CD xchg cl,ch ; 两个寄存器交换之后,CX向右移动六位就可以得到柱面数
00007C89 C0ED06 shr ch,0x6 ;
00007C8C 41 inc cx ;
00007C8D 660FB7C9 movzx ecx,cx
00007C91 66F7E1 mul ecx ; 柱面数*先前的结果得到最终磁盘驱动器的大小,并保存到局部变量当中
00007C94 668946F8 mov [bp-0x8],eax ;
00007C98 837E1600 cmp word [bp+TotalSectors],byte +0x0 ;
00007C9C 7538 jnz print_ntldr_error_message ;
00007C9E 837E2A00 cmp word [bp+FSVersion],byte +0x0 ; 上面进行MBR的属性分析,如果属性不满足则打印出错信息
00007CA2 7732 ja print_ntldr_error_message ;
/*****************************************************************
整个FAT32文件系统支持多系统启动的,而FAT32真正的boot sector有三个扇区长,所以微软对FAT32的启动进行了扩展,其中扇区0是传统的MBR,扇区1保存的是文件系统信息
扇区2用于存放额外的启动代码。为了实现多系统启动,所以就约定将win2k的boot sector存放到第十三个sector,前面的第二个sector用于存放98的boot
00007CA4 668B461C mov eax,[bp+HiddenSectors] ; Get the count of hidden sectors
00007CA8 6683C00C add eax,byte +0xc ; Add 12 to that value so that we are loading the 13th sector of the volume
00007CAC BB0080 mov bx,0x8000 ; Read the sector to address 0x8000
00007CAF B90100 mov cx,0x1 ; Read just one sector
00007CB2 E82B00 call read_sectors ; Read it
00007CB5 E94803 jmp 0x8000 ; Jump to the next sector of boot code
print_disk_error_message:
00007CB8 A0FA7D mov al,[DISK_ERR_offset_from_0x7d00]
putchars:
00007CBB B47D mov ah,0x7d
00007CBD 8BF0 mov si,ax ;这一段实际上是组装整个四,其中si等于7dbf,最后面的代码到了7d6f,然后ret本身一个字节,
get_another_char: ;后面的NTLDR包含11字节,filter包含49字节,同时filter的0可以作为NTLDR的结尾符号;NTLDR_ERR包含19字节,那么7DBF刚好指向DISK_ERR
00007CBF AC lodsb
00007CC0 84C0 test al,al
00007CC2 7417 jz reboot ;如果数据等于0,则直接重启
00007CC4 3CFF cmp al,0xff ;最后这里会设置零标志位
00007CC6 7409 jz print_reboot_message
00007CC8 B40E mov ah,0xe
00007CCA BB0700 &n