内存驻留程序

转载 2006年05月23日 11:44:00


学习DOS下内存驻留程序的基本思想,了解与熟悉用汇编语言编写程序。本课程设计将完成一个小的.com程序,运行程序后,你的所有按键输入(指在DOS或Windows的DOS模式下)将不被接受,所有输入将被替换成特定的字符串(回车键除外)。

二、内存驻留程序的基本框架(framework of a TSR)

  内存驻留程序的基本思想就是让程序一直停留在内存中,不断的执行特定的命令。但内存驻留如何被执行呢?一般地,内存驻留程序都是通过修改BIOS或DOS的系统中断向量表来实现的。比如修改向量表中16H位置的中断(这个中断接收键盘的按键,在DOS中,按键按下,这个中断就会被调用),让其指向我的程序,这时若有按键被按下,则执行的是我的程序。下面是一个最简单的框架:

CSEG SEGMENT
  ASSUME   CS:CSEG, DS:CSEG
  ORG    100H
Start:
  JMP    Initialize
new_keyboard_io PROC FAR // 这一部分是驻留在内存的内容
  STI
  NOP
  IRET
new_keyboard_io ENDP // 到这里结束

Initialize:
  MOV DX, OFFSET new_keyboard_io // 新的键盘处理程序
  MOV AL, 16H // 需更改的向量号(interrupt index)
  MOV AH, 25H // 更改系统中断向量表
  INT 21H

MOV DX, OFFSET Initialize
  INT 27H // 将标签Initialize前的程序驻留内存

CSEG ENDS
  END Start



三、实现原来设计程序

首先,我需要还是需要捕获用户的回车键,所以需要将原来的DOS本身的键盘处理程序保留起来。下面的代码:

old_keyboard_io DD ?
……
Initialize:
……
  MOV AL, 16H          ; Interrupt index in vector table
  MOV AH, 35H          ; Get the interrupt dealing
  INT 21H            ; program's pointer
  MOV old_keyboard_io, BX    ; offset
  MOV old_keyboard_io[2], ES   ; base address
……



  old_keyboard_io用来储存原键盘处理程序的指针,其中INT 21H – AH=35H,是获得其指针,返回值在ES:BX中。ES是指针的基地址,BX是偏移量。

  其次,就是实现我原来设计的功能,截获按键信息,并改为特定的字符串。下面的实现的代码:

……
Hello_Msg DB 'Kasi, haha!'    ; string to display when catch a key-press
Msg_Index DW 0          ; which char in the string been displayed(char index)
……
new_keyboard_io PROC FAR
  ASSUME CS:CSEG, DS:CSEG
    STI

    CMP AH, 00H        ; INT 16H - AH = 0 to catch
    JE new_io_0        ; key-press func
    ASSUME DS:nothing
    JMP old_keyboard_io    ; No catch, jump to old handler
new_io_0:
    PUSHF
  ASSUME DS:nothing
    CALL old_keyboard_io
    CMP AL, 0DH        ; Is a ENTER been pressed ?
    JNE new_io_1       ; no, output string 'Kasi, haha!'
    MOV Msg_Index, 0     ; yes, reset the string index
    JMP new_io_done      ; and return
new_io_1:
    PUSH SI
    MOV SI, Msg_Index     ; Get current char index
    MOV AL, Hello_Msg[SI]   ; Get current char

    INC SI          ; Next char in the Hello_Msg
    CMP SI, 11        ; Reach the end of the Hello_Msg ?
    JNE new_io_2       ; no, jump
    MOV SI, 0         ; yes, set the char index to the beginning
new_io_2:
    MOV Msg_Index, SI     ; Save the char index
    POP SI
new_io_done:
    IRET
new_keyboard_io ENDP
……


  下面的分段说明:

    CMP AH, 00H        ; INT 16H - AH = 0 to catch
    JE new_io_0        ; key-press func
    ASSUME DS:nothing
    JMP old_keyboard_io    ; No catch, jump to old handler



  这一段代码是根据书上抄下来的,先检测AH中是否为0(INT 21H - AH=0表示用户按下键盘),不为0就进入old_keyboard_io,由系统原来的处理程序去处理用户的请求。这里”ASSUME DS:nothing”是告诉编译器忽略DS的内容,这样才能正确跳转。

new_io_0:
    PUSHF
  ASSUME DS:nothing
    CALL old_keyboard_io
    CMP AL, 0DH        ; Is a ENTER been pressed ?
    JNE new_io_1       ; no, output string 'Kasi, haha!'
    MOV Msg_Index, 0     ; yes, reset the string index
    JMP new_io_done      ; and return



  如果是有按键被按下,则先检测按键是否为回车键(0DH),如果不是则跳转到new_io_1去处理,否则将字符串的索引置0(Msg_Inedx = 0)并结束程序。

new_io_1:
    PUSH SI
    MOV SI, Msg_Index     ; Get current char index
    MOV AL, Hello_Msg[SI]   ; Get current char

    INC SI          ; Next char in the Hello_Msg
    CMP SI, 11        ; Reach the end of the Hello_Msg ?
    JNE new_io_2       ; no, jump
    MOV SI, 0         ; yes, set the char index to the beginning
new_io_2:
    MOV Msg_Index, SI     ; Save the char index
    POP SI


  若用户按下的不是回车键,将Hello_Msg[Msg_Index]这个字符放入AL中(因为AL是INT 21H – AH=16H调用的返回值)并让Msg_Index的值加1,然后判断Msg_Index是否指向Hello_Msg的尾部了,是的话将Msg_Index置0。
  这样,就完成了整个程序。

四、调试程序

  程序写好了,当然就要编译和运行。编译通过,但程序运行后却没有任何效果。
  按理说,程序应该是没有问题的,但为何没有任何效果呢?我怀疑new_keyboard_io是不是没其作用,如何检查错误呢?用debug一步步跟踪显然不明智,于是我在这里加了一个断点:

new_keyboard_io PROC FAR
  ASSUME CS:CSEG, DS:CSEG
    STI
      INT 03H        ; break point
    CMP AH, 00H        ; INT 16H - AH = 0 to catch



  编译运行,并在debug用a命令写入

mov ah, 10
mov al, 00
int 21



  手动调用INT 21H – AH=16H,希望能在程序中停住,看new_keyboard_io是否被执行了。但我在debug中一t(trace),整个debug就出问题了,原因不明,看来不能用这种方法试验。
  那我就换一个方法,用一个没有任何命令的new_keyboard_io作测试,代码如下:

CSEG SEGMENT
  ASSUME CS:CSEG, DS:CSEG
  ORG 100H
Start:
  JMP Initialize
new_keyboard_io PROC FAR
  ASSUME CS:CSEG, DS:CSEG
    STI
      NOP
    IRET
new_keyboard_io ENDP
Initialize:
  ASSUME CS:CSEG, DS:CSEG
    MOV DX, OFFSET new_keyboard_io
    MOV AL, 16H
    MOV AH, 25H
    INT 21H

    MOV DX, OFFSET Initialize
    INT 27H

CSEG ENDS
  END Start


  编译运行之后,任何按键输入都不起作用了,看来new_keyboard_io还是被执行了的,那问题就出现在我写的new_keyboard_io的代码里面了。我查了查书,INT 21H – AH=00H是接受按键消息的啊。但我还发现了一个INT 21H – AH=10H也是接受键盘消息的,会不会DOS在提示符(c:>)下用的是AH=10H呢?我马上在原程序中加了一下代码:

……
    CMP AH, 00H        ; INT 16H - AH = 0 to catch
    JE new_io_0        ; key-press func
;-------------------------------
; In the DOS prompt(C:>), DOS uses
; INT 16H - AH = 10H to get a char, not
; AH = 00H
    CMP AH, 10H        ; new added codes
    JE new_io_0
;-------------------------------
    ASSUME DS:nothing
    JMP old_keyboard_io    ; No catch, jump to old handler
……

用汇编编写DOS下的内存驻留程序

绪言 0.1 内存驻留与中断 内存驻留程序英文叫Terminate and S 绪言 0.1 内存驻留与中断 内存驻留程序英文叫Terminate and Stay Resident...
  • pofante
  • pofante
  • 2011年08月01日 15:33
  • 3170

显示内存驻留程序的信息

  • 2007年06月03日 01:10
  • 17KB
  • 下载

TC 开发内存驻留程序

  • 2007年06月03日 01:09
  • 18KB
  • 下载

【汇编】TSR内存驻留程序实现与删除及热键设置——以实现时钟为例

【汇编】TSR内存驻留程序实现与删除及热键设置——以实现时钟为例 最近完成了一个关于时钟中断驻留的汇编大作业,对于TSR很是感兴趣,查阅了不少资料,发现现在很少相关的内容资料。尤其是TSR删除这一块几...
  • cly116
  • cly116
  • 2015年06月06日 13:01
  • 1019

一个关于内存驻留的汇编源代码

  • 2016年11月09日 18:27
  • 35KB
  • 下载

一个关于内存驻留的汇编源代码

  • 2002年08月14日 00:00
  • 35KB
  • 下载

程序从DOS/bios驻留内存到WINNT下监视读入内存数据

 创建时间:2008-04-01文章属性:原创文章提交:cheng5103 (cheng_5103_at_126.com)作者:成松林QQ:179641795Email:cheng_5103@126....

Android应用程序的内存分析

  • 2015年07月14日 15:05
  • 97KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:内存驻留程序
举报原因:
原因补充:

(最多只允许输入30个字)