這篇文章是我十年前寫的第二篇在雜志上發(fā)表的文章。發(fā)表在微電腦世界1997年的第三期上。
那個年代我對計算機(jī)病毒也非常感興趣。在九二年我剛上大學(xué)時候,對計算機(jī)病毒其實一點概念也沒有,只是感覺計算機(jī)病毒是很神秘很高深的東西。對于病毒程序能夠在不同電腦之間傳播,那時感覺很不可思議。
那的確是個很古老的時代,我們用的操作系統(tǒng)是DOS 3.31,學(xué)的是TRUEBASIC,電腦是33M主頻的PC/AT,286是當(dāng)時最先進(jìn)的機(jī)器。那時候的電腦病毒也很有意思,比如小球病毒,就是一個活蹦亂跳的小圓點,不停地運動,當(dāng)碰到屏幕邊沿就立刻反彈。雨點病毒則是一些下落的雨點或字符。64/Bloody病毒則是在屏幕上顯示血紅的Bloody文字。
計算機(jī)系的大學(xué)老師們對病毒其實也很感興趣,記得一個老師曾經(jīng)指著小球病毒的匯編代碼跟我們說:整個中國會編這個病毒的人不超過10個。
最開始的病毒破壞力都很小,在現(xiàn)在看來,甚至有些可愛。我估計都是一些高手在編寫病毒,寫病毒的目的大概是為了炫耀自己的編程能力。DOS病毒幾乎全是用匯編寫的代碼,匯編語言其實和二進(jìn)制機(jī)器語言差不多,用那個東西寫程序可真是一場噩夢啊,我曾經(jīng)寫過一個八百多行的匯編程序,寫的我頭暈?zāi)X漲,我知道,用匯編來寫一個病毒的確不是一件容易的事情,特別是一些病毒甚至還有自身加密、變種的功能,因此,那些人也的確值得炫耀一下的。不過現(xiàn)在,匯編語言我都快忘光了,原因很簡單,用機(jī)器代碼寫程序的可維護(hù)性很差,自然用的人也肯定會越來越少。
大學(xué)畢業(yè)后的幾年,我逐漸對這些失去了興趣,主要因為一些計算機(jī)業(yè)的害群之馬影響了我的心情,CIH病毒開了一個惡劣的開頭,對電腦用戶的資料信息甚至硬件進(jìn)行惡性破壞,而后的病毒似乎在比誰更不要臉,現(xiàn)在互聯(lián)網(wǎng)的普及,以及一些腳本語言的流行,編寫木馬病毒門檻非常低了,菜鳥都可以寫木馬病毒了,而現(xiàn)在的木馬病毒清一色全是惡性病毒,不是偷密碼、彈廣告就是改IE,甚至還出了HAO123這樣依靠木馬病毒發(fā)家的“成功案例”,但這些病毒的編寫目的都令我感到惡心,對于那些低劣的病毒編寫者,我只覺得他們可憐,讓他們繼續(xù)為了他們那低劣的理想和愿望而編寫病毒吧,我還有更重要的事情要做呢。
下面是我寫的論文,其目前已經(jīng)沒有實際意義,因為外部環(huán)境發(fā)生了巨大變化,我寫那篇論文的前提是“計算機(jī)病毒大部分不是惡性病毒”的基礎(chǔ)上,甚至執(zhí)行病毒代碼來還原恢復(fù)原始程序,現(xiàn)在的環(huán)境下這已經(jīng)不可能了,現(xiàn)在是什么世道?誰敢運行病毒啊!
計算機(jī)病毒的通用清除技術(shù)
摘要 本文就當(dāng)前流行的文件型病毒出發(fā),分析介紹了從文件結(jié)構(gòu)特性入手清除計算機(jī)病毒的一種技術(shù).
關(guān)鍵字 病毒 傳染 加載執(zhí)行(EXEC) 文件前綴段(PSP) 進(jìn)程
計算機(jī)病毒的發(fā)展歷史悠久,從80年代中后期廣泛傳播開來.時至今日,據(jù)統(tǒng)計世界上已存在的計算機(jī)病毒有5000余種,并且每月以平均幾十種的速度增加.計算機(jī)病毒的發(fā)展一定程度上影響了反病毒產(chǎn)品的發(fā)展,原有的反病毒技術(shù)在新型病毒面前顯得陳舊而無能為力.病毒檢測產(chǎn)品是以病毒的特征碼為基礎(chǔ)的針對具體病毒的判斷技術(shù),因此,病毒的變種以及未知病毒給檢測軟件帶來較大的困難.病毒的清除是建立在病毒檢測的基礎(chǔ)上,目前病毒的清除實際上是針對已知病毒.這種被動式的方法使反病毒技術(shù)總是落后于病毒技術(shù),雖然這類反病毒產(chǎn)品對病毒的抑制是不容忽視的,但它所暴露出來的漏洞卻越來越多.新一代的開放式反病毒技術(shù)應(yīng)運而生,這種開放式反病毒技術(shù)將病毒的結(jié)構(gòu)用一個統(tǒng)一的數(shù)據(jù)結(jié)構(gòu)加以描述,用戶可以根據(jù)自身對病毒進(jìn)行分析,并具有更加靈活的升級優(yōu)勢,對于新一代具有反跟蹤,加密技術(shù)的多維變異病毒,這種方法顯示出其靈活及高效的特色,這種廣譜型的查毒殺毒系統(tǒng)將逐漸成為反病毒產(chǎn)品的發(fā)展趨勢.
下面,本文將介紹一種基于可執(zhí)行文件結(jié)構(gòu)特性的通用殺毒技術(shù).
首先,我們先了解一下計算機(jī)病毒的結(jié)構(gòu)特點以及其工作原理.
計算機(jī)病毒的結(jié)構(gòu)決定了計算機(jī)病毒的特點,大致歸納如下:
(1) 計算機(jī)病毒是一段可執(zhí)行的程序
計算機(jī)病毒和其它合法程序一樣,是一種可存儲可執(zhí)行的非法程序,它可以直接或間接地運行,可以隱蔽在可執(zhí)行程序和數(shù)據(jù)文件中而不易被人們察覺和發(fā)現(xiàn).在病毒程序運行時,其與合法程序爭奪系統(tǒng)的控制權(quán).
(2) 計算機(jī)病毒的廣泛傳染性
由于病毒一詞來源于“生物學(xué)”,傳染也相應(yīng)成為計算機(jī)病毒的一個重要特性.傳染性是衡量一種程序是否為病毒的首要條件.計算機(jī)病毒的傳染性是計算機(jī)病毒的再生機(jī)制,病毒程序一旦進(jìn)入系統(tǒng)與系統(tǒng)中的程序接在一起,它就會在運行這一被傳染的程序之后開始傳染其它程序.這樣一來,病毒就會很快地傳染到整個計算機(jī)系統(tǒng).
(3) 計算機(jī)病毒的潛伏性
計算機(jī)病毒的潛伏性是具有依附于其它媒體而寄生的能力.一個編制巧妙的計算機(jī)病毒程序,可以在幾周或者幾個月甚至幾年內(nèi)隱藏在合法文件之中,對其它系統(tǒng)進(jìn)行傳染,而不被人們發(fā)現(xiàn).計算機(jī)病毒的潛伏性于傳染性相輔相成,潛伏性越好,其在系統(tǒng)中存在的時間就會越長,病毒的傳染范圍也就會越大.
(4) 計算機(jī)病毒的可觸發(fā)性
計算機(jī)病毒一般都有一個觸發(fā)條件:或者觸發(fā)其傳染,或者在一定條件下激活計算機(jī)病毒的表現(xiàn)部分或破壞部分.觸發(fā)實質(zhì)上是一種條件控制,一個病毒程序可以按照設(shè)計者的要求,在某個點上激活并對系統(tǒng)發(fā)起攻擊.
(5) 計算機(jī)病毒的針對性
現(xiàn)在世界上出現(xiàn)的計算機(jī)病毒,并不是對所有計算機(jī)系統(tǒng)都進(jìn)行傳染的.例如,有針對IBMPC及其兼容機(jī)的,有針對APPLE公司的Macintosh的以及針對Unix操作系統(tǒng)的.現(xiàn)在流行的絕大多數(shù)計算機(jī)病毒都是針對基于MSDOS系統(tǒng)的IBM PC及其兼容機(jī)的.
(6) 計算機(jī)病毒的衍生性
由于計算機(jī)病毒本身是一段計算機(jī)系統(tǒng)可執(zhí)行的文件(程序),所以這種程序反映了設(shè)計者的一種設(shè)計思想.同時,又由于計算機(jī)病毒本身也是由幾部分組成的,如安裝部分,傳染部分和破壞部分等,因此這些模塊很容易被病毒本身或其它模仿者所修改,使之成為一種不同于原病毒的計算機(jī)病毒.[1]
計算機(jī)病毒按鏈接方式可分為以下幾類:
(1)源碼型病毒 (Source Code Virus) (2)入侵型病毒 (Intrusive Virus) (3)操作系統(tǒng)病毒 (Operating System Virus) (4)外殼型病毒 (Shell Virus).
(1)(2)攻擊的是高級語言編寫的源文件及目標(biāo)文件,在微機(jī)上很少見,(3)即引導(dǎo)區(qū)病毒,主要攻擊計算機(jī)的Boot區(qū),其診治方法較為簡單,一般用DEBUG或NU等工具就能方便地清除.本文所提的病毒專指目前在PC在機(jī)上流行最廣的攻擊可執(zhí)行文件的外殼型病毒.
計算機(jī)外殼型病毒是將其自己包圍在主程序的四周,對原來的程序不作修改.外殼型病毒易于編寫,也較為常見,但診治卻較為麻煩.
外殼型病毒具有以下特點:
自身復(fù)制在目標(biāo)文件外圍(即文件尾部);不修改原來正常文件[2];運行時病毒搶先進(jìn)入內(nèi)存.病毒執(zhí)行完后,轉(zhuǎn)回原文件入口運行(隱蔽性).
在基于DOS操作系統(tǒng)PC機(jī)上,外殼型病毒主要攻擊的目標(biāo)是兩類可執(zhí)行文件:COM文件與EXE文件.COM文件結(jié)構(gòu)比較簡單,解毒比較容易.而廣泛流行的EXE文件相對復(fù)雜,但操作卻更靈活,適合于超過64K的程序,更易與將來的操作系統(tǒng)兼容,因此得到廣泛的使用.
COM文件是DOS的一種二進(jìn)制代碼的可執(zhí)行文件,COM文件結(jié)構(gòu)比較簡單,加載過程十分迅速.整個程序只有一個段.因此全部代碼長度必須小于64K,其入口代碼地址是CS:100H.DOS裝入COM文件時,先在內(nèi)存建立一個長度為100H的程序前綴段(PSP,由DOS建立,是DOS用戶程序和命令行之間的接口),然后將整個文件裝載于PSP上端,不進(jìn)行重定位操作,接著將四個段地址寄存器DS(Data Segment),CS(Code Segment),SS(StackSegment),ES(Extra Segment)初始化為程序前綴段(PSP)的段地址,最后將程序的控制權(quán)交于CS:100H處.如表1所示.
表1: COM文件的裝入執(zhí)行
地址 | 內(nèi)容 | |
XXXX:0000 | PSP | ← CS,DS,ES,SS |
XXXX:0100 | 程序代碼 | ← IP |
數(shù)據(jù) | ||
堆棧 | ← SP |
寄生于COM文件的病毒,大部分是采用保存文件頭若干字節(jié),并將第一條指令改為”JMP病毒入口”,以確保病毒最先執(zhí)行,也有部分病毒附加在文件首部,病毒執(zhí)行完后恢復(fù)寄生程序原先的狀態(tài),并用JMPFAR等指令使程序再次回到CS:100H處,以確保寄生程序與PSP的一致.
可見,病毒執(zhí)行完后,必將會恢復(fù)并運行原文件,以便傳播,當(dāng)其將原文件參數(shù)全部恢復(fù)后,會將控制權(quán)交于CS:100H處.因此,判別COM文件的真正入口的標(biāo)準(zhǔn)是:最后一次在CS:100H處執(zhí)行的程序段(CS=當(dāng)前PSP段地址,IP=100H).
于是,可以設(shè)想出這樣一種跟蹤器,每執(zhí)行一條指令,便判斷上述條件是否滿足,如果滿足,則此時CS:100H處的代碼便是原文件的影像,由于COM文件只有一個段,因此此時內(nèi)存的影像既是磁盤文件的內(nèi)容.將CS:100H處的代碼寫回原文件,此病毒即被消除了,如果知道病毒的長度,還可將文件尾的無用代碼去掉,這樣病毒就物理上消除了.
設(shè)想的跟蹤器的實現(xiàn)是核心問題,也是主要的難點.事實上單步陷阱中斷(INT 1)完全符合跟蹤器的條件,但由于目前的計算機(jī)病毒廣泛采取破壞單步斷點的技術(shù),因此這種跟蹤器在具體實現(xiàn)上還有一定難度.
目前有一種比較方便的替代方法,即DOS的EXEC(INT21H的功能4BH,加載執(zhí)行)功能,此功能有一個有趣的現(xiàn)象,即執(zhí)行完加載程序后,它會將所有寄存器恢復(fù)到執(zhí)行前的狀態(tài),并且它不清除內(nèi)存,此方法易于實現(xiàn),操作簡便,但對所處理的文件有一定的要求及限制.
具體實現(xiàn)是,先保存中斷向量表,然后在分配一塊內(nèi)存,調(diào)用DOS的EXEC功能執(zhí)行被感染的COM文件.執(zhí)行結(jié)束后,重寫中斷向量表以清除內(nèi)存中的病毒,然后將內(nèi)存偏移100H上的代碼寫入文件,文件長度為原文件長度,最后,在知曉病毒長度的情況下去掉文件尾的病毒代碼,清除工作結(jié)束.
這種技術(shù)可以對付任何一種文件型病毒,但對于COM文件卻有一定的要求:即文件在執(zhí)行過程中不可以修改代碼段的內(nèi)容,未被加密或壓縮的文件一般均可滿足此條件.
四 使用調(diào)試器DEBUG.COM的EXEC功能
更簡單的方法是用DEBUG來實現(xiàn),先用L命令裝入一個文件,再用G命令運行,EXEC功能結(jié)束后,返回寄存器與運行前完全一樣,此時用W命令存盤,這時病毒便被清除了.(全過程只用了三條命令)
EXE文件是DOS系統(tǒng)最為常見且靈活的可執(zhí)行文件,其應(yīng)用十分廣泛.但EXE文件的結(jié)構(gòu)要比COM文件復(fù)雜得多.EXE文件由文件頭(Header)和裝入模塊(Load Module)兩大部分組成.文件頭由格式化區(qū)(Format Area)和重定位表(RelocationTable)組成.裝入模塊為程序代碼部分,從位移量100H字節(jié)開始.DOS系統(tǒng)在調(diào)用EXE文件時,先在內(nèi)存塊底部建立一個程序前綴段(PSP),再將裝入模塊讀入內(nèi)存指定區(qū)域(PSP上方),DS和ES初始化為PSP段地址,CS,IP,SS,SP由文件頭格式化區(qū)確定,并通過重定位參數(shù)調(diào)整.然后根據(jù)重定位項修改代碼數(shù)據(jù),最后將程序的控制權(quán)由CS:IP傳遞給目標(biāo)程序. (如表2所示)
表2: EXE文件的裝入執(zhí)行
地址 | 內(nèi)容 | |
XXXX:0000 | PSP | ← DS,ES |
XXXX:0100 | 數(shù)據(jù) | |
程序代碼 | ← CS:IP | |
堆棧 | ← SS:SP |
對于EXE文件而言,計算機(jī)病毒主要是附著于宿主文件的尾部,由于它必須首先獲得程序的控制權(quán),因此它必須對文件頭進(jìn)行修改.一般來說,只要恢復(fù)了正確的文件頭,便可達(dá)到殺毒的目的.
EXE文件被加載時,系統(tǒng)根據(jù)EXE文件頭的CS:IP參數(shù)確定第一條執(zhí)行語句,因此病毒只需將CS:IP地址指針修改,便可首先執(zhí)行,事實上,大多數(shù)病毒僅僅只修改了文件頭,而未修改原文件內(nèi)容.這便為完整地恢復(fù)原程序代碼提供了條件.
從上面的分析可知,感染病毒的EXE文件尾部形成明顯的層次,CS:IP指向病毒體,不管病毒采取什么樣的措施,它最終必定會在內(nèi)存中恢復(fù)宿主程序所有的真實參數(shù),并且用一條長跳轉(zhuǎn)指令返回原程序.這時,我們便可直接提取出正確的CS:IP和SS:SP參數(shù)指針,用它修改文件頭后,再將外層病毒代碼去掉,這便徹底地恢復(fù)了原EXE文件.
問題在于如何找到EXE文件的正確入口.判斷EXE文件的真正入口是十分復(fù)雜的,但對于基于DOS系統(tǒng)的病毒來說,其編寫語種基本上是匯編語言,因此便具有一些獨特的特點.經(jīng)過大量分析看出,一般情況下,當(dāng)EXE病毒執(zhí)行到真正的文件開頭時,其CS和DS均要改變,并且DS內(nèi)容必定是PSP段地址,SS:SP指針被初始化,對于不修改重定位表的病毒來說,CS:IP指針應(yīng)處于重定位區(qū)域內(nèi).
于是,可以再設(shè)想出這樣一種跟蹤器,每執(zhí)行一條指令,便判斷上述條件是否滿足,如果滿足,則此時CS:IP處的代碼便是原文件的影像,根據(jù)CPU各個寄存器的內(nèi)容便可正確地恢復(fù)EXE文件頭,以達(dá)到殺毒的目的.
同COM文件殺毒一樣,這種理論上的跟蹤器實際上是很難奏效的.因此,我們又要求助于我們的老朋友--EXEX功能.
MS DOS的功能4B有兩個重要的子功能:4B00為裝入并執(zhí)行,4B01為裝入不執(zhí)行(未公開的文檔功能),4B00用于執(zhí)行所有的可執(zhí)行程序,4B01則用于DEBUG調(diào)試器中的裝入功能.(關(guān)于4B01功能的具體參數(shù)見附錄1).
由于問題的關(guān)鍵在于如何找到原程序的第一條指令,也就是說在執(zhí)行到原程序的第一條指令時發(fā)生中斷,因此我們可以人為地將第一條指令改為中斷指令.為了完成這種功能,只需用4B01功能來仿真4B00功能.
具體是這樣做的,當(dāng)系統(tǒng)調(diào)用加載執(zhí)行功能4B00時,先用功能4B01加載,并初試化所有參數(shù),這時內(nèi)存的影像應(yīng)如表3所示.
表3: EXE 染毒程序內(nèi)存影像
地址 | 內(nèi)容 |
原程序代碼區(qū) | |
CS:IP→ | 病毒代碼區(qū) |
假定病毒的第一條指令處于病毒代碼的最前端,原程序的內(nèi)存影像應(yīng)為PSP:100~CS:IP(病毒的第一條指令),將這部分區(qū)域全部用ASCII碼CD填充.這樣,原程序的每一條指令都變成了中斷指令I(lǐng)NT CD(不用INT3斷點中斷是因為大部分病毒都具有破壞單步斷點中斷的功能),也就是說,無論從原程序的任何地址開始運行,所執(zhí)行的第一條指令都是INTCD.這樣,一旦病毒代碼執(zhí)行完畢,打算用長跳轉(zhuǎn)指令返回原程序執(zhí)行時,都會觸發(fā)軟中斷INT CD,而通過INTCD的中斷服務(wù)程序便可取得EXE文件頭真正的初始化CS:IP和SS:SP指針.
另外值得注意的是,修改后的INT 21必須是可遞歸的,因為有些病毒(如新世紀(jì)病毒)是通過第二次加載原程序來返回的,因此,內(nèi)存填充要進(jìn)行兩次.4B01也被調(diào)用了兩次.
此方法的效率和準(zhǔn)確度要遠(yuǎn)遠(yuǎn)高于用DEBUG等工具逐步跟蹤分析的手工殺毒法.可以為各種染上已知或未知病毒的文件去除病毒外殼.與RCOPY等去殼程序不同的是,這種方法對EXE程序的恢復(fù)是全真的恢復(fù),它并不改變原EXE文件的任何內(nèi)容.它所恢復(fù)的EXE程序代碼應(yīng)與原EXE程序代碼完全一樣.另外,此法由于采用了剝殼還原法,因此還可以用來清除交叉感染的病毒,方法是從外到內(nèi)逐層脫殼,最后徹底恢復(fù)最內(nèi)層的宿主文件.
本文所論述的這種清除病毒的方法的實現(xiàn)原理是非常獨特的.當(dāng)然,文中所給出的實現(xiàn)方案并不能清除所有的計算機(jī)病毒,但它卻給出了一種思想,即拋棄以前那種一個殺毒算法只能殺一個病毒,而是一個算法可以殺一類病毒.根據(jù)這種思想,筆者已用C語言和匯編語言編寫出這個通用殺病毒程序,并且用大量的病毒對它進(jìn)行了測試,效果良好.當(dāng)然,病毒是五花八門的,因此一個統(tǒng)一的病毒對抗軟件應(yīng)接受廣泛的考驗.其具體的功效還需要多方面的驗證,筆者也僅僅希望這種思想能夠在反病毒領(lǐng)域發(fā)揮出積極的作用.
參考文獻(xiàn)
1. 李向宇 著 <<計算機(jī)病毒概論>> IDG國際數(shù)據(jù)集團(tuán) 1990
2. Ray Dancan <<高水平MS DOS程序設(shè)計>> 電子工業(yè)出版社 1988
Ray Dancan Advanced MS-DOS Programing Microsoft Press 1988
3 . Ray Dancan <<MS DOS百科全書>> 電子工業(yè)出版社 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系統(tǒng)的加載,即把磁盤上的COM及EXE文件裝入內(nèi)存并執(zhí)行,可以被任何程序使用MS-DOS功能(功能4BH,加載執(zhí)行)產(chǎn)生.DOS的命令解釋程序COMMAND.COM使用EXEC裝入它的外部命令,如CHKDSK,或其它應(yīng)用程序.許多流行的商業(yè)軟件,例如數(shù)據(jù)庫和字處理,都使用EXEC執(zhí)行輔助程序(例如拼寫檢查),或是裝入COMMAND.COM的另一個副本,這就允許用戶在不失去當(dāng)前工作上下文時運行一個輔助程序或打入MS-DOS命令.
當(dāng)EXEC被一個程序(父進(jìn)程)調(diào)用并加載另一個程序(子進(jìn)程),父進(jìn)程可以通過一串字符即環(huán)境塊,命令行及兩個文件控制塊,來傳輸一定的信息給子進(jìn)程.子進(jìn)程同樣繼承了父進(jìn)程的MSDOS標(biāo)準(zhǔn)設(shè)備及其它父進(jìn)程打開的設(shè)備的句柄(除非打開的操作有"非繼承性"的選擇).任何操作都可被子進(jìn)程的繼承句柄執(zhí)行,例如定位或文件輸入輸出,而且還影響著與父進(jìn)程句柄聯(lián)系著的文件指針.子進(jìn)程也可裝入另一程序,如此循環(huán)直至系統(tǒng)內(nèi)存溢出.
因為MSDOS并非一個多任務(wù)的操作系統(tǒng),子進(jìn)程直到運行結(jié)束才交出系統(tǒng)控制權(quán),父進(jìn)程此時被掛起,這種進(jìn)程操作有時也叫做同步執(zhí)行.當(dāng)子進(jìn)程中止,父進(jìn)程得到控制權(quán)并可用另一個系統(tǒng)功能調(diào)用(INT21H功能4DH)取回子進(jìn)程的返回碼并檢查子進(jìn)程的中止是否正常,或是一個重大的硬件錯誤,比如用戶按了Ctrl-C.
除了裝入子進(jìn)程外,EXEC還可以被用來裝入由于用匯編或高級語言寫成而不能包含在其庫文件中的子程序或應(yīng)用程序的覆蓋文件,這種類型的覆蓋文件不能單獨運行,多數(shù)需要主程序的段內(nèi)的"幫助"工作或數(shù)據(jù).
EXEC功能僅存在MSDOS 2.0版以上,在MSDOS 1.X版中,父進(jìn)程可以用INT 21H的功能26H建立一個子進(jìn)程的程序前綴段,但必須自己完成裝載,重定位,執(zhí)行代碼的過程,而不是依靠操作系統(tǒng)的幫助.
EXEC是怎樣工作的
當(dāng)EXEC功能接到一個執(zhí)行程序的請求時,它首先試圖打開并定位指定的程序文件.如果文件沒有找到,EXEC立刻失敗并返回調(diào)用者一個錯誤碼.
如果文件存在,EXEC打開此文件,確定它的大小,并檢查文件的首塊.如果塊的頭兩個字節(jié)是ASCII碼MZ,文件便設(shè)定為一個EXE裝入模式.程序代碼段,數(shù)據(jù)段,堆棧段的大小可以從文件頭獲得.否則,整個文件便設(shè)定為一個決對裝入影像(COM程序).實際的文件名后綴(COM或EXE)在這個測試中被忽略.
此時,內(nèi)存所需要裝入程序的大小是知道的,假如有足夠的空間裝入程序,EXEC便在內(nèi)存分配兩個塊:一個包括新程序的環(huán)境塊,另一個包括程序的代碼段,數(shù)據(jù)段和堆棧段.不同類型的程序?qū)嶋H分配的大小不同.COM程序得到系統(tǒng)中全部的空余內(nèi)存(除非內(nèi)存空間過早形成碎塊),而分配給EXE程序的空間大小是由文件頭的兩個字段控制,MINALLOC和MAXALLOC,它是由LINK設(shè)置的.
EXEC接著將父進(jìn)程的環(huán)境塊拷入子進(jìn)程的環(huán)境塊,在子進(jìn)程內(nèi)存塊的底部建立一個程序前綴段(PSP).并將命令行及缺省文件控制塊拷入PSP.以前的終止地址(INT 22H),Ctrl-C(INT 23H)
及嚴(yán)重錯誤(INT 24H)中斷向量的目錄存入新的PSP,終止地址向量被更新,以便子進(jìn)程終止或失敗時控制能夠返回到父進(jìn)程.
接著子進(jìn)程的實際代碼和部分?jǐn)?shù)據(jù)便由磁盤文件讀到新PSP結(jié)構(gòu)上方的程序內(nèi)存塊.如果子程序是一個EXE文件,文件頭的重定位表常用于在程序里定位參考段以便反映出它實際的裝入地址.
最后,EXEC功能建立為程序的CPU寄存器和堆棧并將控制傳給程序.COM文件的入口指針常是程序內(nèi)存塊中偏移100H(PSP后第一個字節(jié)).而EXE文件的入口地址由文件頭指定,可以在程序中任何位置.
當(dāng)EXEC用于裝入并執(zhí)行一個覆蓋文件而不是子程序時,它的操作會比上述更為簡單.對于覆蓋文件,EXEC并不試圖分配內(nèi)存或建立PSP及環(huán)境塊,它只簡單地將文件的內(nèi)容裝入調(diào)用文件所指定的地址,并執(zhí)行一些必要的重定位(如果覆蓋文件有一個EXE文件頭).使用的段值也是由調(diào)用者提供.EXEX接著并不是將控制傳給最新裝入文件的代碼,而是返回所產(chǎn)生的程序,請求程序負(fù)責(zé)在適當(dāng)?shù)奈恢谜{(diào)用覆蓋.
使用EXEC裝入程序
當(dāng)一個程序裝入并執(zhí)行另一個程序時,它必須執(zhí)行以下幾步:
1.確認(rèn)有足夠的空閑內(nèi)存來裝入子進(jìn)程的代碼,數(shù)據(jù)和堆棧.
2.建立EXEC和子進(jìn)程所需要的信息.
3.調(diào)用MSDOS的EXEC功能運行子進(jìn)程.
4.恢復(fù)并測試子進(jìn)程的結(jié)束及返回碼.
分配內(nèi)存
MSDOS典型地分配給被加載的COM或EXE文件所有可用的內(nèi)存.一個不常見的例外是當(dāng)一個由/CPARMAXALLOC開關(guān)聯(lián)接或被EXEMOD修改的EXE程序會由它先前駐留的數(shù)據(jù)或代碼分裂一個短小的程序塊.所以,當(dāng)一個程序要裝入另一個程序之前,它必須釋放所有它本身代碼數(shù)據(jù)堆棧所不用的內(nèi)存.
釋放多余的內(nèi)存是調(diào)用MSDOS的重分配內(nèi)存塊功能(INT21H,功能4AH).此時,ES寄存器置父進(jìn)程的PSP段地址,BX寄存器置程序自身必須使用的內(nèi)存塊數(shù),如預(yù)期的父進(jìn)程是COM程序,且它減少它的內(nèi)存分配數(shù)低于64K時,它必須移動它的堆棧到一個安全的空間.
準(zhǔn)備EXEC的參數(shù)
當(dāng)使用裝入和執(zhí)行一程序時,必須提供EXEC功能兩條參數(shù):
1.子程序路徑名的地址.
2.參數(shù)塊地址.
參數(shù)塊依次包括子程序所需信息的地址.
程序名
子程序的路徑名必需是明確的,零結(jié)尾(ASCIIZ),規(guī)定文件名(沒有非識別字符).如果沒有包含路徑,便在當(dāng)前目錄下尋找程序,如果無驅(qū)動器名,則使用默認(rèn)驅(qū)動器.
參數(shù)塊
參數(shù)塊包括四個數(shù)據(jù)項地址:
1. 環(huán)境塊
2. 命令行
3. 二個缺省文件控制塊(FCBs)
在參數(shù)塊中為環(huán)境塊指針準(zhǔn)備的空間只有兩個字節(jié),包括一個段地址.這是因為環(huán)境塊總是排在段落上(它的地址總可以被16整除).值0000H表示子進(jìn)程的環(huán)境應(yīng)被毫不改變地繼承.余下的三個地址全是雙字節(jié)地址,是標(biāo)準(zhǔn)的Intel格式,一個低字的段偏移,一個高字的段地址.
環(huán)境塊
一個環(huán)境塊總是從一個邊界段開始,包含一系列的以0結(jié)尾的字符串(ASCIIZ),形式如下:
name = variable 全部字符串的結(jié)尾以一個附加的0表示.
如果在參數(shù)塊中的環(huán)境塊指針提供給一個EXEC的調(diào)用包含0,那么子進(jìn)程只需簡單地拷貝父進(jìn)程的環(huán)境塊.父進(jìn)程能夠提供一個不同或是增長一組字符串的段指針.另一方面,在MSDOS 3.0
以后的版本里,EXEC使子程序的環(huán)境塊具有完整的路徑名.環(huán)境塊最大為32字節(jié).通過這種途徑,這么大的信息也可被程序識別.
最初的(或主控的)系統(tǒng)環(huán)境塊屬于系統(tǒng)接通或重新啟動后的命令處理程序(通常是COMMAND.COM)所裝入的.COMMAND.COM將字符串PATH,SHELL,PROMPT和SET命令的結(jié)果寫入系統(tǒng)的主環(huán)境塊.前兩個通常使用的是默認(rèn)值.例如,一個MSDOS3.2版的系統(tǒng)從C驅(qū)啟動,在AUTOEXEC.BAT文件中無PATH命令,CONFIG.SYS文件中也無SHELL命令,則主環(huán)境塊將下面兩行字符串寫入:
PATH =
COMSPEC = C: \COMMAND.COM
COMMAND.COM為運行"外部"命令而尋找這些說明清單,同時也為了找到自身在磁盤上的可執(zhí)行文件以便它能在必要的時候重新裝入它的暫態(tài)部分.當(dāng)PROMPT字串存在時(先前的PROMPT或SET PROMPT命令產(chǎn)生的結(jié)果),COMMAND.COM它來修訂用戶的提示顯示.
環(huán)境塊中的其它字符串僅僅為了特殊程序提供信息,它不影響操作系統(tǒng)的操作.例如,Microsoft C 編譯器和 MicrosoftObject連接器在環(huán)境塊中尋找INCLUDE,LIB和TMP字符串,以確定頭文件,庫文件,臨時文件的指定位置.圖2給出了一個典型的環(huán)境塊的十六進(jìn)制顯示圖.
命令行
命令行是傳給子進(jìn)程的,它包括一字節(jié)指明余下命令行的長度,緊接著的ASCII字符串是以ASCII碼回車(0DH)為結(jié)束的.回車碼并不包含在長度值里.命令行可包括子進(jìn)程可以檢查到的所有開關(guān),文件名,以及其它參數(shù),用以影響程序的操作.命令行被拷貝到子進(jìn)程PSP偏移80H處.
當(dāng)COMMAND.COM使用EXEC運行一個程序時,它的命令行包括除程序名或重定向參數(shù)外所有用戶打下的命令.I/O的重定向是在COMMAND.COM內(nèi)部處理的,它表明子進(jìn)程繼承了標(biāo)準(zhǔn)設(shè)備句柄的活動.其它程序使用EXEC來運行子進(jìn)程必須自己做一些必要的重定向而且必須提供一個合適的命令行,以便子進(jìn)程表現(xiàn)得如同被COMMAND.COM裝入一樣.
確省的文件控制塊
EXEC參數(shù)塊的二個確省的FCBs指向拷貝到子進(jìn)程PSP的偏移5CH和6CH.
當(dāng)前只有極少數(shù)應(yīng)用程序使用FCB作為文件和記錄的I/O.這是因為FCBs不支持目錄樹結(jié)構(gòu).但有些程序檢查確省的文件控制塊作為分離前二個開關(guān)或其它命令行參數(shù)的快速的方法.然而,使它自己本身對子進(jìn)程透明,父進(jìn)程應(yīng)該仿效COMMAND.COM那樣把命令行前二個參數(shù)裝入確省的文件控制塊.這能使MSDOS的分析文件名功能(INT 21H,功能29H)能方便地使用.
如果子進(jìn)程不需要這二個確省的文件控制塊,應(yīng)用程序內(nèi)存中的參數(shù)塊中正確的地址會初始化指向二個空FCBs,這些空FCBs是由1字節(jié)0和11字節(jié)ASCII碼空格(20H)組成.
運行子進(jìn)程
當(dāng)父進(jìn)程構(gòu)造完所必要的參數(shù)后,它就可以通過中斷21H來調(diào)用EXEC,各寄存器設(shè)置如下:
AH = 4BH
AL = 00H (EXEC子功能,裝入并執(zhí)行程序)
DS:DX = 程序路徑名的段地址:偏移址
ES:BX = 參數(shù)塊的段地址:偏移址
從以上軟件中斷返回后,父進(jìn)程必須要測試一下進(jìn)位標(biāo)志,以此來檢測子進(jìn)程是否實際運行過.如果進(jìn)位清楚,則成功裝入并控制了子進(jìn)程.如果進(jìn)位置位,則EXEC功能失敗,錯誤碼返回在AX中,可檢測原因.通常的原因是:
指定文件沒有找到
文件找到,但沒有足夠的內(nèi)存裝入
其它不常見的服務(wù)錯誤可以從整個系統(tǒng)感到其特征(如磁盤文件或內(nèi)存中的MSDOS被損壞),使用MSDOS 3.0以后的版本,可以通過調(diào)用INT 21H功能59(取擴(kuò)展錯誤信息)來獲得EXEC更詳細(xì)的失敗原因.
總的來說,提供給EXEC參數(shù)塊一個無效地址或參數(shù)塊本身地址無效并不會引起EXEC錯誤,但這將使子進(jìn)程產(chǎn)生一些不可的后果.
聯(lián)系客服