David.Ko

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

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

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

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

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

          句柄功能調用中用于管理某個已打 開文件的狀態,這就和在DOS1.X中,FCB管理已打開文件狀態一樣.
          主站蜘蛛池模板: 吐鲁番市| 中西区| 章丘市| 蓝田县| 怀远县| 北票市| 鄯善县| 满城县| 南城县| 毕节市| 图片| 徐水县| 靖州| 三原县| 故城县| 泰州市| 隆化县| 宜宾市| 龙山县| 长岭县| 剑河县| 海宁市| 朔州市| 揭阳市| 历史| 濉溪县| 泸西县| 曲沃县| 韶关市| 福泉市| 大同县| 宣城市| 阳曲县| 望江县| 汉寿县| 金乡县| 上高县| 东山县| 镶黄旗| 视频| 施甸县|