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

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

用汇编编写DOS下的内存驻留程序(1)=page&child=view&pid=744用汇编编写DOS下的内存驻留程序(1)翠落的草(Poet月下舞者)发表于2009-10-2510:44:11序言0.1内存驻留与中断内存驻留程序英文叫TerminateandStayResidentProgram,缩写为TSR.这些程序加载进内存,执行完后,就驻留在内存里,当满足条件时,调到前台来执行。内存驻留程序的常用形式有:诸如Borland的SideKick弹出式实用程序日历系统网络服务器通讯程序本地的DOS扩展(如CCDOS,UCDOS等中文系统都属于这个范畴)一些可恶的人利用TSR技术制作很多可恶的病毒程序,几乎所有的病毒程序都是TSR程序.就象多任务系统调度一个进程有一个调度程序一样,在PC中从前台程序进入到一个TSR,也要有一个调度者,只是PC操作系统的调度不称为调度程序,而只称为触发机制.触发机制调度TSR执行在PC机上党称为激活一个TSR.触发机制主要有以下几种:硬件中断:党用的是键盘中断INT9H,时钟中断INT8H,通讯中断INT14H,磁盘中断INT13H等等.软件中断:党用的是键盘中断INT16H,时钟中断INT1CH,DOS中断INT21H,等等.以上各种的结合.从以上的触发机制可以看出,TSR和PC机的中断系统有着密切的关系.每种激活方式实际上都是与中断有关的.常用特殊的击键序列的识别码是通过截获INT9H和INT16H来实现.实际上不管TSR程序的哪一个环节,都与中断有着密切的关系.因此在具体进行TSR和程序设计之前,先介绍PC中断系统.在此只作简单说明.在PC机内存的最低端(0000H开始)的1K字节中,存放着256个指针即常说的中为向量或中断矢量(Interruptvertor),每个中断向量都指向一个子程序,该程序称为中断处理程序(Interruphandler).一个中断向量由四个字节组成,有一个字是中断处理程序的偏移量值,后一个字是中断处理程序的段值.256中断向量一起称为中断向量表.手式计算中断向量的首址,可通过以下的公式来求得:X号中断向量的首址=0000H:X*4当产生一个中断时,处理器都按顺序执行以下步骤:在堆栈上压入处理器的标志(相当于指令PUSHF).在堆栈上压入当前CS和IP值(相当于指令PUSHCS和PUSHIP).关闭中断(CLI)从中断向量加载的CS和IP,执行中断处理程序.当执行完中断处理程序后,一般用IRET返回,它的作用是:从堆栈上取出保存的IP和CS(相当于指令POPCS和PUSHCS).同时恢复中断前的处理器标志(相当于指令POPF).中断有多种分类,由触发的原因和实现的性质来分,可分为硬件中断和软件中断,从操作系统分层实现来说,可以分成BIOS中断,BOS中断和用户中断.一方面,BIOS和DOS通过中断系统向用户提供一个操作系统功能界面.也就是说用户(一般来说是前台程序)的功能主要是通过调用DOS和BIOS的中断服务来实现的,具体来说就是通过INT指令来实现的.另一方面,BIOS和DOS由中断系统所构成,BIOS对硬件成为高层的功能,并通过中断的形式向用户提供.如果在当前程序执行的同时,能将一块代码放在内存,把中断向量指向代码中的子程序,那么在当前程序执行中产生中断时,就有可能执行不属于当前程序和操作系统的代码,产生的中断可能是当前程序产生的软件中断,也可能是由硬件产生的硬件中断.这就是单任务的PC操作系统可能执行多于一个进程的简单说明.在PC中断系统中有几个中断具有周期性,即INT8H,INT1CH和INT28H.它们或者周期性被执行用于时间计时,或者周期性产生用于等待.它们是在实现TSR时进行轮询触发的基础.键盘中断(INT9H和INT16H)当用户击键时发生,利用它们是进行热键处理的基础.串行口通讯也是触发的一个重要机制.此外众多的软件中断也是触发的媒介.0.2DOS的可重入性分析一个多任务操作系统之所以能使多个进行并存,是因为操作系统的大部分代码是可以了重的,对于临界资源有相应的PV操作,使得当调度一个新的进程时,能完整地保存前一个里程的现场,当再一次调度被挂起的进程时能象没有被中断一样继续执行.对于PC机来说,代码的重入性比较弱,对临界资源没有PC操作.当我们用中断程序启动用户的TSR时,如果只保存标志和寄存器,以及当前进程一些信息,那么只保存了当前程序的一部分现场,DOS的临界资源不会自动保存.在进行TSR设计时,一定要了解PC操作系统的重入性和临界资源.重入性总是体现在代码上,所谓可重入代码的指这样的代码,即该代码被执行时还没有从中退出,由于某种原因又一次或者多次进入相同的代码,该代码每次的执行结果都是正确的,就说该代码是可重入的.相反,如果结果不正确,那么就就该代码是不可重入的.下面是一个可重入的子程序的例子:AddprocnearcmpDS:wordptr[si],0jeDonotAddTheValueaddax,DS:wordptr[si]DonotAddTheValue:retAddendp上面的例子不管在其中任何一处再一次执行该子程序,执行结果不变.为了说明,只举多种可能性中的一种.movds,0100h;ds=0100hmovsi,0010h;si=0010hmovax,0001h;ax,=0001hcallAddcmp0100h:wordptr[0010h],0;CallAddsubroutinepushds;Interruptedpushsipushaxmovds,0200h;ds=0200hmovsi,0200h;si=0020hmovax,0003h;ax=0003hcallAddcmp0200h:wordptr[0020h],0;0200:0020h=0004hjneaddax,0200h:wordptr[0020h];ax=0007hret;Returnpopax;ax=0001hpopsi;si=0010hpopds;ds=0100hiret;ReturntoAddsubroutinejneaddax,0100h:wordptr[0100h];ax=0001h;0100h:0010h=0002h;----------------------------------------;ax=0003hretmovbx,ax而下面的子程序是不可重入的:AddprocnearmovTemp,axmovax,DS:wordptr[si]cmpax,0jeDonotTheValueaddax,TempDonotTheValue:retTemp:dw0Addendp可以利用检查可重入子程序的方法检查这个子程序的不可重入性,尝试一下在movax,DS:wordptr[si]指令后再次执行该子程序,那么就会出第一次调用返回的结果不对.movds,0100h;ds=0100hmovsi,0010h;si=0010hmovax,0001h;ax,=0001hcallAddmovTemp,ax;CallAddsubroutine;Temp=0001hmovax,0100h:wordptr[0010h];0100h:0010h=0002h;ax=2pushds;Interruptedpushsipushaxmovds,0200h;ds=0200hmovsi,0020h;si=0020hmovax,0003h;ax=0003hcallAddmovTemp,ax;Temp=0003hmovax,0200h:wordptr[0020h];0200h:0020h=0004hcmpax,0;ax=0004hjne;Notequal,addaddax,Temp;ax=0007hret;Returntotheinterruptedpointpopax;ax=0002hpopsi;si=0010hpopds;ds=0100hiret;ReturntoAddsubroutinecmpax,0;ax=2jne;Noequal,addaddax,Temp;ax=0002h;0100h:0010h=0003h;----------------------------------------;ax=0005hretmovbx,ax上面执行的结果是AX=5,实上正确的结果应该是AX=3,这是由于当Add子程序从中断子程序再一次被调用时,修改了Temp的值,当从中断返回时不能正确恢复其值.解决的方法是把Temp放在堆栈中,当每次Add子程序被调用时Temp的地址都不一样,因此原调用的Temp值不会被第二次在中断中调用的Add所破坏.Addprocnearpushbp;StoreBPsubsp,2;distributeabytespaceinthestackmovbp,sp;SS:BPpointtothestackheadtempequSS:wordptr[BP+0];ExplainthepointertoSS:BPmovTemp,axmovax,DS:wordptr[si]cmpax,0jeDonotAddTheValueaddax,TempDonotAddTheValue:addsp,2;Releasethedsitributedspaceinthestackpopbp;RestoreBPretAddendp对于DOS来说,DOS的内存数据就象Temp变量,它被分配在数据区,而不在堆栈上,因此DOS从总体上是不可重入的.从最后的一个例子看来.重入性跟堆栈有很大的关系.可重入代码允许在任何时候被中断,其所有的变量都存放在该代码的私有堆栈中.DOS是一个单任务的操作系统,在执行INT21H的代码时是不允许中断DOS,并再次调用INT21H的.每个时该最多有一个进程在调用DOS的代码.对DOS的重入性,以及相应所作的处理总结如下:当通过INT21H调用DOS时,DOS会使三个内部栈之一:I/O栈,磁盘栈和辅助栈.功能00H到处0CH使用I/O栈,除了不致命错误处理程序以外使用磁盘栈,致命错误处理程序使用辅助栈.在这种栈切换模式下,如果前台处在INT22H中,而TSR调用了使用相同栈的DOS功能,就会使前台程序保存栈中的数据被TSR的数据覆盖掉;但如果调用不同栈的DOS功能,那将是安全的.INT21H中的几个功能调即33H,50H,51H,62H,和64H由于非常简单,使用用户栈,因此在任何情况下都是可重入的.避免这种不可重入的简单方法是当前台程序正处在INT21H中时,不要调用INT21H.或者如果前台程序正在处理INT21H时,只允许调用不同栈的INT21H功能.DOS数据区中有一个InDOS标志,也探源为DOS安全标志,表示当前访问DOS功能是来否安全.由于DOS不可重入,它指示当前是否处于DOS中,激活TSR和代码可检查该标志(34H),如果DOS忙,则不能激活使用INT21H调用的TSR.当前台程序执行能设置错误状态的DOS功能时,DOS会把扩展错误信息存放起来,正常情况下,前台程序可以读取扩展错误信息;如果在前台程序读取信息之前激活TSR,且TSR也执行能报告错误信息的DOS功能,则后来的错误信息会覆盖原来的错误信息,前台程序就会得不到正确的错误信息.因此必须在激活TSR之前保存(59H)这些错误信息,并在退出以前把它们恢复(5D0AH)成原来的值.大多硬件中断如INT13H,INT0BH和INT0CH等都是不可重往返.如果设置一引起寄存器,而在此时被TSR打断,执行类似的设置,就会出现非常情况,端口是不会自动保持值的.在进入这些中断时设置一个进入的标志,如果TSR检查到标志已置,则不调用相应的中断.最好也不要重入INT10H,INT25H,和INT26H中断.在进入这些中断时设置一个进入的标志,如果TSR检查到标志已置,则不调用相应的中断.最好能接管

1 / 39
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功