外中断是指那些不再CPU内部产生的中断,即通过端口与cpu通信的外设产生的中断。
- 可屏蔽中断是CPU可以不响应的外中断
- 不可屏蔽中断是CPU必须响应的中断,其中断类型码都是2
- sti,cli可以屏蔽中断,让一些如改变中断向量的操作安全进行。
(1)下面程序在屏幕中某个位置一次输出A~Z,按ESC改变该位置颜色:
1 ;中断时的入栈顺序是pushf,push cs, push ip 2 assume cs : codesg, ss : stacksg 3 4 stacksg SEGMENT 5 dw 64 dup (0) 6 stacksg ENDS 7 8 9 10 codesg SEGMENT 11 12 start: ;改变中断向量到本程序中的中断例程处 13 mov ax, 0 14 mov es, ax 15 mov ax, stacksg 16 mov ss, ax 17 mov sp, 64 18 mov ds, ax 19 20 ;分别将中断程序cs:ip入栈ds:[si]分别存ip,cs 21 push es : [9 * 4 + 2] 22 push es : [9 * 4] 23 mov si, sp 24 25 ;改变中断向量 26 cli 27 mov ax, codesg 28 mov es : [9 * 4 + 2], ax 29 mov word ptr es : [9 * 4], offset int9 30 sti 31 32 mov ax, 0b800h 33 mov es, ax 34 mov bl, 'A' 35 print: mov es : [12 * 160 + 36 * 2], bl 36 add bl, 1 37 call delay 38 cmp bl, 'Z' 39 jna print 40 41 ;改回中断向量 42 mov ax, 0 43 mov es, ax 44 cli 45 mov ax, word ptr ds : [si + 2] 46 mov es : [9 * 4 + 2], ax 47 mov ax, word ptr ds : [si] 48 mov es : [9 * 4], ax 49 sti 50 51 mov ax, 4c00h 52 int 21h 53 54 55 delay: push ax 56 push bx 57 mov ax, 0 58 mov bx, 1000h 59 wl: sub ax, 1 60 sbb bx, 0 61 cmp ax, 0 62 jne wl 63 cmp bx, 0 64 jne wl 65 pop bx 66 pop ax 67 ret 68 69 ;原来的中断例程存放在ds:[si]处 70 int9: push ax 71 push es 72 pushf ;中断例程最后是iret 73 ;注意是dword 74 call dword ptr ds : [si] ;运行原中断例程处理硬件细节 75 76 in al, 60h 77 cmp al, 1 78 jne int9end 79 80 mov ax, 0b800h 81 mov es, ax 82 add byte ptr es : [12 * 160 + 36 * 2 + 1], 1 83 84 int9end: pop es 85 pop ax 86 iret 87 codesg ENDS 88 END start 89
在windows XP下运行有效果不过会导致鼠标左键失灵。
(2)安装新的int 9中断历程,按f1改变屏幕显示颜色:
1 ;cs总在高地址处 2 assume cs : codesg, ss : stacksg 3 4 stacksg SEGMENT 5 dw 64 dup (0) 6 stacksg ENDS 7 8 9 10 codesg SEGMENT 11 12 start: mov ax, stacksg 13 mov ss, ax 14 mov sp, 128 15 mov ax, 0 16 mov es, ax 17 mov ax, codesg 18 mov ds, ax 19 mov si, offset int9s 20 mov di, 0200h 21 22 cli 23 mov bx, offset table 24 mov ax, es : [9 * 4] 25 mov [bx], ax 26 mov ax, es : [9 * 4 + 2] 27 mov [bx + 2], ax 28 mov word ptr es : [9 * 4], 0200h 29 mov word ptr es : [9 * 4 + 2], 0 30 sti 31 32 mov cx, offset int9end - offset int9s 33 cld 34 rep movsb 35 36 mov ax, 4c00h 37 int 21h 38 39 int9s: jmp short sss 40 table dw 0, 0 41 sss: push ds 42 push ax 43 push cx 44 push si 45 pushf 46 mov ax, 0 47 mov ds, ax 48 call dword ptr ds : [202h] 49 in al, 60h 50 cmp al, 3bh 51 jne int9ret 52 mov si, 0 53 mov cx, 2000 54 mov ax, 0b800h 55 mov ds, ax 56 s1: inc byte ptr [si + 1] 57 add si, 2 58 loop s1 59 int9ret: pop si 60 pop cx 61 pop ax 62 pop ds 63 iret 64 65 int9end: nop 66 codesg ENDS 67 END start
效果不错~
(3)安装新的int9中断例程,在DOS下,按下'A'键后,松开就显示满屏幕‘A’,其他照旧:
1 ;中断时的入栈顺序是pushf,push cs, push ip 2 assume cs : codesg, ss : stacksg 3 4 stacksg SEGMENT 5 dw 64 dup (0) 6 stacksg ENDS 7 8 9 10 codesg SEGMENT 11 12 start: mov ax, stacksg 13 mov ss, ax 14 mov sp, 128 15 mov ax, 0 16 mov es, ax 17 mov di, 0200h 18 mov si, offset int9 19 push cs 20 pop ds 21 22 cli 23 mov bx, offset table 24 mov ax, es : [9 * 4] 25 mov ds : [bx], ax 26 mov ax, es : [9 * 4 + 2] 27 mov ds : [bx + 2], ax 28 sti 29 30 mov cx, offset int9end - offset int9 31 cld 32 rep movsb 33 34 mov word ptr es : [9 * 4 + 2], 0 35 mov word ptr es : [9 * 4], 0200h 36 37 mov ax, 4c00h 38 int 21h 39 40 int9: jmp short s 41 table dw 0, 0 42 s: push ax 43 push cx 44 push si 45 push es 46 mov ax, 0 47 mov ds, ax 48 pushf 49 call dword ptr ds : [202h] 50 in al, 60h 51 cmp al, 9eh 52 jne int9ret 53 mov ax, 0b800h 54 mov es, ax 55 mov si, 0 56 mov cx, 2000 57 s1: mov byte ptr es : [si], 'A' 58 add si, 2 59 loop s1 60 61 int9ret:pop es 62 pop si 63 pop cx 64 pop ax 65 iret 66 67 int9end:nop 68 codesg ENDS 69 END start
因为一个ds寄存器忘记保护现场,导致莫名其妙的错误,谨慎~