02年刚学汇编语言时写的一个小程序,并投稿至《计算机爱好者》杂志,结果被退稿(好没面子),一直没有机会展现在世人面前,今天抖胆发出来,实现自己多年的夙愿,各位看官见笑了!
我们知道硬盘的0磁头0柱面1扇区为硬盘的主引导扇区,它又分为主引导记录(MBR) 和分区表(DPT)一共512字节。其中前446字节为主引导记录,接着是分区表,起始地址为第1BEH字节,占16×4=64字节(主分区和扩展分区最多有四个,每个分区记录占16个字节),剩下的二个字节是结束标志,恒定为55H、AAH。分区表是记录硬盘的分区情况,如标记活动分区的地址、各分区的起始扇区、结束扇区、分区的大小等。通过修改分区表我们最可以实现安装多操作系统及多重启动。主引导记录其实就是一段程序,它的作用是在硬盘启动时检测分区表的完整性及引导活动分区的操作系统。如果我们用自己的程序代替主引导记录,那么我们就可以在硬盘启动时为所欲为了,例如加上一个启动密码。
现在我们来分析一下硬盘的启动流程,假定BIOS设定为从硬盘启动:
开机时BIOS程序先检测分区表的有效性,如果分区表有问题,比如没有结束标志,则按照BIOS设定启动的驱动器顺序依次去引导。否则把主引导扇区加载到内存的0:7C00H 处,并跳到0:7C00H去运行主引导程序。
在硬盘的0磁头0柱面除了第1个扇区(主引导扇区)外,其它的扇区基本上是无用的,我们所要做的事情就是先找到一个全为0的空扇区,可以用KV300的F6功能或NORTON D- ISKEDIT等磁盘工具去查找 ,然后把主引导扇区搬到这个扇区,再把自己的程序连同原分区表一起加载到0磁头0柱面1扇区。读写扇区的工作可以调用BIOS的13号中断的2、3子功能来完成。
接下来替代主引导记录的程序则可以按如下步骤编写:
(1) 初始化堆栈和各寄存器
(2)把主程序搬移到0:61BH处,为以后要加载的主引导扇区腾出空间
(3)跳到0:61BH处继续运行
(4)显示密码框及输入、判断密码,如密码正确则跳到(5),否则重复(4)
(5)把备份的主引导扇区读到0:7C00H处
(6)跳到0:7C00H处运行
下面就把以上的步骤结合起来,写一个完整的程序,源程序用汇编语言编写,并连接成COM程序,在使用前请先备份分区表,否则若出现什么问题那可就多多得罪了。
cseg segment
assume cs:cseg,ds:cseg,es:cseg,ss:cseg
org 100h
main proc near
jmp start
sector db 200h dup(0);存放扇区数据,长度为512字节
n dw 8 ;n为空扇区的扇区号,可以用磁盘工具找到
start:
mov ax,201h
lea bx,sector
mov cx,1
mov dx,80h
int 13h ;读主引导扇区数据
mov ax,301h
mov cx,n
int 13h ;备份主引导扇区的数据到空扇区
lea si,my_code
lea di,sector
mov cx,1beh
cld
rep movsb ;把密码程序的前1BEH字节移到sector,
;对原来的分区表不作更改
mov ax,301h
inc cx
int 13h ;把sector中的数据写到硬盘的主引导扇区
int 20h ;程序结束
org 600h ;把下面的程序EA定义到600H处,这样所有变量
;和标号在内存中的相对位址也就确定了
main endp
;---------------------------------------------------
my_code proc near
xor ax,ax
mov ss,ax
mov sp,7c00h ;堆栈设在0:7C00H处
sti
push ax ;ES=DS=AX=0
pop es
push ax
pop ds
cld
mov si,7c1bh ;把password_start以下的程序搬到0:61BH处
;因为在引导时下面程序的EA为7C1BH,
;所以这里填上立即数
mov di,61bh
push ax
push di
mov cx,1e5h
rep movsb
retf ;跳到password_start去执行
password_start:
lea di,buffer ;清除键盘缓冲区,di为缓冲区指针,buffer在后面定义
push di
xor al,al
mov cx,8
rep stosb
pop di
mov ax,600h
mov bx,7000h
mov cx,0b1ch
mov dx,0d34h
int 10h ;把sector中的数据写到硬盘的主引导扇区
mov ah,13h
xchg bh,bl
mov cx,0fh
mov dx,0c1dh
lea bp,string
int 10h ;把sector中的数据写到硬盘的主引导扇区
mov ah,2
xor bh,bh
add dx,0fh
int 10h ;设置光标位置
in_key:
xor ah,ah ;键盘输入
int 16h
cmp ah,1ch
jz check ;回车则跳去检查密码
cmp di,offset buffer+8
jz in_key ;密码最多8位,如缓冲区满则不再接受字符
stosb ;把输入字符的ASCII码存入缓冲,di+1
mov ax,0e2ah ;在光标置显示"*",光标右移
int 10h
jmp in_key ;继续等待键盘输入直至按回车
check:
lea si,buffer ;SI指向键盘缓冲区首地址
xor bx,bx ;BX清零
mov cx,8 ;循环次数为8次
add_loop:
lodsb ;把(SI)装入AL,并SI+1
mul cl ;AX=AL*CL
add bx,ax ;BX=BX+AX
loop add_loop ;循环直到CX=0
xor bx,password
jnz password_start;如密码错误则重新输入
mov ah,2
xor bx,bx
mov dx,1700h
int 10h ;设置光标位置到屏幕的24行1列
mov ax,201h
lea bx,7c00h
mov cx,8
mov dx,80h
int 13h ;把备份的主引导扇区加载到0:7C00H处
;这里的CX与上面的n对应,但必须填入立即数
jmp bx ;跳到0:7C00H
my_code endp
;--------------------------------------------------
buffer db 8 dup(0);键盘缓冲区,密码最多为8位
password dw 738h ;密码的值,即密码为12345678
string db 'Enter password:';提示字符
org 7beh ;把下面指令的EA设置为7BEH,使这段程序填满1BEH字节
nop
cseg ends
end main
这个程序功能比较简单,只能在引导时启用口令,对磁盘的文件则没有加密的效果,且没有更改密码的功能。小弟只在这里提出一条思路,各位朋友可以发挥想象力,写出更好的程序.此程序的初始密码为12345678,如果想修改密码则可以按以下公式进行计算:password=N1*8+N2*7+N3*6+……N8*1。其中N1为第一个字符的ASCII码,N2为第二个字符的ASCII码,以此类推,如果密码不足8位则只计算前面几位即可,然后把相加的结果存入源程序的password区再进行汇编连接并运行。使用时还要注意一点:这个程序只能使用一次,如果运行第二次开机时会出现死循环,除非在运行第二次前已经恢复了主引导扇区的数据。