学习汇编的一个重要目的就是获得面对底层编程的经验。
这也就是说有的时候我们这些编程者应该绕开操作系统,直接面向硬件要资源。当然,这
在某种程度上是不安全的。但请别忘了,我们在写汇编。
一、简单介绍下博文的目标
这篇博文主要是改写0号中断(除法溢出)的入口地址,使之执行编程者自己编写的中断处理
程序。系统提供的0号中断服务程序做法是打印divide overflow!,然后返回。新的中断服务
程序的目标是在屏幕中央打印overflow!,然后返回。
那么,怎么怎样体现直接向硬件要资源呢?举个例子,我们知道普通的子程序实在编译的时候
由系统分配一个安全的内存空间存储之。我写的新的中断程序则不这样了,分析程序可以发现,
我是直接将新的中断服务程序,拷到了内存0000:0200开始的空间。
到这里,细心的读者可能就会有两个疑问了。
1、我们虽然强调直接面向系统资源(这里主要是内存)编程,但我们总不能什么也不管什么也
不顾吧,本着破坏的目的吧?
2、为什么将中断服务程序写到内存0000:0200开始的区域呢?
回答这两个问题之前我们先来看看利用debug的D命令,查看内存0000:0200开始的256个字节的
内容。
到这里,上述的两个问题都可以迎刃而解了。从0000:0200开始的内存区域虽然是系统存放
中断向量表的区域,但显然,系统没有提供那么多的中断,这区域为空。另外,由于这段区
域啥也没有,我们向这里写东西也一般不会引起不安全的事。
二、代码
data segment
hint db 'overflow!','$'
addr dw ?,?
data ends
code segment
assume cs:code,ds:data
start:
mov ax,data
mov ds,ax
;将新中断服务程序直接复制到地址0000:0200,此处不再向操作系统申请内存
mov cx,offset doend - offset dostart
mov si,offset dostart
mov ax,seg dostart
mov ds,ax
mov ax,0000h
mov es,ax
mov di,0200h
cld
rep movsb
mov ax,0
mov es,ax
;保存原中断地址
mov ax,es:[0*4]
mov addr[0],ax
mov ax,es:[0*4+2]
mov addr[2],ax
;写入新中断地址
cli
mov word ptr es:[0*4],0200h
mov word ptr es:[0*4+2],0000h
sti
;产生除法溢出0号中断
mov ax,0ffffh
mov bh,1
div bh
mov ah,4ch
int 21h
dostart:
;显示字符串overflow!
mov ax,data
mov ds,ax
;以下注释的部分是调用DOS功能调用在屏幕上打印字符串
;mov dx,offset hint
;mov ah,9
;int 21h
;直接向显存b8000:bffff内写入内容,也可以在屏幕上显示
mov si,offset hint
mov ax,0b800h
mov es,ax
mov di,12*160+36*2 ;设置在屏幕中央显示
mov cx,9
again:
mov al,[si]
mov es:[di],al
inc si
add di,2
loop again
;将原中断服务程序地址写回
cli
mov ax,0
mov es,ax
mov ax,addr
mov es:[0*4],ax
mov ax,addr[2]
mov es:[0*4+2],ax
sti
;程序退出
mov ah,4ch
int 21h
doend:
nop
code ends
end start
三、结果截图
四、代码中提到了两种打印overflow!方法。
1、DOS的功能调用-int 21h,利用其中的9号功能即可打印。其中,要将要打印的内容的首地址放到
ds:dx中,并且要打印的字符串要以$结尾。
2、直接要显存空间写数据,写入的数据会显示在屏幕上。
注:如果对显存不了解的可以到这里查看显存介绍及编程