这篇文章是我十年前写的第二篇在杂志上发表的文章。发表在微电脑世界1997年的第三期上。
那个年代我对计算机病毒也非常感兴趣。在九二年我刚上大学时候,对计算机病毒其实一点概念也没有,只是感觉计算机病毒是很神秘很高深的东西。对于病毒程序能够在不同电脑之间传播,那时感觉很不可思议。
那的确是个很古老的时代,我们用的操作系统是DOS 3.31,学的是TRUE BASIC,电脑是33M主频的PC/AT,286是当时最先进的机器。那时候的电脑病毒也很有意思,比如小球病毒,就是一个活蹦乱跳的小圆点,不停地运动,当碰到屏幕边沿就立刻反弹。雨点病毒则是一些下落的雨点或字符。64/Bloody病毒则是在屏幕上显示血红的Bloody文字。
计算机系的大学老师们对病毒其实也很感兴趣,记得一个老师曾经指着小球病毒的汇编代码跟我们说:整个中国会编这个病毒的人不超过10个。
最开始的病毒破坏力都很小,在现在看来,甚至有些可爱。我估计都是一些高手在编写病毒,写病毒的目的大概是为了炫耀自己的编程能力。DOS病毒几乎全是用汇编写的代码,汇编语言其实和二进制机器语言差不多,用那个东西写程序可真是一场噩梦啊,我曾经写过一个八百多行的汇编程序,写的我头晕脑涨,我知道,用汇编来写一个病毒的确不是一件容易的事情,特别是一些病毒甚至还有自身加密、变种的功能,因此,那些人也的确值得炫耀一下的。不过现在,汇编语言我都快忘光了,原因很简单,用机器代码写程序的可维护性很差,自然用的人也肯定会越来越少。
大学毕业后的几年,我逐渐对这些失去了兴趣,主要因为一些计算机业的害群之马影响了我的心情,CIH病毒开了一个恶劣的开头,对电脑用户的资料信息甚至硬件进行恶性破坏,而后的病毒似乎在比谁更不要脸,现在互联网的普及,以及一些脚本语言的流行,编写木马病毒门槛非常低了,菜鸟都可以写木马病毒了,而现在的木马病毒清一色全是恶性病毒,不是偷密码、弹广告就是改IE,甚至还出了HAO123这样依靠木马病毒发家的“成功案例”,但这些病毒的编写目的都令我感到恶心,对于那些低劣的病毒编写者,我只觉得他们可怜,让他们继续为了他们那低劣的理想和愿望而编写病毒吧,我还有更重要的事情要做呢。
下面是我写的论文,其目前已经没有实际意义,因为外部环境发生了巨大变化,我写那篇论文的前提是“计算机病毒大部分不是恶性病毒”的基础上,甚至执行病毒代码来还原恢复原始程序,现在的环境下这已经不可能了,现在是什么世道?谁敢运行病毒啊!
计算机病毒的通用清除技术
摘要 本文就当前流行的文件型病毒出发,分析介绍了从文件结构特性入手清除计算机病毒的一种技术.
关键字 病毒 传染 加载执行(EXEC) 文件前缀段(PSP) 进程
第一章 引言
计算机病毒的发展历史悠久,从80年代中后期广泛传播开来.时至今日,据统计世界上已存在的计算机病毒有5000余种,并且每月以平均几十种的速度增加.计算机病毒的发展一定程度上影响了反病毒产品的发展,原有的反病毒技术在新型病毒面前显得陈旧而无能为力.病毒检测产品是以病毒的特征码为基础的针对具体病毒的判断技术,因此,病毒的变种以及未知病毒给检测软件带来较大的困难.病毒的清除是建立在病毒检测的基础上,目前病毒的清除实际上是针对已知病毒.这种被动式的方法使反病毒技术总是落后于病毒技术,虽然这类反病毒产品对病毒的抑制是不容忽视的,但它所暴露出来的漏洞却越来越多.新一代的开放式反病毒技术应运而生,这种开放式反病毒技术将病毒的结构用一个统一的数据结构加以描述,用户可以根据自身对病毒进行分析,并具有更加灵活的升级优势,对于新一代具有反跟踪,加密技术的多维变异病毒,这种方法显示出其灵活及高效的特色,这种广谱型的查毒杀毒系统将逐渐成为反病毒产品的发展趋势.
下面,本文将介绍一种基于可执行文件结构特性的通用杀毒技术.
第二章 计算机病毒的机理
首先,我们先了解一下计算机病毒的结构特点以及其工作原理.
计算机病毒的结构决定了计算机病毒的特点,大致归纳如下:
(1) 计算机病毒是一段可执行的程序
计算机病毒和其它合法程序一样,是一种可存储可执行的非法程序,它可以直接或间接地运行,可以隐蔽在可执行程序和数据文件中而不易被人们察觉和发现.在病毒程序运行时,其与合法程序争夺系统的控制权.
(2) 计算机病毒的广泛传染性
由于病毒一词来源于“生物学”,传染也相应成为计算机病毒的一个重要特性.传染性是衡量一种程序是否为病毒的首要条件.计算机病毒的传染性是计算机病毒的再生机制,病毒程序一旦进入系统与系统中的程序接在一起,它就会在运行这一被传染的程序之后开始传染其它程序.这样一来,病毒就会很快地传染到整个计算机系统.
(3) 计算机病毒的潜伏性
计算机病毒的潜伏性是具有依附于其它媒体而寄生的能力.一个编制巧妙的计算机病毒程序,可以在几周或者几个月甚至几年内隐藏在合法文件之中,对其它系统进行传染,而不被人们发现.计算机病毒的潜伏性于传染性相辅相成,潜伏性越好,其在系统中存在的时间就会越长,病毒的传染范围也就会越大.
(4) 计算机病毒的可触发性
计算机病毒一般都有一个触发条件:或者触发其传染,或者在一定条件下激活计算机病毒的表现部分或破坏部分.触发实质上是一种条件控制,一个病毒程序可以按照设计者的要求,在某个点上激活并对系统发起攻击.
(5) 计算机病毒的针对性
现在世界上出现的计算机病毒,并不是对所有计算机系统都进行传染的.例如,有针对IBM PC及其兼容机的,有针对APPLE公司的Macintosh的以及针对Unix操作系统的.现在流行的绝大多数计算机病毒都是针对基于MS DOS系统的IBM PC及其兼容机的.
(6) 计算机病毒的衍生性
由于计算机病毒本身是一段计算机系统可执行的文件(程序),所以这种程序反映了设计者的一种设计思想.同时,又由于计算机病毒本身也是由几部分组成的,如安装部分,传染部分和破坏部分等,因此这些模块很容易被病毒本身或其它模仿者所修改,使之成为一种不同于原病毒的计算机病毒.[1]
计算机病毒按链接方式可分为以下几类:
(1)源码型病毒 (Source Code Virus) (2)入侵型病毒 (Intrusive Virus) (3)操作系统病毒 (Operating System Virus) (4)外壳型病毒 (Shell Virus).
(1)(2)攻击的是高级语言编写的源文件及目标文件,在微机上很少见, (3)即引导区病毒,主要攻击计算机的Boot区,其诊治方法较为简单,一般用DEBUG或NU等工具就能方便地清除.本文所提的病毒专指目前在PC在机上流行最广的攻击可执行文件的外壳型病毒.
计算机外壳型病毒是将其自己包围在主程序的四周,对原来的程序不作修改.外壳型病毒易于编写,也较为常见,但诊治却较为麻烦.
外壳型病毒具有以下特点:
自身复制在目标文件外围(即文件尾部);不修改原来正常文件[2];运行时病毒抢先进入内存.病毒执行完后,转回原文件入口运行(隐蔽性).
在基于DOS操作系统PC机上,外壳型病毒主要攻击的目标是两类可执行文件:COM文件与EXE文件.COM文件结构比较简单,解毒比较容易.而广泛流行的EXE文件相对复杂,但操作却更灵活,适合于超过64K的程序,更易与将来的操作系统兼容,因此得到广泛的使用.
第三章 COM病毒的清除
一 实现原理
COM文件是DOS的一种二进制代码的可执行文件,COM文件结构比较简单,加载过程十分迅速.整个程序只有一个段.因此全部代码长度必须小于64K,其入口代码地址是CS:100H. DOS装入COM文件时,先在内存建立一个长度为100H的程序前缀段(PSP,由DOS建立,是DOS用户程序和命令行之间的接口),然后将整个文件装载于PSP上端,不进行重定位操作,接着将四个段地址寄存器DS(Data Segment),CS(Code Segment),SS(Stack Segment),ES(Extra Segment)初始化为程序前缀段(PSP)的段地址,最后将程序的控制权交于CS:100H处.如表1所示.
表1: COM文件的装入执行
地址 | 内容 | |
XXXX:0000 | PSP | ← CS,DS,ES,SS |
XXXX:0100 | 程序代码 | ← IP |
数据 | ||
堆栈 | ← SP |
寄生于COM文件的病毒,大部分是采用保存文件头若干字节,并将第一条指令改为”JMP 病毒入口”,以确保病毒最先执行,也有部分病毒附加在文件首部,病毒执行完后恢复寄生程序原先的状态,并用JMP FAR等指令使程序再次回到CS:100H处,以确保寄生程序与PSP的一致.
可见,病毒执行完后,必将会恢复并运行原文件,以便传播,当其将原文件参数全部恢复后,会将控制权交于CS:100H处.因此,判别COM文件的真正入口的标准是:最后一次在CS:100H处执行的程序段(CS=当前PSP段地址,IP=100H).
于是,可以设想出这样一种跟踪器,每执行一条指令,便判断上述条件是否满足,如果满足,则此时CS:100H处的代码便是原文件的影像,由于COM文件只有一个段,因此此时内存的影像既是磁盘文件的内容.将CS:100H处的代码写回原文件,此病毒即被消除了,如果知道病毒的长度,还可将文件尾的无用代码去掉,这样病毒就物理上消除了.
二 实现方案
设想的跟踪器的实现是核心问题,也是主要的难点.事实上单步陷阱中断(INT 1)完全符合跟踪器的条件,但由于目前的计算机病毒广泛采取破坏单步断点的技术,因此这种跟踪器在具体实现上还有一定难度.
目前有一种比较方便的替代方法,即DOS的EXEC(INT 21H的功能4BH,加载执行)功能,此功能有一个有趣的现象,即执行完加载程序后,它会将所有寄存器恢复到执行前的状态,并且它不清除内存,此方法易于实现,操作简便,但对所处理的文件有一定的要求及限制.
具体实现是,先保存中断向量表,然后在分配一块内存,调用DOS的EXEC功能执行被感染的COM文件.执行结束后,重写中断向量表以清除内存中的病毒,然后将内存偏移100H上的代码写入文件,文件长度为原文件长度,最后,在知晓病毒长度的情况下去掉文件尾的病毒代码,清除工作结束.
这种技术可以对付任何一种文件型病毒,但对于COM文件却有一定的要求:即文件在执行过程中不可以修改代码段的内容,未被加密或压缩的文件一般均可满足此条件.
四 使用调试器DEBUG.COM的EXEC功能
更简单的方法是用DEBUG来实现,先用L命令装入一个文件,再用G命令运行,EXEC功能结束后,返回寄存器与运行前完全一样,此时用W命令存盘,这时病毒便被清除了.(全过程只用了三条命令)
第四章 EXE病毒的清除
一 实现原理
EXE文件是DOS系统最为常见且灵活的可执行文件,其应用十分广泛.但EXE文件的结构要比COM文件复杂得多.EXE文件由文件头(Header)和装入模块(Load Module)两大部分组成.文件头由格式化区(Format Area)和重定位表(Relocation Table)组成.装入模块为程序代码部分,从位移量100H字节开始.DOS系统在调用EXE文件时,先在内存块底部建立一个程序前缀段(PSP),再将装入模块读入内存指定区域(PSP上方),DS和ES初始化为PSP段地址,CS,IP,SS,SP由文件头格式化区确定,并通过重定位参数调整.然后根据重定位项修改代码数据,最后将程序的控制权由CS:IP传递给目标程序. (如表2所示)
表2: EXE文件的装入执行
地址 | 内容 | |
XXXX:0000 | PSP | ← DS,ES |
XXXX:0100 | 数据 | |
程序代码 | ← CS:IP | |
堆栈 | ← SS:SP |
对于EXE文件而言,计算机病毒主要是附着于宿主文件的尾部,由于它必须首先获得程序的控制权,因此它必须对文件头进行修改.一般来说,只要恢复了正确的文件头,便可达到杀毒的目的.
EXE文件被加载时,系统根据EXE文件头的CS:IP参数确定第一条执行语句,因此病毒只需将CS:IP地址指针修改,便可首先执行,事实上,大多数病毒仅仅只修改了文件头,而未修改原文件内容.这便为完整地恢复原程序代码提供了条件.
从上面的分析可知,感染病毒的EXE文件尾部形成明显的层次,CS:IP指向病毒体,不管病毒采取什么样的措施,它最终必定会在内存中恢复宿主程序所有的真实参数,并且用一条长跳转指令返回原程序.这时,我们便可直接提取出正确的CS:IP和SS:SP参数指针,用它修改文件头后,再将外层病毒代码去掉,这便彻底地恢复了原EXE文件.
问题在于如何找到EXE文件的正确入口.判断EXE文件的真正入口是十分复杂的,但对于基于DOS系统的病毒来说,其编写语种基本上是汇编语言,因此便具有一些独特的特点.经过大量分析看出,一般情况下,当EXE病毒执行到真正的文件开头时,其CS和DS均要改变,并且DS内容必定是PSP段地址,SS:SP指针被初始化,对于不修改重定位表的病毒来说,CS:IP指针应处于重定位区域内.
于是,可以再设想出这样一种跟踪器,每执行一条指令,便判断上述条件是否满足,如果满足,则此时CS:IP处的代码便是原文件的影像,根据CPU各个寄存器的内容便可正确地恢复EXE文件头,以达到杀毒的目的.
二 实现方案
同COM文件杀毒一样,这种理论上的跟踪器实际上是很难奏效的.因此,我们又要求助于我们的老朋友--EXEX功能.
MS DOS的功能4B有两个重要的子功能:4B00为装入并执行,4B01为装入不执行(未公开的文档功能),4B00用于执行所有的可执行程序,4B01则用于DEBUG调试器中的装入功能.(关于4B01功能的具体参数见附录1).
由于问题的关键在于如何找到原程序的第一条指令,也就是说在执行到原程序的第一条指令时发生中断,因此我们可以人为地将第一条指令改为中断指令.为了完成这种功能,只需用4B01功能来仿真4B00功能.
具体是这样做的,当系统调用加载执行功能4B00时,先用功能4B01加载,并初试化所有参数,这时内存的影像应如表3所示.
表3: EXE 染毒程序内存影像
地址 | 内容 |
原程序代码区 | |
CS:IP→ | 病毒代码区 |
假定病毒的第一条指令处于病毒代码的最前端,原程序的内存影像应为PSP:100~CS:IP(病毒的第一条指令),将这部分区域全部用ASCII码CD填充.这样,原程序的每一条指令都变成了中断指令INT CD(不用INT 3断点中断是因为大部分病毒都具有破坏单步断点中断的功能),也就是说,无论从原程序的任何地址开始运行,所执行的第一条指令都是INT CD.这样,一旦病毒代码执行完毕,打算用长跳转指令返回原程序执行时,都会触发软中断INT CD,而通过INT CD的中断服务程序便可取得EXE文件头真正的初始化CS:IP和SS:SP指针.
另外值得注意的是,修改后的INT 21必须是可递归的,因为有些病毒(如新世纪病毒)是通过第二次加载原程序来返回的,因此,内存填充要进行两次.4B01也被调用了两次.
此方法的效率和准确度要远远高于用DEBUG等工具逐步跟踪分析的手工杀毒法.可以为各种染上已知或未知病毒的文件去除病毒外壳.与RCOPY等去壳程序不同的是,这种方法对EXE程序的恢复是全真的恢复,它并不改变原EXE文件的任何内容.它所恢复的EXE程序代码应与原EXE程序代码完全一样.另外,此法由于采用了剥壳还原法,因此还可以用来清除交叉感染的病毒,方法是从外到内逐层脱壳,最后彻底恢复最内层的宿主文件.
第五章 结论
本文所论述的这种清除病毒的方法的实现原理是非常独特的.当然,文中所给出的实现方案并不能清除所有的计算机病毒,但它却给出了一种思想,即抛弃以前那种一个杀毒算法只能杀一个病毒,而是一个算法可以杀一类病毒.根据这种思想,笔者已用C语言和汇编语言编写出这个通用杀病毒程序,并且用大量的病毒对它进行了测试,效果良好.当然,病毒是五花八门的,因此一个统一的病毒对抗软件应接受广泛的考验.其具体的功效还需要多方面的验证,笔者也仅仅希望这种思想能够在反病毒领域发挥出积极的作用.
参考文献
1. 李向宇 著 <<计算机病毒概论>> IDG国际数据集团 1990
2. Ray Dancan <<高水平MS DOS程序设计>> 电子工业出版社 1988
Ray Dancan Advanced MS-DOS Programing Microsoft Press 1988
3 . Ray Dancan <<MS DOS百科全书>> 电子工业出版社 1990
Ray Duncan the MS-DOS Encyclopedia Microsoft Press 1990
附录:MS-DOS EXEC功能详解
翻译人:William Long 于1996年 译自:MS DOS百科全书(Ray Duncan: the MS-DOS Encyclopedia)
MS-DOS系统的加载,即把磁盘上的COM及EXE文件装入内存并执行,可以被任何程序使用MS-DOS功能(功能4BH,加载执行)产生.DOS的命令解释程序COMMAND.COM使用EXEC装入它的外部命令,如CHKDSK,或其它应用程序.许多流行的商业软件,例如数据库和字处理,都使用EXEC执行辅助程序(例如拼写检查),或是装入COMMAND.COM的另一个副本,这就允许用户在不失去当前工作上下文时运行一个辅助程序或打入MS-DOS命令.
当EXEC被一个程序(父进程)调用并加载另一个程序(子进程),父进程可以通过一串字符即环境块,命令行及两个文件控制块,来传输一定的信息给子进程.子进程同样继承了父进程的MSDOS标准设备及其它父进程打开的设备的句柄(除非打开的操作有"非继承性"的选择).任何操作都可被子进程的继承句柄执行,例如定位或文件输入输出,而且还影响着与父进程句柄联系着的文件指针.子进程也可装入另一程序,如此循环直至系统内存溢出.
因为MSDOS并非一个多任务的操作系统,子进程直到运行结束才交出系统控制权,父进程此时被挂起,这种进程操作有时也叫做同步执行.当子进程中止,父进程得到控制权并可用另一个系统功能调用(INT 21H功能4DH)取回子进程的返回码并检查子进程的中止是否正常,或是一个重大的硬件错误,比如用户按了Ctrl-C.
除了装入子进程外,EXEC还可以被用来装入由于用汇编或高级语言写成而不能包含在其库文件中的子程序或应用程序的覆盖文件,这种类型的覆盖文件不能单独运行,多数需要主程序的段内的"帮助"工作或数据.
EXEC功能仅存在MSDOS 2.0版以上,在MSDOS 1.X版中,父进程可以用INT 21H的功能26H建立一个子进程的程序前缀段,但必须自己完成装载,重定位,执行代码的过程,而不是依靠操作系统的帮助.
EXEC是怎样工作的
当EXEC功能接到一个执行程序的请求时,它首先试图打开并定位指定的程序文件.如果文件没有找到,EXEC立刻失败并返回调用者一个错误码.
如果文件存在,EXEC打开此文件,确定它的大小,并检查文件的首块.如果块的头两个字节是ASCII码MZ,文件便设定为一个EXE装入模式.程序代码段,数据段,堆栈段的大小可以从文件头获得.否则,整个文件便设定为一个决对装入影像(COM程序).实际的文件名后缀(COM或EXE)在这个测试中被忽略.
此时,内存所需要装入程序的大小是知道的,假如有足够的空间装入程序,EXEC便在内存分配两个块:一个包括新程序的环境块,另一个包括程序的代码段,数据段和堆栈段.不同类型的程序实际分配的大小不同.COM程序得到系统中全部的空余内存(除非内存空间过早形成碎块),而分配给EXE程序的空间大小是由文件头的两个字段控制,MINALLOC和MAXALLOC,它是由LINK设置的.
EXEC接着将父进程的环境块拷入子进程的环境块,在子进程内存块的底部建立一个程序前缀段(PSP).并将命令行及缺省文件控制块拷入PSP.以前的终止地址(INT 22H),Ctrl-C(INT 23H)
及严重错误(INT 24H)中断向量的目录存入新的PSP,终止地址向量被更新,以便子进程终止或失败时控制能够返回到父进程.
接着子进程的实际代码和部分数据便由磁盘文件读到新PSP结构上方的程序内存块.如果子程序是一个EXE文件,文件头的重定位表常用于在程序里定位参考段以便反映出它实际的装入地址.
最后,EXEC功能建立为程序的CPU寄存器和堆栈并将控制传给程序.COM文件的入口指针常是程序内存块中偏移100H(PSP后第一个字节).而EXE文件的入口地址由文件头指定,可以在程序中任何位置.
当EXEC用于装入并执行一个覆盖文件而不是子程序时,它的操作会比上述更为简单.对于覆盖文件,EXEC并不试图分配内存或建立PSP及环境块,它只简单地将文件的内容装入调用文件所指定的地址,并执行一些必要的重定位(如果覆盖文件有一个EXE文件头).使用的段值也是由调用者提供.EXEX接着并不是将控制传给最新装入文件的代码,而是返回所产生的程序,请求程序负责在适当的位置调用覆盖.
使用EXEC装入程序
当一个程序装入并执行另一个程序时,它必须执行以下几步:
1.确认有足够的空闲内存来装入子进程的代码,数据和堆栈.
2.建立EXEC和子进程所需要的信息.
3.调用MSDOS的EXEC功能运行子进程.
4.恢复并测试子进程的结束及返回码.
分配内存
MSDOS典型地分配给被加载的COM或EXE文件所有可用的内存.一个不常见的例外是当一个由/CPARMAXALLOC开关联接或被EXEMOD修改的EXE程序会由它先前驻留的数据或代码分裂一个短小的程序块.所以,当一个程序要装入另一个程序之前,它必须释放所有它本身代码数据堆栈所不用的内存.
释放多余的内存是调用MSDOS的重分配内存块功能(INT 21H,功能4AH).此时,ES寄存器置父进程的PSP段地址,BX寄存器置程序自身必须使用的内存块数,如预期的父进程是COM程序,且它减少它的内存分配数低于64K时,它必须移动它的堆栈到一个安全的空间.
准备EXEC的参数
当使用装入和执行一程序时,必须提供EXEC功能两条参数:
1.子程序路径名的地址.
2.参数块地址.
参数块依次包括子程序所需信息的地址.
程序名
子程序的路径名必需是明确的,零结尾(ASCIIZ),规定文件名(没有非识别字符).如果没有包含路径,便在当前目录下寻找程序,如果无驱动器名,则使用默认驱动器.
参数块
参数块包括四个数据项地址:
1. 环境块
2. 命令行
3. 二个缺省文件控制块(FCBs)
在参数块中为环境块指针准备的空间只有两个字节,包括一个段地址.这是因为环境块总是排在段落上(它的地址总可以被16整除).值0000H表示子进程的环境应被毫不改变地继承.余下的三个地址全是双字节地址,是标准的Intel格式,一个低字的段偏移,一个高字的段地址.
环境块
一个环境块总是从一个边界段开始,包含一系列的以0结尾的字符串(ASCIIZ),形式如下:
name = variable 全部字符串的结尾以一个附加的0表示.
如果在参数块中的环境块指针提供给一个EXEC的调用包含0,那么子进程只需简单地拷贝父进程的环境块.父进程能够提供一个不同或是增长一组字符串的段指针.另一方面,在MSDOS 3.0
以后的版本里,EXEC使子程序的环境块具有完整的路径名.环境块最大为32字节.通过这种途径,这么大的信息也可被程序识别.
最初的(或主控的)系统环境块属于系统接通或重新启动后的命令处理程序(通常是COMMAND.COM)所装入的.COMMAND.COM将字符串PATH,SHELL,PROMPT和SET命令的结果写入系统的主环境块.前两个通常使用的是默认值.例如,一个MSDOS 3.2版的系统从C驱启动,在AUTOEXEC.BAT文件中无PATH命令,CONFIG.SYS文件中也无SHELL命令,则主环境块将下面两行字符串写入:
PATH =
COMSPEC = C: \COMMAND.COM
COMMAND.COM为运行"外部"命令而寻找这些说明清单,同时也为了找到自身在磁盘上的可执行文件以便它能在必要的时候重新装入它的暂态部分.当PROMPT字串存在时(先前的PROMPT或SET PROMPT命令产生的结果),COMMAND.COM它来修订用户的提示显示.
环境块中的其它字符串仅仅为了特殊程序提供信息,它不影响操作系统的操作.例如,Microsoft C 编译器和 Microsoft Object 连接器在环境块中寻找INCLUDE,LIB和TMP字符串,以确定头文件,库文件,临时文件的指定位置.图2给出了一个典型的环境块的十六进制显示图.
命令行
命令行是传给子进程的,它包括一字节指明余下命令行的长度,紧接着的ASCII字符串是以ASCII码回车(0DH)为结束的.回车码并不包含在长度值里.命令行可包括子进程可以检查到的所有开关,文件名,以及其它参数,用以影响程序的操作.命令行被拷贝到子进程PSP偏移80H处.
当COMMAND.COM使用EXEC运行一个程序时,它的命令行包括除程序名或重定向参数外所有用户打下的命令.I/O的重定向是在COMMAND.COM内部处理的,它表明子进程继承了标准设备句柄的活动.其它程序使用EXEC来运行子进程必须自己做一些必要的重定向而且必须提供一个合适的命令行,以便子进程表现得如同被COMMAND.COM装入一样.
确省的文件控制块
EXEC参数块的二个确省的FCBs指向拷贝到子进程PSP的偏移5CH和6CH.
当前只有极少数应用程序使用FCB作为文件和记录的I/O.这是因为FCBs不支持目录树结构.但有些程序检查确省的文件控制块作为分离前二个开关或其它命令行参数的快速的方法.然而,使它自己本身对子进程透明,父进程应该仿效COMMAND.COM那样把命令行前二个参数装入确省的文件控制块.这能使MSDOS的分析文件名功能(INT 21H,功能29H)能方便地使用.
如果子进程不需要这二个确省的文件控制块,应用程序内存中的参数块中正确的地址会初始化指向二个空FCBs,这些空FCBs是由1字节0和11字节ASCII码空格(20H)组成.
运行子进程
当父进程构造完所必要的参数后,它就可以通过中断21H来调用EXEC,各寄存器设置如下:
AH = 4BH
AL = 00H (EXEC子功能,装入并执行程序)
DS:DX = 程序路径名的段地址:偏移址
ES:BX = 参数块的段地址:偏移址
从以上软件中断返回后,父进程必须要测试一下进位标志,以此来检测子进程是否实际运行过.如果进位清楚,则成功装入并控制了子进程.如果进位置位,则EXEC功能失败,错误码返回在AX中,可检测原因.通常的原因是:
指定文件没有找到
文件找到,但没有足够的内存装入
其它不常见的服务错误可以从整个系统感到其特征(如磁盘文件或内存中的MSDOS被损坏),使用MSDOS 3.0以后的版本,可以通过调用INT 21H功能59(取扩展错误信息)来获得EXEC更详细的失败原因.
总的来说,提供给EXEC参数块一个无效地址或参数块本身地址无效并不会引起EXEC错误,但这将使子进程产生一些不可的后果.