当前位置:文档之家› 中断程序设计

中断程序设计

中断程序设计
中断是CPU和外部设备进行输出\输入的有效方法。
中断是一种使CPU中止正在执行和程序而转去处理特殊事件的操作,这些引起中断的事件称为中断源。
由外设控制器或协处理器(8087\80287)引起的中断一般称为外中断。
由程序中安排的中断指令INT产生的中断,或由CPU的某些错误结果产生的中断称为内中断。
外中断:可屏蔽中断INTR
不可屏蔽中断NMI
内中断:除法错中断,溢出中断,软中断,单步中断等

中断向量表
病毒程序驻留内存之后,通常以经常调用的系统程序为“病毒宿主”如INT13H、INT21H、INT8等。病毒修改中断服务的入口地址,形成类似于:
INT13H->病毒程序入口->病毒体->病毒出口->INT13H中断服务程序入口。
提取中断向量表
DEBUG
-M0000:0000 L0400 0100;复制中断向量表
-RCX
CX 0000
:0400
-N INT.TAB
-W
 Writing 0400 bytes
-Q

恢复中断向量表
DEBUG INT.TAB
-M 0100 L0400 0000:0000
-Q

一个批处理病毒程序
特点:简单,无伪装性,有病毒的典型结构。
文件名:AUTOEXEC.BAT

ECHO VIRUS DEMOSTRATION PROGRAM
IF EXIST A:\AUTOEXEC.BAT GOTO VIRUS
GOTO NO_VIRUS
VIRUS:
A:
RENAME AUTOEXEC.BAT AUTO.BAT
COPY C:\AUTOEXEC.BAT B:
ECHO I AM VIRUS!
NO_VIRUS:
C:
\AUTO
PAUSE
相当于原来的程序中嵌入病毒程序

每种中断都安排有一个中断类型号,计256种。类型号分别为0-0FFH中断向量表就是种中断类型的处理程序的入口地址。
256项中断,每项占4个字节,2个字节存放中断处理程序的段地址,另2个字节存放偏移地址。
在计算机主存中从0到5FFH为系统占用,从0到3FFH存放中断向量,即占用1024字节。
每类中断向量的地址可由中断类型号乘以4计算出来。
例:报警中断类型为4AH
其中断向量地址为4AH*4=128H,即可得到
段地址为12AH,12BH.段内偏移地址为128H,129H。
中断操作的5个步骤:
1. 取中断类型号
2. 计算中断向量地址
3. 取中断向量偏移地址送IP,段地址送CS
4. 转入中断处理程序
5. 中断返回到INT指令的下一条指令
中断向量分配:
0- 1FH BIOS中断
20-3FH DOS中断
40-5FH 扩充BIOS中断
60-67H 用户中断向量
68-6FH 保留
70-77H I/O 中断
78-7FH 保留
80-FDH BASIC中断
F1-FFH 保留

设置中断向量
用户可利用保留的中断类型号扩充自己需要的中断功能,新增加的中断功能要在中断表中建立相应的中断向量。
例:用指令来为中断类型N设置中断向量
MOV AX,0
MOV ES,AX
MOV BX,N*4
MOV AX,OFFSET INTHAND
MOV ES:WORD PTR[BX],AX
MOV AX,SEG INTHAND
MOV ES:WORD PTR[BX+2],AX
:
INTHAND:
:
IRET
若新中断功能只供自己使用OR用自己编写的中断处理程序代

替系统中的中断处理能时,要注意保存原中断功能。
在检查或设置任何中断向量时,总是避免直接使用中断的绝对地址。
利用DOS功能设置中断向量:
将由AL指定的中断类型的中断向量DS:DX放置在中断向量表中。
入口参数为:AL类型号,AH功能号,DS:DX中断向量。
执行:INT 21H

MOV AX,0
MOV AL,N
MOV AX,OFFSET INTHAND
MOV DX,AX
MOV AX,SEG INTHAND
MOV DS,AX
MOV AH,25H
INT 21H
:
INTHAND:
:
IRET

取中断向量有两种方法:第一种方法为利用中断向量表来保存其入口地址。
MOV AX,0
MOV ES,AX
MOV BX,N*4
PUSH ES:WORD PTR[BX]
PUSH ES:WORD PTR[BX+2]
POP ES
POP BX
:
第二种提取方法为利用DOS功能调用:将由AL指定的中断类型的中断向量从中断向量表中取到ES:BX中。
入口参数:AL类型号,AH功能号
执行:INT 21H
出口参数:ES:BX
MOV AL,N
MOV AH,35H
INT 21H
:
对中断类型的中断向量的保存、修改、恢复过程如下:

MOV AL,N
MOV AH,35H
INT 21H
PUSH ES
PUSH BX
PUSH DS
MOV AX,SEG INTHAND
MOV DS,AX
MOV DX,OFFSET INT HAND
MOV AL,N
MOV AH,25H
INT 21H
POP DS
:
POP DX
POP DS
MOV AL,N
MOV AH,25H
INT 21H
RET
INTHAND:
:
IRET
中断过程:
中断发生时,硬件自己完成下列动作。
1. 取中断向量
2. 标志寄存器入栈(PSW)
3. 当前段寄存器入栈(CS)
4. 当前指令指针计数器入栈(IP)
5. 禁止外部中断和单步中断(IF=0,TF=0)
6. 从中断向量表中取N*4的字内容送IP,取N*4+2字内容送CS。
7. 转中断处理程序
中断优先级和中断嵌套
IBMPC规定中断的优先级次序为:内中断(除法错、INTO、INT),非屏蔽中断(NMI),可屏蔽中断(INTR),单步中断。
正在运行的中断处理程序,又被其它中断源中断,这种情况叫中断嵌套。
一个正在运行的中断处理程序,在开中断(IF=1)的情况下,能被其它优先级高于它的中断源中断。但若要被同级OR低级中断源中断,则必须发出EOI命令,清除正在执行的中断请求,才能响就同级OR低级的中断。
中断处理程序的编写步骤:
1. 保存寄存器内容。
2. 如允许中断嵌套,则开中断(STI)
3. 处理中断
4. 关中断
5. 送中断结束命令(EOI)给中断命令寄存器。
6. 恢复寄存器内容
7. 返回被中断的程序。
用DEBUG提取中断向量表:
DEBUG
-M0000:0000 L0400 0100;复制表
-RCX
CX 0000
:0400
-N A:INT.TAB
-W
WRITINg 0400 ByTES IS COPIED
-Q
恢复中断向量表
DEBUG INT.TAB
-M0100 L0400 00:00
-Q
中断程序设计举例:
1. 修改INT 20H的中断向量,使它指向了程序中的一个地方。当执行INT 20H时,程序不再结束,而是按我们的意图行事。
注:修改之前,就将原有的中断向量保存,以后再恢复。
DATA SEGMENT
STRING DB 'THIS IN

TERRUPT VECTOR HAS BEEN CHANGED',0AH,0DH
DB 'AND IT HAS BEEN RESUMED AGAIN','$'
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA
MAIN PROC FAR
START:
PUSH DS
MOV AX,0
PUSH AX
MOV AX,DATA
MOV DS,AX
MOV AX,0
MOV ES,AX
CLI
PUSH ES:[80H]
PUSH ES:[82H]
MOV WORD PTR ES:[80H],OFFSET BEGIN
PUSH CS
POP AX
MOV WORD PTR ES:[82H],AX
STI
INT 20H
CLI
POP ES:[82H]
POP ES:[80H]
STI
JMP DONE
BEGIN:
PUSH DS
MOV AX,DATA
MOV DS,AX
MOV DX,OFFSET STRING
MOV AH,9
INT 21H
POP DS
IRET
DONE:
RET
MAIN ENDP
CODE ENDS
END START
注;INT 20H 的原始内容为:PROgRAM TERMINATED NORMALLy

如何获取真正中断入口地址

例1:

提取原始INT13H中断位置
分析:中断发生时,硬件完成了以下几个动作:
⑴PSW程序状态控制字入栈;⑵CS代码段寄存器入栈;⑶IP指令指针寄存器入栈。
思想:病毒程序、安全程序修改了INT13中断,则13H*4=4CH处的内容,就不是真正的13H入口地址。
.MODEL TINY
.CODE
ORG 100H
BEGIN:
PUSH CX
POP DS
MOV AX,3513H;取当前INT13H的入口地址,尽管不是真正的原始地址
INT 21H
MOV INT13_SEG,ES
MOV INT13_OFS,BX
MOV DX,OFFSET INT1_HAND
MOV AX,2501H ;设置单步执行中断
INT 21H
PUSHF
POP AX
OR AX,0100H ;设置TF
PUSH AX
POPF
MOV AH,0 ;利用一个无关紧要的硬盘复位命令调用13H,找出进入点。
MOV DL,80H
PUSHF
CALL DWORD PTR INT13_HAND
MOV AH,4CH
INT 21H

INT13_HAND LABEL DWORD
INT13_OFS DW ?
INT13_SEG DW ?

PRINT_CHAR PROC NEAR
MOV AH,0EH
INT 10H
RET
PRINT_CHAR ENDP

HEXTABLE DB ‘0123456789ABCDEF’

PRINT_HEX PROC NEAR
PUSH AX
PUSH BX
PUSH DX
MOV CL,4
SHR DL,CL
XOR BX,BX
MOV BL,DL
MOV AL,HEXTABLE[BX]
CALL PRINT_CHAR
POP DX
PUSH DX
AND DL,0FH ;屏蔽高4位
XOR BX,BX
MOV BL,DL
MOV AL,HEXTABLE[BX]
CALL PRINT_CHAR
POP DX
POP BX
POP AX
RET
PRINT_HEX ENDP

PRINT_WORD PROC NEAR
XCHG DH,DL
CALL PRINT_HEX
XCHG DH,DL
CALL PRINT_HEX
RET
PRINT_WORD ENDP
INT1_HAND:
PUSH BP
MOV BP,SP
PUSH DX
MOV DX,WORD PTR[BP+0004] ;取CS
CMP DX,0F00H
JZ PRINT
JMP EXIT
PRINT:
MOV CS:INT13_SEG,DX
CALL PRINT_WORD
MOV DX,WORD PTR [BP+0002]
MOV CS:INT13_OFS,DX
CALL PRINT_WORD
A

ND WORD PTR[BP+0006],0FEFFH;清TF
JMP EXIT1
EXIT:
OR WORD PTR[BP+0006],0100H
EXIT1:
POP DX
POP BP
IRET
END BEGIN

例2:概述:

我们知道,DOS 的中断例程的入口地址存在 0000:0000 开始的中断向量表中,当程序要要建立一个中断例程时,需要修改中断向量表把入口地址指向自己的程序,为了使原来的中断例程能正常使用,在出口的时候还要用远跳转指令回到原中断的入口地址,如 DOS 中断 INT 21H,在 DOS 启动后,后面要挂上很多的新的例程,如 SMARTDRV 等等,磁盘中断 INT 13H 也是如此。
但在程序中,有时需要用到真正的中断入口,如 INT 13H 的 BIOS 入口举例说为 F000:EC59,为了反跟踪,程序中有时要用 PUSHF/CALL F000:EC59 的方法来调用,这就需要在程序开始运行时检测出真正的中断入口地址以备用。
检测真正的入口地址可以用单步中断的方法来进行,在调用 INT XX之前,把单步中断指向自己的程序,
在单步中断中,从堆栈中取出要返回的地址,这就起到的跟踪 INT XX 的执行的作用,举例程序中将跟踪 INT 21H 的执行,然后把执行的地址输出到屏幕上,在 INT 21H 中远跳转的地方给出提示。
真正的中断地址往往在远跳转的地方,在判断哪个远跳转是真正的中断地址时,不同的中断要具体判断,如跟踪 INT 13H 时,我们知道 BIOS 的段地址一般为 E000,所以一旦判断到段地址为 E000 时,就可以把这个地址保存下来作为真正 INT 13H 地址,而跟踪 INT 21H 时,INT 21H 在 DOS 的内核中,所以要先用第一个 MCB 地址的功能取出 MCB 地址,而第一个 MCB 地址之前是系统内核区,当判断到段地址小于第一个 MCB 地址时,这个地址就是真正的 INT 21H 地址。


汇编编程示例:


.286
CODE SEGMENT
ASSUME CS:CODE,DS:CODE
ORG 100H
START:
jMP INSTALL
D_MES1 DB 'CS:IP = %04H:%04H %,FLAG = %017B%,',0DH,0AH,0
DW _CS,_IP,_FLAG
_CS DW ?
_OLD_CS DW ?
_IP DW ?
_FLAG DW ?
D_MES2 DB '%14R- SEGMENT CHANGE %13R-',0DH,0AH,0
;新的单步中断 INT 1 例程
;
INT1:
PUSH AX
PUSH BP
MOV BP,SP ;

MOV AX,SS:[BP+4] ;返回的 IP
MOV CS:_IP,AX
MOV AX,SS:[BP+6] ;返回的 CS
MOV CS:_CS,AX
MOV AX,SS:[BP+8] ;FLAg
MOV CS:_FLAg,AX

POP BP
POP AX

PUSHF
PUSHA
PUSH DS
PUSH ES

PUSH CS
POP DS
PUSH CS
POP ES

MOV AX,_CS
CMP AX,_OLD_CS
MOV _OLD_CS,AX
jz INT1_1
MOV SI,OFFSET D_MES2 ;SEgMENT HAS CHANgED
CALL PRINTF
INT1_1:
MOV SI,OFFSET D_MES1 ;PRINT RETURN ADDRESS
CALL PRINTF ;AND FLAgS
POP ES
POP DS
POPA
POPF
IRET
INSTALL:
MOV AX,CS
MOV _OLD_CS,AX

MOV AX,3501H ;KEEP INT 01
INT 21H
PUSH ES
PUSH BX

MOV AX,2501H ;SET NEw I

NT 01
MOV DX,OFFSET INT1
INT 21H

PUSHF
POP AX
OR AX,0100H
PUSH AX
POPF ;SET INT 01 FLAg
;--------------------------------------------------------
XOR AX,AX
MOV ES,AX ;从这一句开始单步中断

MOV AH,-1 ;由于 INT 语句要清单步中断,所以
PUSHF ;要用 PUSHF/CALL FAR 的形式执行 INT 21H
CALL DwORD PTR ES:[4*21H]
PUSHF
POP AX
AND AX,0FEFFH
PUSH AX ;跟踪完毕后清楚单步中断
POPF ;CLEAR INT 01 FLAg
;---------------------------------------------------------
POP DX
POP DS
MOV AX,2501H
INT 21H ;RESTORE OLD INT 01

INT 20H
INCLUDE PRINTF.ASM ;公用屏幕输出子程序
CODE ENDS
END START


相关主题
文本预览
相关文档 最新文档