David.Ko

          Follow my heart!
          posts - 100, comments - 11, trackbacks - 0, articles - 0
             :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

          用匯編編寫DOS下的內(nèi)存駐留程序(1)

          Posted on 2007-09-30 08:22 David.Ko 閱讀(274) 評(píng)論(0)  編輯  收藏 所屬分類: 病毒

          緒言
          0.1 內(nèi)存駐留與中斷
          內(nèi)存駐留程序英文叫Terminate and Stay Resident Program,縮寫為TSR.這些程序加載進(jìn)內(nèi)存,執(zhí)行完后,就駐留在內(nèi)存里,當(dāng)滿足條件時(shí),調(diào)到前臺(tái)來執(zhí)行。
          內(nèi)存駐留程序的常用形式有:
          >諸如Borland 的SideKick彈出式實(shí)用程序
          >日歷系統(tǒng)
          >網(wǎng)絡(luò)服務(wù)
          >通訊程序
          >本地的DOS擴(kuò)展(如CCDOS,UCDOS等中文系統(tǒng)都屬于這個(gè)范疇)
          >一些可惡的人利用TSR技術(shù)制作很多可惡的病毒程序,幾乎所有的病毒程序都是TSR程序.
          就象多任務(wù)系統(tǒng)調(diào)度一個(gè)進(jìn)程有一個(gè)調(diào)度程序一樣,在PC中從前臺(tái)程序進(jìn)入到一個(gè)TSR,也要有一個(gè)調(diào)度者,只是PC操作系統(tǒng)的調(diào)度不稱為調(diào)度程序,而只稱為觸發(fā)機(jī)制.觸發(fā)機(jī)制調(diào)度TSR執(zhí)行在PC機(jī)上黨稱為激活一個(gè)TSR.觸發(fā)機(jī)制主要有以下幾種:
          >硬件中斷:黨用的是鍵盤中斷INT 9H,時(shí)鐘中斷INT 8H,通訊中斷INT 14H,磁盤中斷INT 13H等等.
          >軟件中斷:黨用的是鍵盤中斷INT 16H,時(shí)鐘中斷INT 1CH,DOS中斷INT 21H,等等.
          >以上各種的結(jié)合.
          從以上的觸發(fā)機(jī)制可以看出,TSR和PC機(jī)的中斷系統(tǒng)有著密切的關(guān)系.每種激活方式實(shí)際上都是與中斷有關(guān)的.常用特殊的擊鍵序列的識(shí)別碼是通過截獲INT 9H和INT 16H來實(shí)現(xiàn).實(shí)際上不管TSR程序的哪一個(gè)環(huán)節(jié),都與中斷有著密切的關(guān)系.因此在具體進(jìn)行TSR和程序設(shè)計(jì)之前,先介紹PC中斷系統(tǒng).在此只作簡(jiǎn)單說明.
          在PC機(jī)內(nèi)存的最低端(0000H開始)的1K字節(jié)中,存放著256個(gè)指針即常說的中為向量或中斷矢量(Interrupt vertor),每個(gè)中斷向量都指向一個(gè)子程序,該程序稱為中斷處理程序(Interrup handler).一個(gè)中斷向量由四個(gè)字節(jié)組成,有一個(gè)字是中斷處理程序的偏移量值,后一個(gè)字是中斷處理程序的段值.256中斷向量一起稱為中斷向量表.
          手式計(jì)算中斷向量的首址,可通過以下的公式來求得:
          X號(hào)中斷向量的首址=0000H:X*4
          當(dāng)產(chǎn)生一個(gè)中斷時(shí),處理器都按順序執(zhí)行以下步驟:
          >在堆棧上壓入處理器的標(biāo)志(相當(dāng)于指令PUSHF).
          >在堆棧上壓入當(dāng)前CS和IP值(相當(dāng)于指令PUSH CS和PUSH IP).
          >關(guān)閉中斷(CLI)
          >從中斷向量加載的CS和IP,執(zhí)行中斷處理程序.
          當(dāng)執(zhí)行完中斷處理程序后,一般用IRET返回,它的作用是:
          >從堆棧上取出保存的IP和CS(相當(dāng)于指令POP CS和PUSH CS).
          >同時(shí)恢復(fù)中斷前的處理器標(biāo)志(相當(dāng)于指令POPF).
          中斷有多種分類,由觸發(fā)的原因和實(shí)現(xiàn)的性質(zhì)來分,可分為硬件中斷和軟件中斷,從操作系統(tǒng)分層實(shí)現(xiàn)來說,可以分成BIOS中斷,BOS中斷和用戶中斷.
          一方面,BIOS和DOS通過中斷系統(tǒng)向用戶提供一個(gè)操作系統(tǒng)功能界面.也就是說用戶(一般來說是前臺(tái)程序)的功能主要是通過調(diào)用DOS和BIOS的中斷服務(wù)來實(shí)現(xiàn)的,具體來說就是通過INT指令來實(shí)現(xiàn)的.另一方面,BIOS和DOS由中斷系統(tǒng)所構(gòu)成,BIOS對(duì)硬件成為高層的功能,并通過中斷的形式向用戶提供.
          如果在當(dāng)前程序執(zhí)行的同時(shí),能將一塊代碼放在內(nèi)存,把中斷向量指向代碼中的子程序,那么在當(dāng)前程序執(zhí)行中產(chǎn)生中斷時(shí),就有可能執(zhí)行不屬于當(dāng)前程序和操作系統(tǒng)的代碼,產(chǎn)生的中斷可能是當(dāng)前程序產(chǎn)生的軟件中斷,也可能是由硬件產(chǎn)生的硬件中斷.這就是單任務(wù)的PC操作系統(tǒng)可能執(zhí)行多于一個(gè)進(jìn)程的簡(jiǎn)單說明.
          在PC中斷系統(tǒng)中有幾個(gè)中斷具有周期性,即INT 8H,INT 1CH和INT 28H.它們或者周期性被執(zhí)行用于時(shí)間計(jì)時(shí),或者周期性產(chǎn)生用于等待.它們是在實(shí)現(xiàn)TSR時(shí)進(jìn)行輪詢觸發(fā)的基礎(chǔ).鍵盤中斷(INT 9H和INT 16H)當(dāng)用戶擊鍵時(shí)發(fā)生,利用它們是進(jìn)行熱鍵處理的基礎(chǔ).串行口通訊也是觸發(fā)的一個(gè)重要機(jī)制.此外眾多的軟件中斷也是觸發(fā)的媒介.

          0.2 DOS的可重入性分析
          一個(gè)多任務(wù)操作系統(tǒng)之所以能使多個(gè)進(jìn)行并存,是因?yàn)椴僮飨到y(tǒng)的大部分代碼是可以了重的,對(duì)于臨界資源有相應(yīng)的PV操作,使得當(dāng)調(diào)度一個(gè)新的進(jìn)程時(shí),能完整地保存前一個(gè)里程的現(xiàn)場(chǎng),當(dāng)再一次調(diào)度被掛起的進(jìn)程時(shí)能象沒有被中斷一樣繼續(xù)執(zhí)行.
          對(duì)于PC機(jī)來說,代碼的重入性比較弱,對(duì)臨界資源沒有PC操作.當(dāng)我們用中斷程序啟動(dòng)用戶的TSR時(shí),如果只保存標(biāo)志和寄存器,以及當(dāng)前進(jìn)程一些信息,那么只保存了當(dāng)前程序的一部分現(xiàn)場(chǎng),DOS的臨界資源不會(huì)自動(dòng)保存.在進(jìn)行TSR設(shè)計(jì)時(shí),一定要了解PC操作系統(tǒng)的重入性和臨界資源.
          重入性總是體現(xiàn)在代碼上,所謂可重入代碼的指這樣的代碼,即該代碼被執(zhí)行時(shí)還沒有從中退出,由于某種原因又一次或者多次進(jìn)入相同的代碼,該代碼每次的執(zhí)行結(jié)果都是正確的,就說該代碼是可重入的.相反,如果結(jié)果不正確,那么就就該代碼是不可重入的.下面是一個(gè)可重入的子程序的例子:
          Add proc near
          cmp DS:word ptr [si],0
          je DonotAddTheValue
          add ax,DS:word ptr [si]
          DonotAddTheValue:
          ret
          Add endp
          上面的例子不管在其中任何一處再一次執(zhí)行該子程序,執(zhí)行結(jié)果不變.為了說明,只舉多種可能性中的一種.
          mov ds,0100h ;ds=0100h
          mov si,0010h ;si=0010h
          mov ax,0001h ;ax,=0001h
          call Add
          cmp 0100h:word ptr [0010h],0 ;Call Add subroutine
          push ds ;Interrupted
          push si
          push ax
          mov ds,0200h ;ds=0200h
          mov si,0200h ;si=0020h
          mov ax,0003h ;ax=0003h
          call Add
          cmp 0200h:word ptr [0020h],0 ;0200:0020h=0004h
          jne
          add ax,0200h:word ptr [0020h] ;ax=0007h
          ret ;Return
          pop ax ;ax=0001h
          pop si ;si=0010h
          pop ds ;ds=0100h
          iret ;Return to Add subroutine
          jne
          add ax,0100h:word ptr [0100h] ;ax= 0001h
          ;0100h:0010h= 0002h
          ;----------------------------------------
          ;ax = 0003h
          ret
          mov bx,ax
          而下面的子程序是不可重入的:
          Add proc near
          mov Temp,ax
          mov ax,DS:word ptr [si]
          cmp ax,0
          je DonotTheValue
          add ax,Temp
          DonotTheValue:
          ret
          Temp:
          dw 0
          Add endp
          可以利用檢查可重入子程序的方法檢查這個(gè)子程序的不可重入性,嘗試一下在" mov ax,DS:word ptr [si]"指令后再次執(zhí)行該子程序,那么就會(huì)出第一次調(diào)用返回的結(jié)果不對(duì).
          mov ds,0100h ;ds=0100h
          mov si,0010h ;si=0010h
          mov ax,0001h ;ax,=0001h
          call Add
          mov Temp,ax ;Call Add subroutine
          ;Temp=0001h
          mov ax,0100h:word ptr [0010h] ;0100h:0010h=0002h
          ;ax=2
          push ds ;Interrupted
          push si
          push ax
          mov ds,0200h ;ds=0200h
          mov si,0020h ;si=0020h
          mov ax,0003h ;ax=0003h
          call Add
          mov Temp,ax ;Temp=0003h
          mov ax,0200h:word ptr [0020h] ;0200h:0020h=0004h
          cmp ax,0 ;ax=0004h
          jne ;Not equal ,add
          add ax,Temp ;ax=0007h
          ret ;Return to the interrupted point
          pop ax ;ax=0002h
          pop si ;si=0010h
          pop ds ;ds=0100h
          iret ;Return to Add subroutine
          cmp ax,0 ;ax=2
          jne ;No equal,add
          add ax,Temp ;ax =0002h
          ;0100h:0010h =0003h
          ;----------------------------------------
          ;ax =0005h
          ret
          mov bx,ax
          上面執(zhí)行的結(jié)果是AX=5,實(shí)上正確的結(jié)果應(yīng)該是AX=3,這是由于當(dāng)Add子程序從中斷子程序再一次被調(diào)用時(shí),修改了Temp的值,當(dāng)從中斷返回時(shí)不能正確恢復(fù)其值.
          解決的方法是把Temp放在堆棧中,當(dāng)每次Add子程序被調(diào)用時(shí)Temp的地址都不一樣,因此原調(diào)用的Temp值不會(huì)被第二次在中斷中調(diào)用的Add所破壞.
          Add proc near
          push bp ;Store BP
          sub sp,2 ;distribute a byte space in the stack
          mov bp,sp ;SS:BP point to the stack head
          temp equ SS:word ptr [BP+0] ;Explain the pointer to SS:BP
          mov Temp,ax
          mov ax,DS:word ptr [si]
          cmp ax,0
          je DonotAddTheValue
          add ax,Temp
          DonotAddTheValue:
          add sp,2 ;Release the dsitributed space in the stack
          pop bp ;Restore BP
          ret
          Add endp
          對(duì)于DOS來說,DOS的內(nèi)存數(shù)據(jù)就象Temp變量,它被分配在數(shù)據(jù)區(qū),而不在堆棧上,因此DOS從總體上是不可重入的.從最后的一個(gè)例子看來.重入性跟堆棧有很大的關(guān)系.可重入代碼允許在任何時(shí)候被中斷,其所有的變量都存放在該代碼的私有堆棧中.DOS是一個(gè)單任務(wù)的操作系統(tǒng),在執(zhí)行INT 21H的代碼時(shí)是不允許中斷DOS,并再次調(diào)用INT 21H的.每個(gè)時(shí)該最多有一個(gè)進(jìn)程在調(diào)用DOS的代碼.
          對(duì)DOS的重入性,以及相應(yīng)所作的處理總結(jié)如下:
          >當(dāng)通過INT 21H調(diào)用DOS時(shí),DOS會(huì)使三個(gè)內(nèi)部棧之一:I/O棧,磁盤棧和輔助棧.功能00H到處0CH使用I/O棧,除了不致命錯(cuò)誤處理程 序以外使用磁盤棧,致命錯(cuò)誤處理程序使用輔助棧.在這種棧切換模式下,如果前臺(tái)處在INT 22H中,而TSR調(diào)用了使用相同棧的DOS功能, 就會(huì)使前臺(tái)程序保存棧中的數(shù)據(jù)被TSR的數(shù)據(jù)覆蓋掉;但如果調(diào)用不同棧的DOS功能,那將是安全的.INT 21H中的幾個(gè)功能調(diào)即33H,50H, 51H,62H,和64H由于非常簡(jiǎn)單,使用用戶棧,因此在任何情況下都是可重入的.避免這種不可重入的簡(jiǎn)單方法是當(dāng)前臺(tái)程序正處在INT 21H 中時(shí),不要調(diào)用INT 21H.或者如果前臺(tái)程序正在處理INT 21H時(shí),只允許調(diào)用不同棧的INT 21H功能.
          >DOS數(shù)據(jù)區(qū)中有一個(gè)InDOS標(biāo)志,也探源為DOS安全標(biāo)志,表示當(dāng)前訪問DOS功能是來否安全.由于DOS不可重入,它指示當(dāng)前是 否處于DOS中,激活TSR和代碼可檢查該標(biāo)志(34H),如果DOS忙,則不能激活使用INT 21H 調(diào)用的TSR.
          >當(dāng)前臺(tái)程序執(zhí)行能設(shè)置錯(cuò)誤狀態(tài)的DOS功能時(shí),DOS會(huì)把擴(kuò)展錯(cuò)誤信息存放起來,正常情況下,前臺(tái)程序可以讀取擴(kuò)展錯(cuò)誤信息; 如果在前臺(tái)程序讀取信息之前激活TSR,且TSR也執(zhí)行能報(bào)告錯(cuò)誤信息的DOS功能,則后來的錯(cuò)誤信息會(huì)覆蓋原來的錯(cuò)誤信息,前臺(tái)程序就 會(huì)得不到正確的錯(cuò)誤信息.因此必須在激活TSR之前保存(59H)這些錯(cuò)誤信息,并在退出以前把它們恢復(fù)(5D0AH)成原來的值.
          >大多硬件中斷如INT 13H,INT 0BH和INT 0CH等都是不可重往返.如果設(shè)置一引起寄存器,而在此時(shí)被TSR打斷,執(zhí)行類似的設(shè)置 ,就會(huì)出現(xiàn)非常情況,端口是不會(huì)自動(dòng)保持值的.在進(jìn)入這些中斷時(shí)設(shè)置一個(gè)進(jìn)入的標(biāo)志,如果TSR檢查到標(biāo)志已置,則不調(diào)用相應(yīng)的中斷.
          >最好也不要重入INT 10H,INT 25H,和INT 26H中斷.在進(jìn)入這些中斷時(shí)設(shè)置一個(gè)進(jìn)入的標(biāo)志,如果TSR檢查到標(biāo)志已置,則不調(diào)用 相應(yīng)的中斷.
          >最好能接管INT 1BH,INT 23H和INT 24H中斷.
          >保存DOS的數(shù)據(jù)交換區(qū)(SDA)可以安全地使用的DOS的功能.SDA保存了DOS幾乎所有內(nèi)部數(shù)據(jù),如果保存(5D06H)和恢復(fù)(5D0BH)SDA ,DOS就變成在任何時(shí)候都可以重入的了.當(dāng)DOS處在關(guān)鍵區(qū)中時(shí),調(diào)用INT 2AH.一旦處在關(guān)鍵區(qū)中,就不能改變SDA.在關(guān)鍵區(qū)的結(jié)束處會(huì) 調(diào)用INT21H的81H和82H功能.
          0.3 內(nèi)存駐留程序設(shè)計(jì)一般過程
          駐留程序分成兩個(gè)部分,即暫駐部分和駐留部分.駐留程序要完成安裝檢測(cè),激活和刪除等過程.
          基本上可抽象成以下幾個(gè)過程:
          >取中斷向量
          >保存舊的中斷向量
          >設(shè)置或恢復(fù)中斷向量
          >中斷處理程序的鏈接
          >檢測(cè)是來呀已駐留
          >執(zhí)行終止并駐留
          >TSR的刪除
          刪除TSR比較復(fù)雜,必須按下列步驟進(jìn)行:
          >檢查中斷向量是否已經(jīng)被替換.如果沒有替換,就恢復(fù)所有的中斷向量;如果某個(gè)中斷向量被替換,則跳過下面各步,不能刪除該 TSR.
          >TSR的PSP中偏移量16H存放著父進(jìn)程的PSP.把這個(gè)值改為當(dāng)前進(jìn)程的地址.
          >把當(dāng)前PSP設(shè)為TSR的PSP
          >執(zhí)行INT 21H的4CH功能,釋放TSR占用的內(nèi)存,關(guān)閉所有文件,并使用PSP中存放的父進(jìn)程地址和終止地址.
          >這里控制返回到初始進(jìn)程中,當(dāng)前PSP也指向初始進(jìn)程,所有寄存器值包括SS和SP都不確定.
          在執(zhí)行完上述步驟后,要恢復(fù)寄存器.
          如果要無條件地刪除TSR,必須監(jiān)控每個(gè)TSR對(duì)中斷向量表,內(nèi)存控制塊和設(shè)備驅(qū)動(dòng)程序鏈的修改.
          0.5 縮寫語表
          ASCIZ: 以零結(jié)束的ASCII字符串.
          BPD: "BIOS Parameter Block (BIOS 參數(shù)塊)"的縮寫.含有對(duì)驅(qū)動(dòng)器的低級(jí)參數(shù)的說明.
          CDS: "Current Directory Structure(當(dāng)前目錄結(jié)構(gòu))"的縮寫,含有某個(gè)邏輯驅(qū)動(dòng)器的當(dāng)前目錄,類型和其它信息.
          DPB: "DOS Drive Parameter Block(DOS驅(qū)動(dòng)器參數(shù)塊)"的縮寫,含有某個(gè)邏輯驅(qū)動(dòng)器的介質(zhì)說明及一些內(nèi)部信息.
          DPL: "DOS Parameter List (DOS參數(shù)表)"的縮寫,該數(shù)據(jù)結(jié)構(gòu)用來傳遞參數(shù)給SHARE和網(wǎng)絡(luò)功能調(diào)用.
          DTA: "Disk Transfer Address(磁盤傳輸?shù)刂?"的縮寫,指示對(duì)磁盤進(jìn)行數(shù)據(jù)讀寫的功能調(diào)用不必顯式地給出緩沖區(qū)地址.
          FAT: "File Allocation Table(文件分配表)"的縮寫,磁盤的文件分配表記錄了所使用的簇信息.
          FCB: "File Control Block(文件控制塊)"的縮寫,在DOS的1.X版本中,用FCB來記錄文件打開的狀態(tài)..
          IFS: "Installable File System(可安裝的文件系統(tǒng))"的縮寫,它允許一個(gè)非DOS格式的介質(zhì)被DOS所使用. 大多數(shù)情況下IFS 與網(wǎng)絡(luò)驅(qū)動(dòng)器非常相似,盡管IFS最典型的情況是一個(gè)本地驅(qū)動(dòng)器而不是一個(gè)遠(yuǎn)程驅(qū)動(dòng)器.
          JFT: "Job File Table(工作文件表)或Open File Table(打開文件表)"的縮寫,程序PSP中的JFT可用來將文件句柄轉(zhuǎn)換成SFT值.
          NCB: "Network control Block( PSP: "Porgram Segment Prefix(程序段前綴)"的縮寫.當(dāng)程序被裝入時(shí),PSP為一個(gè)預(yù)留的256字節(jié)的數(shù)據(jù)區(qū)它包含了程序調(diào)用時(shí) 的命令行內(nèi)容和一些DOS的內(nèi)部信息.
          SDA: "DOS Swappable Data Area (DOS對(duì)換 SFT: "System File Table(系統(tǒng)文件表)"的縮寫,SFT是一個(gè)DOS內(nèi)部數(shù)據(jù)結(jié)構(gòu),在DOS 2+版本的

          句柄功能調(diào)用中用于管理某個(gè)已打 開文件的狀態(tài),這就和在DOS1.X中,FCB管理已打開文件狀態(tài)一樣.
          主站蜘蛛池模板: 灵丘县| 邵东县| 壤塘县| 成安县| 和静县| 木兰县| 赣州市| 阿鲁科尔沁旗| 贺兰县| 石阡县| 连云港市| 阜南县| 台中县| 黄冈市| 桃园县| 临邑县| 青海省| 信丰县| 昭通市| 台南县| 南通市| 鲁山县| 泸水县| 阿合奇县| 逊克县| 建始县| 昂仁县| 兰州市| 通渭县| 措美县| 米林县| 苗栗县| 周至县| 申扎县| 思南县| 耒阳市| 朝阳市| 无极县| 廉江市| 龙海市| 那曲县|