BIOS中断浅析
作者:lincon
首先,我们介绍一下中断。中断大致可以分为四种类型:
中断类型 中断号 处理器 0--4h
硬件 8--F,70--77h
软件 大部分为int形式,例外:
1)1Dh,1Eh,46h返回在ROM中驻留的硬件参数表格
2)20--3Fh用于DOS
3)5,10--1A,1D--1F,40,41,43,46h用于BIOS
用户 60--67,F1--FF 上表仅是一个粗略的说明,随着中断的发展,一些原先保留
的中断也有了确定的定义。现在所讲的BIOS中断意指中断0--1Fh。
中断程序的执行过程简单说来,即中断程序在中断向量表中查到中断地址后,保存
现场,跳到中断地址执行程序,结束后再恢复现场继续执行中断前的程序。我们调用中
断就与调用一个c程序一样方便。
BIOS固化于ROM中,是其他软件与硬件传递信息的桥梁。以应用的角度看,它的各个
中断程序是我们最感兴趣的。早在DOS时代,就有不少关于BIOS的介绍,那么到了Windo
ws纵横天下的时候,BIOS又有了什么变化和发展呢?下面我们将BIOS中断程序按编程的复
杂度由简单到复杂度选择进行分析。
。
(一)准备工作
一)开机后,BIOS中断程序驻留于内存F0000--FFFFF处,我们可先用DEBUG.EXE 将这
内存的内容复制成一个文件。例如:
C:/>debug.exe
-rbx
BX 0000
:1
-n bios.dat
-w f000:0
Writing 10000 bytes
-q
然后,我们再将内存0:0 --0:700处的内容复制下来。此处主要有中断向量表,所
用到的BIOS数据区和DOS数据区。为了方便查看,以文本形式保存。例如:先编写一个批
处理文件C.bat,其内容为:
@echo d 0:0 700 >temp
@echo q>>temp
type temp|debug.exe >bios.txt
将C.bat执行后,得到一个bios.txt文件。
二)熟悉DEBUG.EXE和PCTOOLS5.0 的用法。它们都是很老的软件了,但对付BIOS 还
是绰绰有余的(当然还有例外,下文将要讲到)。
三)准备一本汇编方面的书籍。上面一般附有BIOS 中断。虽然不太全,但可以作为
参考。如清华大学计算机系教材《IBM-PC汇编语言程序设计》。
四)那就是你必须具有相当熟练的汇编语言的知识,以及对硬件要有一定的了解,如
对8259A,8042 等计算机用到的硬件的端口要有比较清楚的认识,最少也得有一本这方
面的参考书,如我们就参考过《PC系列机系统开发与应用》,《微型计算机原理与汇编
语言》等十几本书籍。
(二)纵览全局
查看bios.txt ,地址0:0-0:700为中断0-1FH入口地址,如下图:
0000:0000 9E 0F C9 00 65 04 70 00-16 00 A4 08 65 04 70 00 ....e.p.....e.
p.
0000:0010 65 04 70 00 54 FF 00 F0-E2 47 00 F0 C8 E6 00 F0 e.p.T....G....
..
0000:0020 00 00 00 CC 28 00 A4 08-6F EF 00 F0 6F EF 00 F0 ....(...o...o.
..
0000:0030 6F EF 00 F0 6F EF 00 F0-9A 00 A4 08 65 04 70 00 o...o.......e.
p.
0000:0040 05 00 75 CC 4D F8 00 F0-41 F8 00 F0 E7 25 53 FD ..u.M...A....%
S.
0000:0050 39 E7 00 F0 40 02 13 02-2D 04 70 00 28 0A 5C 02 9...@...-.p.(.
\.
0000:0060 A4 E7 00 F0 2F 00 65 09-6E FE 00 F0 04 06 5C 02 ..../.e.n.....
\.
0000:0070 1D 00 00 CC A4 F0 00 F0-22 05 00 00 19 4E 00 C0 ........"....N
..
但其中有些地址已经被DOS 修改了。我们可打开bios.dat 查看原来的地址,用PCT
OOLS 打开bios.dat,按F2 ,键入127 ,在相对扇区 127 处,偏移E3-122 的地方查到
原来的地址。我们以大众MVP3主板(VP3-586B-WB77)上的 AWARD BIOS(日期:98年7月2
0日)(注:以下都将以此BIOS为例)为例看一看,如下图:
F000:FEE0 00 0F AA C8 E6 C8 E6 C3-E2 C8 E6 C8 E6 54 FF E2 .............T
..
F000:FEF0 47 C8 E6 A5 FE 87 E9 6F-EF 6F EF 6F EF 6F EF 57 G......o.o.o.o
.W
F000:FF00 EF 6F EF 65 F0 4D F8 41-F8 59 EC 39 E7 59 F8 2E .o.e.M.A.Y.9.Y
..
F000:FF10 E8 D2 EF A4 E7 F2 E6 6E-FE 53 FF 53 FF A4 F0 C7 .......n.S.S..
..
F000:FF20 EF 00 00 5E BB F3 EC 6F-EF 6F EF 6F EF FC F0 6F ...^...o.o.o..
.o
可以看到,确实与0:700处的地址有差别。在127 扇区的结尾处,可看到BIOS 的日
期及机子型号,如:
F000:FFF0 CD 19 E0 00 F0 30 37 2F-32 30 2F 39 38 00 FC AA .....07/20/98.
..
如果你用PCTOOLS 查看各扇区,还可发现一些在CMOS SETUP设置时遇到的提示信息
,如:
F000:0660 00 07 02 16 0B 39 0F 02-05 19 0D 53 41 56 45 20 .....9.....SAV
E
F000:0670 74 6F 20 43 4D 4F 53 20-61 6E 64 20 45 58 49 54 to CMOS and EX
IT
F000:0680 20 28 59 2F 4E 29 3F 20-00 07 02 16 0B 39 0F 02 (Y/N)? .....9.
.
F000:0690 05 1A 0D 51 75 69 74 20-57 69 74 68 6F 75 74 20 ...Quit Withou
t
F000:06A0 53 61 76 69 6E 67 20 28-59 2F 4E 29 3F 20 00 07 Saving (Y/N)?
..
(三)最简单的中断程序
为了提高自信心,我们先来看一看最简单的中断程序是怎样的。
INT 1B,1CH为提供给用户的软中断,即用户如果不对它们进行修改,则它们是仅有
一条IRET指令的程序。
INT 12H功能为检查基本内存容量。程序为
PUSH DS
MOV AX,40
MOV DS,AX
MOV AX,[13]
POP DS
IRET
查看地址0:413H的内容,为280H,即十进制的640K,这说明基本内存为640K。
INT 0,1,3,4,7H 程序为:
E6C8:PUSH DS
PUSH AX
PUAH CX
MOV AX,40
MOV DS,AX
JMP EFBD
EFBD:MOV AH,FF
MOV [6B],AH
POP CX
POP AX
POP DS
IRET
程序仅仅在地址0:46B处填入FF字节。我们知道,单步与断点两中断由DEBUG.EXE接
管和修改的,而其他则由DOS接管。故现在查看一下0:46B,已经不是FF了。
INT 11H的程序为:
JMP EE81
EE81:PUSH DS
MOV AX,40
MOV DS,AX
XOR EAX,EAX
MOV AX,[10]
POP DS
IRET
其中地址0:410H字为设备安装标志,意义为
低字节:7,6位:软驱数量(00:1台;01:2台;10:3台;11:4台)
5,4位:显示模式(01:40*25彩色;10:80*25彩色;11:80*25单色;00:上述以
外)
3,2位:无意义
1位:安装协处理器为1
0位:安装软驱为1
高字节:15,14位:并行口打印机数
13位:无意义
13位:安装游戏适配器为1
11-9位:串行口数
8位:保留
显然,这些中断并没有做很多工作。你是不是没想过BIOS程序也有如此简单呢:
(四)比较简单的中断程序
在这一节,我们将介绍INT 5H以及INT 8H。
INT 5H为打印屏幕中断,其编程思路很简单。程序先做好一些初始化工作,如检查
屏幕打印状态 ,以及通过INT 17H 检查打印机是否忙碌或纸尽。处理好以上过程后,就
开始打印了。打印调用了INT 17H,每调用一次打印一个字符。程序设计了一个二重循环
,内循环判断是否换行,外循环判断是否打印结束。就与一对FOR语句嵌套一样。
总的说来,这个程序并无多少可看之处。不过,我们认为程序中开,关中断指令设
置的巧极了,它们的位置恰好保护了应该不被中断执行的程序段,具有一些"互斥"意味
。此外,打印时还对一些特殊字符进行了过滤,以空格代之打印。
下面,介绍一下INT 8H--定时器中断程序。这里,我们感兴趣的是程序中涉及到了
时间。那么,它又是如何解决"千年虫"的问题的?原来,程序设置了一个子过程,它将年
代的高两位取出,判断是否为"19XX ",如果不是,则可认为是"20XX"年了;如果是,又
取出年代的高两位,判断是否小于"80",如小于,认为到了2000 年,则将年代的高两位
标志改为"20",如大于或等于,则认为仍在20世纪。
此外,该程序中还对CMOS 的70,71 端口进行了操作,操作中使用了两条相邻的跳
转指令JCXZ进行延时,以确保对端口的操作准确无误。程序的末尾,对8259A主片的20
端口进行了操作。指令为
MOV AL,20
OUT 20,AL
当用8259A来实现中断服务程序结束时(返回指令IRET 前),必须给8259A 送一条EO
I命令(即AL第五位为 1)。8259A收到这条命令后,将中断服务寄存器ISR中的相应位清零
,然后才可为其他同优先级的中断源服务。
这个中断程序,完成了两个基本功能:计时和管理软磁盘驱动器的启动时间。每调用
一次此中断,时间就增加"一秒"(实际约为55毫秒),当小时标志为18H时,还要判断"秒
"标志是否到了B0H,这是为了弥补其计时方法引起的误差所采取的措施。程序在修改“
计时器”后,还调用了INT 1CH ,紧接着又调用了两个仅包含一条IRET指令的子过程。
这有什么作用呢?似乎给我们提供了修改此中断的好方法。
总之,INT 8H是一个比较有意思的中断。由于程序不长,仅70 余行,有兴趣的读者
不妨将之反编译,完整的读一下。
(五)INT 18H --一个暗伏圈套的中断
当我们对BIOS进行反编译的时候,常常会碰到诸如DB 0F,DB 66等的语句,那么,
程序中出现这些语句又是什么意思呢?先前我们并没有很在意这些语句,仅仅简单的认
为它们是在修改BIOS中留下的无用语句(这可是一个可怕的错误)。然而,事实告诉我们
,这里隐藏着一个小秘密。让我们先来看一看这个程序。
程序首先设置了屏幕显示格式,然后调用了子过程(CALL EDA8)一次。如果我们以
U F000:EDA8翻译它们,则会显示如下语句。
EDA8:PUSH CX
PUSH BX
PUSH DS
PUSH CS
POP DS;DS=F000
XCHG BX,BX
NOP
EDB0:LODSB ;DS:SI=“PRESS A KEY TO REROOT ”,0D 0A 00...
OR AL,AL
EDB3:DB 0F
TEST AL,[DI]
ADD AH,CH
XOR AX,EB00
HLT
EDBC:POP DS
POP BX
POP CX
RET
而主程序为:
E7A4:MOV AX,40
MOV DS,AX
XOR AH,AH
MOV AL,[49]
INT 10
MOV SI,EA70
CALL EDA8 ;显示“PRESS A KEY TO REBOOT”
XOR AH,AH
INT 16 ;等待按下任一键
MOV WORD PTR [72],1234;跳过存储器测试
JMP F470;跳向自检
如果你试读一下,会发现简直莫名其妙,子过程没法读懂。问题出在那呢?我们曾
经为此费劲脑筋,直到有一次,我们尝试着运行这个程序,才发现运行的过程与表面的
显示有所不同。最终的结论是,DEBUG给我们开了一个大玩笑----DEBUG不认得这是一条
高级指令!!!子过程EDB0处的DB 0F开始之处为一条高级指令。大家可以参阅INTEL奔
腾机的用户参考手册,它其实是JZ指令。真实的子过程为:
EDA8:PUSH CX
PUSH BX
PUSH DS
PUSH CS
POP DS
XCHG BX,BX
NOP
EDB0:LODSB
OR AL,AL
JZ EDBC
CALL EDEF
JMP EDB0
EDEF:PUSH AX
PUSH BX
MOV AH,0E
MOV BX,3 ;背景为黑色
INT 10 ;显示当前字符
POP BX
POP AX
RET
由于进行了JZ判断,所以程序进行了一个循环,从而显示了一个提示重新启动的字符
串--PRESS A KEY TO REBOOT。当然,如果你在WINDOWS下运行这个程序,将会得到一个
“程序异常结束”的警告,你可以将WINDOWS切换到MS_DOS模式下,执行这个程序将会重
启计算机。大家可以验证一下。
我们从这个程序得到什么启示呢?
1.不要被表面的现象所迷惑,不要想当然。
2.要有扎实的基础知识,只有这样才能发现错误,改正错误。
3.要多实践,不可死背书本。
摘自电脑报
阅读(4638) | 评论(0) | 转发(0) |