请大家做这样一个实验:首先利用DEBUG编制这样一小段程序:
C:\ASM\>DEBUG[Enter] -A100[Enter] 0BFB:0100 MOV AX,0003 0BFB:0103 INT 10 0BFB:0105 MOV AX,0000 0BFB:0108 MOV DS,AX 0BFB:010A MOV SI,7C1B 0BFB:010D CLD 0BFB:010E LODSB 0BFB:010F OR AL,AL 0BFB:0111 JZ 0119 0BFB:0113 MOV AH,0E 0BFB:0115 INT 10 0BFB:0117 JMP 010E 0BFB:0119 JMP 0119 0BFB:011B DB 'Hello,cowboy!!!',0d,0a,07,0 0BFB:012E [Enter]
而后将这一小段程序写入A盘的0面0磁道第一扇区中,将磁盘中原有内容覆盖。这里介绍一个简单的方法,使用DEBUG提供的"W"命令。"W"命令我们前面讲过,它用于将编制的程序保存到文件中之中。这里我们要介绍它的另一个功能,即将内存中的一段内容保存到磁盘的某一扇区中。这个命令的用法如下:
-W〈起始地址〉 〈驱动器号〉 〈起始逻辑扇区号〉 〈写入扇区数量〉
关于逻辑扇区号我需要做一简单的说明,我们前面说过描述磁盘扇区的方法,即给出"磁头号"、"磁道号"、"扇区号"三个数据描述一个磁盘扇区;注意这是BIOS的规定,也就是说我们在使用BIOS关于磁盘的功能调用时才按照这种方式描述磁盘扇区。而DOS对此规定做了简化,DOS将所有磁盘扇区看作连续的,从0开始进行统一编号,因此对于一片1.44MB的磁盘来说,其0面0磁道第一扇区的"逻辑扇区号"就是0,最后一个扇区的"逻辑扇区号"为17;而其1面0磁道第一扇区的"逻辑扇区号"为18,接在0面0磁道的后头,按照这个规律依次向下排。
将这小段程序正确写入磁盘后即可热启动机器,注意不要从硬盘启动。如果没有什么意外你应该从屏幕上看到这样的一种结果:将机器完成自检之后A驱动器亮了一下,这时屏幕突然被清除,而后在屏幕左上角出现了一段英文信息同时喇叭发出一声鸣叫。注意到了吗,那句英文信息就是程序在偏移地址011B处所给出的。
这确是一个不寻常的现象,它所说明的唯一结论就是我们所编写的那一小段程序在机器启动的时候被执行了一次。事实也确是如此,当BIOS完成机器自检之后它会试图从A驱动器或物理硬盘C上读一个扇区的内容到内存0000:7C00处,这个扇区就是0面0磁道第一个扇区。如果这个扇区正确地读入内存,那么BIOS会通过一条远程转移指令让CPU转移到0000:7C00处继续执行指令,至此BIOS的启动工作便全部完成了,剩下的事就要由磁盘上读入的那些"东西"接替。
对于一片"正常"的软盘而言,其0面0磁道第一扇区内存放着一小段程序,这个程序在运行时会检查它所在的磁盘上是否有DOS系统的两个重要文件"IO.SYS"、"MSDOS.SYS",如果没有,则这段程序就会显示出"Non-system disk or disk error......"这样一段信息;如果这是一片"系统盘",则这段程序就会将"IO.SYS"调入内存,并通过转移指令将系统控制权交给"IO.SYS",由此之后整个系统就由DOS进行控制,这就是DOS的启动过程。
这个过程只是相对软盘而言,硬盘的启动过程要更复杂一些。但是无论从软盘启动或是从硬盘启动,磁盘的0面0磁道第一扇区在系统启动过程中占有重要的地位,它在BIOS自检与DOS开始工作之间起一个承前启后的作用,在技术上我们把这个扇区称为"引导扇区",英文为"BOOT SECTOR"。在短短512个字节的空间内存储了一个精心编制的小程序,称"引导程序",整个操作系统就要由这个程序负责调入,即使是WINDOWS95、WINDOWS-NT这样的操作系统同样离不开引导程序。因此我们说,引导扇区在整个PC系统中占据着十分重要的一环。
引导扇区不仅十分重要,而且十分有趣,甚至可以说是妙趣横生。这是因为无论是ROM BIOS还是DOS等操作系统,对BOOT程序的"合法性"并不作任何检查。也就是说无论什么样的程序,只要它存储在磁盘的BOOT扇区内,都会在操作系统启动之前被调入内存并由CPU执行,我们刚刚做过的那个实验恰好说明了这一点。由于这个原因所以有些人就编制了一些"特殊"的程序取代了合法的引导程序,这些"特殊"的程序在进入内存运行的时候会使用特殊的技巧将自己隐藏在内存的某个"角落"中,并时刻监视系统的运行。一旦时机成熟,它们就会象吃了兴奋剂一样疯狂运行,控制住整个PC系统。或者在屏幕上画个小球来回弹跳,或者将硬盘格式化后在显示一些信息将用户大骂一番,甚至于显示一个征婚广告搅乱用户的视线。这一类特殊的"引导程序"在国际上有一个通用的名字--计算机病毒。可不要小看这一个扇区512个字节的容量,它造就了个人电脑中一项专门的技术--病毒防治。很长一段时期内正邪两股势利在这一扇区中进行过激烈的碰撞,硝烟一直弥漫至今仍未散去。真不知道在大家的系统中是否有计算机病毒,如果你的机器染了毒,那么你在完成前面的实验时就可能会出现很多问题。所以一旦大家发现自己的电脑运行情况与笔者给出的情况有出入,那么建议大家在否定笔者的结论之前能够仔细地思考一番,也许真就是病毒作的怪。
至此我们对操作系统在软盘上的第一个保留扇区已有了一些了解,有关计算机病毒的更多内容大家可以参阅相关书籍。硬盘上0面0磁道第一个扇区也有一个引导程序,但硬盘的"逻辑"构成与软盘不同。因为硬盘是分区存储的,所以硬盘上有多个引导程序。位于0面0磁道第一扇区的引导程序称为"主引导程序"(MAIN BOOT),各个分区的头部各有一个"分区引导程序"。主引导程序的任务就是将"活动"分区的分区引导程序调入内存执行,操作系统的启动运行由活动分区引导程序具体完成。下面给出的这个程序可以将硬盘主引导程序读入内存,我们将读入的数据写入A盘的0面0磁道第一扇区,将软盘的BOOT程序盖掉,大家能推断出用这片软盘引导系统的结果吗?
C:\ASM\>DEBUG[Enter] -A100[Enter] 123D:0100 MOV AH,02 123D:0102 MOV AL,01 123D:0104 MOV DL,80 123D:0106 MOV DH,00 123D:0108 MOV CH,00 123D:010A MOV CL,01 123D:010C MOV BX,0200 123D:010F PUSH CS 123D:0110 POP ES 123D:0111 INT 13 123D:0113 INT 20 -G=100[Enter] -W200 0 0 1[Enter]
对于病毒而言,硬盘的主引导扇区可以说是"兵家必争之地"。所以笔者建议大家在保证系统无毒的情况下将硬盘主引导程序读出保存至文件中,对于以后分析一些"未知"病毒会有帮助。
除了引导扇区之外,在DOS的保留扇区内还有一些值得我们注意的地方。比如下面这个程序所反映的内容:
code segment assume cs:code,ds:code org 100h main proc far mov bx,80h ;BX寄存器指向命令行参数计数值 cmp byte ptr [bx],0 ;没有命令行参数吗? jz exit ;若没有命令行参数,转EXIT结束 add bl,byte ptr [bx] ;BX指向命令行参数末尾 dec bx or byte ptr [bx],20h ;将驱动器名改为小写 cmp byte ptr [bx],'b' ;驱动器名比"B"大吗? ja exit ;若驱动器名大于"B",转EXIT结束 mov dl,byte ptr [bx] ;将驱动器名送入DL寄存器 sub dl,'a' ;并转换成对应的数字 mov di,4 ;准备进行4次操作 loop1: mov ah,2 ;选择扇区读取功能 mov al,3 ;读入3个扇区 mov bx,offset buffer ;BX寄存器指向缓冲区 mov ch,0 ;读0磁道 mov cl,2 ;从第2扇区开始 mov dh,1 ;读磁盘的1面 int 13h jnc disp ;若操作正确,转DISP显示读入的内容 dec di ;若出错,则准备进行一次重试 jnz loop1 ;未做完4次重试,转LOOP1继续 mov ah,9 ;4次读取不成功,显示出错信息 mov dx,offset errmsg int 21h jmp short exit ;结束进程 disp: mov si,bx ;SI寄存器指向读入的数据 mov cx,2 loop2: push cx mov cx,24 loop3: cmp byte ptr [si],0 ;SI寄存器指向的数据为0吗? jz exit ;若为0,转EXIT结束 mov word ptr [si+11],0a0dh ;在[SI+11]处加入回车和换行 mov byte ptr [si+13],'$' ;在回车换行符后加"$"表示字符串结束 mov dx,si ;DX寄存器指向构造好的字符串 mov ah,9 ;显示这个字符串 int 21h add si,32 ;SI寄存器指向后面32个字节 loop loop3 ;处理24个32字节数据组 mov ah,0 ;等待键盘输入 int 16h pop cx ;继续处理读入的数据 loop loop2 exit: mov ah,4ch ;结束进程 int 21h errmsg db 'ERROR!!!',0dh,0ah,24h ;读盘出错信息 buffer db ? ;缓冲区首 main endp code ends end main
此程序的使用稍有复杂,有些象DIR命令,它要求用户给出一个参数A:或B:来指明要对哪个驱动器进行操作。请注意,被操作的驱动器中应该放入一片1.44MB的磁盘。