在8086汇编中有一个事情就是中断,比如说在div指令时可能会引发除0异常,这个时候就会转到中断处理程序去执行,比如说调用
int 0h
指令,那么背后的原理是啥?
事情是这样的,假设我们现在调用了int 0h指令,系统会首先把cs,ip依次压入栈,可能还有其它需要保存的参数,这里只关注cs和ip
到(8086系统)以0000h为段起始地址找中断向量表,这个表里存放了多种中断程序的入口地址,也称为中断向量,这个找的过程:比如说是第N号中断,那么4个字节为一组(存放的是一组中断向量)然后去0000:N4的位置就可以
这里注意0000:N4是偏移地址,0000:N*4+2是段基址
这个地址的组成是:高2个字节为段基址,低2个字节为偏移地址,由该地址就可以找到处理程序的入口,然后进行执行,执行完毕之后恢复psw(标志寄存器)和pc(cs和ip)
现在做一个有意思的事情:改变中断向量入口,把原本应该报溢出错误的东西换成我们自己的代码。
怎么做呢?很简单,把我们程序的入口放在0000:0000(假设调用int 0h)也就是改变对应内存存放的地址,这样的话就可以调用我们自己写的代码了
附代码,这里面使用了中断处理程序做了一个循环,要尤其注意各个寄存器对应的默认段基址寄存器是啥
比如说si对应的是ds寄存器,di对应的是es寄存器(扩展寄存器)bx对应的是ds寄存器,bp对应的是ss寄存器
; multi-segment executable file template.
data segment
; add your data here!
pkey db "press any key...$"
count db 1h
ends
stack segment
dw 128 dup(0)
ends
code segment
start:
; set segment registers:
mov ax,0
mov ds,ax
mov es,ax
mov ds,ax
mov bx,0 ;得把ds段也放成0
mov ds:bx+2,cs ;放段基址
mov ds:bx,word ptr dzz ;放偏移地址
lea bx,dzz
mov dx,offset s-offset se
mov al,40h
;mov cx,1
s:
mov ah,2;调用10号中断的2号程序,改变光标位置
push dx
mov dl,count;列号
mov dh,count
int 10h
inc dl
mov count,dl
pop dx;这个是打印的数据变量
inc al
int 0H
se:
mov ax, 4c00h ; exit to operating system.
int 21h
dzz:
mov cx,1
mov ah,9
mov bh,0
mov bl,11001001B
int 10h
cmp al,5Ah
jz y ;如果是0不加偏移量,如果不是0加偏移量
mov bp,sp;这里做出脱裤子放屁的举动是因为sp变量不能取地址
add [bp],dx;给栈里面的原有偏移值加一个偏移量使得它能够回到s标号位置
y:
iret
dzzend:
nop
; wait for any key....
mov ah, 1
int 21h
ends
end start ; set entry point and stop the assembler.