教授如何編寫病毒是一個很敏感的話題。這會不會引起病毒泛濫?到底有沒有學習編寫病毒的必要?這就牽涉到一個問題,引起病毒泛濫的原因到底是什嗎?是因為會編寫病毒的人太多還是因為懂得對付病毒的人太少?當騙子到處橫行,我們到底應該讓每個人都懂得騙子行騙的手段以防止受騙還是應該隱瞞騙子的行徑呢?使人們懂法是否是教唆人們違法呢?
一、怎樣編寫主引導記錄和BOOT區病毒
什麼是主引導記錄?主引導記錄存放在何處?主引導記錄是用來裝載硬碟使用中的磁碟分割的BOOT扇區的程式。主引導記錄存放於硬碟0道0柱面1扇區,長度最大為一個扇區。從硬碟啟動時,BIOS引導程式將主引導記錄裝載至0:7C00H處,然後將控制權交給主引導記錄。一般的,BOOT區病毒存在於磁碟片。因為磁碟片不存在分區,可以將其看成為磁碟片的主引導記錄。磁碟片的BOOT區存在於其0道0面1扇區,長度為一個扇區。
一般的主引導記錄病毒的原理。
一般的,這類病毒是把原來的主引導記錄儲存後用自己的程式替代掉原來的主引導記錄。啟動時,當病毒體得到控制權,在做完了自己的處理後,病毒將儲存的原主引導記錄讀入0:7C00,然後將控制權交給原主引導記錄進行啟動。這類病毒對硬碟的感染一般是在用帶毒磁碟片啟動的時候,對磁碟片的感染一般是在當系統帶毒時對磁碟片操作時。
編寫主引導記錄病毒需要瞭解的幾點
1、用什麼來儲存原始主引導記錄。
眾所周知的,檔案型病毒用以儲存被感染修改的部分是檔案。引導型病毒是否也可以使用檔案儲存體被覆蓋的引導記錄呢?答案是否定的。由於主引導記錄病毒先於作業系統執行,因而不能使用作業系統的功能調用,而只能使用BIOS的功能調用或者使用直接的IO設計。一般的,使用BIOS的磁碟服務將主引導記錄儲存於絕對的扇區內。由於0道0面2扇區是保留扇區,因而通常使用它來儲存。
2、需要掌握的BIOS磁碟服務功能調用。
INT 13H 子功能 02H 讀扇區
其調用方法為:
入口為:
AH=02H
AL=讀入的扇區數
CH=磁軌號
CL=扇區號(從1開始)
DH=頭號
DL=物理磁碟機代號
ES:BX-->要填充的緩衝區
返回為: 當CF置位時表示調用失敗
AH=狀態
AL=實際讀入的扇區數
INT 13H 子功能03H寫扇區
其調用方法為:
入口為:
AH=03H
AL=寫入的扇區數
CH=磁軌號
CL=扇區號(從1開始)
DH=頭號
DL=物理磁碟機代號
ES:BX-->緩衝區
返回為: 當CF置位時表示調用失敗
AH=狀態
AL=實際寫入的扇區數
3。這類病毒通過什麼來進行感染
通常的,這類病毒通過截獲中斷向量INT 13H 進行系統監控。當存在有關於磁碟片或硬碟的磁碟讀寫時, 病毒將檢測其是否乾淨,若尚未感染則感染之。
4。駐留的位置
通常病毒通過修改基本記憶體的大小來擷取自己駐留的空間。基本記憶體大小的儲存位置在40H:13H,單位為KB。病毒體存在於最後的幾K記憶體中。
==========================================================
二、如何編寫DOS病毒?
自磁芯大戰以來,病毒從DOS時代的病毒發展到WINDOS系統的病毒,從變形、加密到智能化現在的病毒是讓人防不勝防,現在網路上病毒大肆泛濫,給人們帶來的很大的危害,本人在此僅做拋磚引玉,介紹病毒的原理,希望大家共同研究交流。(本文參考了網路上的部分文章,並引用了部分內容。)
要學DOS下的病毒,首先你必須要學會或掌握組合語言。DOS下病毒一般分為引導型病毒、檔案型病毒、混合型病毒等。大部分病毒是感染COM和EXE檔案,因此你必須瞭解COM檔案和EXE檔案結構。
一 .COM檔案結構及原理
.COM 檔案比較簡單,.COM檔案包含程式的一個絕對映象―――就是說,為了運行程式準確的處理器指令和記憶體中的資料,MS-DOS通過直接把該映象從檔案拷貝到記憶體而載入.COM程式,它不作任何改變。為載入一個.COM程式,MS-DOS首先試圖分配記憶體,因為.COM程式必須位於一個64K的段中,所以.COM檔案的大小不能超過65,024(64K減去用於PSP的256位元組和用於一個起始堆棧的至少256位元組)。如果MS-DOS不能為程式、一個PSP、一個起始堆棧分配足夠記憶體,QQ:9750406則分配嘗試失敗。否則,MS-DOS分配儘可能多的記憶體(直至所有保留記憶體),即使.COM程式本身不能大於64K。在試圖運行另一個程式或分配另外的記憶體之前,大部分.COM程式釋放任何不需要的記憶體。
分配記憶體後,MS-DOS在該記憶體的頭256位元組建立一個PSP,如果PSP中的第一個FCB含有一個有效磁碟機標識符,則置AL為00h,否則為0FFh。MS-DOS還置AH為00h或0FFh,這依賴於第二個FCB是否含有一個有效磁碟機標識符。建造PSP後,MS-DOS在PSP後立即開始(位移100h)載入.COM檔案,它置SS,DS和ES為PSP的段地址,接著建立一個堆棧.為建立一個堆棧,MS-DOS置SP為0000h,若已指派了至少64K記憶體;否則,它置寄存器為比所分配的位元組總數大2的值.最後,它把0000h推進棧(這是為了保證與在早期MS-DOS版本上設計的程式的相容性)。MS-DOS通過把控制傳遞位移100h處的指令而啟動程式.程式設計者必須保證.COM檔案的第一條指令是程式的進入點。注意,因為程式是在位移100h處載入,因此所有代碼和資料位移也必須相對於100h.組合語言程式設計者可通過置程式的初值為100h而保證這
一點(例如通過在原程式的開始使用語句org 100h).
二 EXE檔案結構
EXE 檔案比較複雜,每個EXE檔案都有一個檔案頭,結構如下:
EXE檔案頭資訊
―――――――――――――――――――
├ 位移量 ┤ 意義 ┤
├00h-01h ┤MZ‘EXE檔案標記 ┤
├2h-03h ┤檔案長度除512的餘數 ┤
├04h-05h ┤...............商 ┤
├06h-07h ┤重定位項的個數 ┤
├08h-09h ┤檔案頭除16的商 ┤
├0ah-0bh ┤程式運行所需最小段數 ┤
├0ch-0dh ┤..............大.... ┤
├oeh-0fh ┤堆棧段的段值 (SS) ┤
├10h-11h ┤........sp ┤
├12h-13h ┤檔案校正和 ┤
├14h-15h ┤IP ┤
├16h-17h ┤CS ┤
├18h-19h ┤............ ┤
├1ah-1bh ┤............ ┤
├1ch ┤............ ┤
―――――――――――――――――――――――――
.EXE檔案包含一個檔案頭和一個可重定位程式映象。檔案頭包含MS-DOS用於載入程式的資訊,例如程式的大小和寄存器的初始值。檔案頭還指向一個重定位表,該表包含指向程式映象中可重定位段地址的指標鏈表。檔案頭的形式與EXEHEADER結構對應:
EXEHEADER STRUC
exSignature dw 5A4Dh ;.EXE標誌
exExraBytes dw ? ;最後(部分)頁中的位元組數
exPages dw ? ;檔案中的全部和部分頁數
exRelocItems dw ? ;重定位表中的指標數
exHeaderSize dw ? ;以位元組為單位的檔案頭大小
exMinAlloc dw ? ;最小分配大小
exMaxAlloc dw ? ;最大分配大小
exInitSS dw ? ;初始SS值
exInitSP dw ? ;初始SP值
exChechSum dw ? ;補碼校正值
exInitIP dw ? ;初始IP值
exInitCS dw ? ;初始CS值
exRelocTable dw ? ;重定位表的位元組位移量
exOverlay dw ? ;覆蓋號
EXEHEADER ENDS程式映象,包含處理器代碼和程式的初始資料,緊接在檔案頭之後。它的大小以位元組為單位,等於.EXE檔案的大小減去檔案頭的大小,也等於exHeaderSize的域的值乘以16。MS-DOS通過把該映象直接從檔案拷貝到記憶體載入.EXE程式然後調整定位表中說明的可重定位段地址。
定位表是一個重定位指標數組,每個指向程式映象中的可重定位段地址。檔案頭中的exRelocItems域說明了數組中指標的個數,exRelocTable域說明了分配表的起始檔案位移量。每個重定位指標由兩個16位值組成:位移量和段值。 為載入.EXE程式,MS-DOS首先讀檔案頭以確定.EXE標誌並計算程式映象的大小。然後它試圖申請記憶體。首先,它計算程式映象檔案的大小加上PSP的大小再加上EXEHEADER結構中的exMinAlloc域說明的記憶體大小這三者之和,如果總和超過最大可用記憶體塊的大小。則MS-DOS停止載入程式並返回一個出錯值。否則面,它計算程式映象的大小加上PSP的大小再加上EXEHEADER結構中exMaxAlloc域說明的記憶體大小之和,如果第二個總和小於最大可用記憶體塊的大小,則MS-DOS 分配計算得到的記憶體量。否則,它分配最大可用記憶體塊。分配完記憶體後,MS-DOS確定段地址,也稱為起始段地址,MS-DOS從此處載入程式映象。如果exMinAlloc域和exMaxAlloc域中的值都為零,則MS-DOS把映象儘可能地載入到記憶體最高端。否則,它把映象載入到緊挨著PSP域之上。接下來,MS-DOS讀取重定位表中的項目調整所有由可重定位指標說明的段地址。對於重定位表中的每個指標,MS-DOS尋找程式映象中相應的可重定位段地址,並把起始段地址加到它之上。一旦調整完畢,段地址便指向了記憶體中被載入程式的代碼和資料區段。 MS-DOS在所分配記憶體的最低部分建造256位元組的PSP,把AL和AH設定為載入 .COM程式時所設定的值。MS-DOS使用檔案頭中的值設定SP與SS,調整SS初始值,把起始地址加到它之上。MS-DOS還把ES和DS設定為PSP的段地址.最後,MS-DOS從程式檔案頭讀取CS和IP的初始值,把起始段地址加到CS之 上,把控制轉移到位於調整後地址處的程式。
三、引導型病毒原理
瞭解引導型病毒的原理,首先要瞭解引導區的結構。磁碟片只有一個引導區,稱為DOS BOOT SECTER ,只要磁碟片做了格式化,就會存在。其作用為尋找盤上有無IO.SYS DOS.SYS,若有則引導,若無則顯示‘NO SYSTEM DISK...’等資訊。硬碟有兩個引導區,在0面0道1扇區的稱為主引導區,內有主引導程式和分區表,主引導程式尋找啟用分區,該分區的第一個扇區即為DOS BOOT SECTER。絕大多數病毒感染硬碟主開機磁區和磁碟片DOS開機磁區。
***3.5”磁碟片格式***
3.5”磁碟片是雙面的,所以零磁軌有正反兩面,正面為0-17扇區,
反面是18-35扇區。
0 扇區: Boot area (開機磁區);
1 - 9 扇區: 1st FAT area (第一張檔案配置表);
10 - 18 扇區: 2st FAT area (第二張檔案配置表);
19 - 32 扇區: Root dir area(也叫 File Directory Table,FDT)
檔案目錄表(根目錄)
33-2879 扇區: Data area (資料區)
***硬碟的主引導記錄結構***
硬碟的主引導記錄結構
位移 機器碼 符號指令 說明
0000 FA CLI ;屏蔽中斷
0001 33C0 XOR AX,AX
0003 8ED0 MOV SS,AX ;(SS)=0000H
0005 BC007C MOV SP,7C00 ;(SP)=7C00H
0008 8BF4 MOV SI,SP ;(SI)=7C00H
000A 50 PUSH AX
000B 07 POP ES ;(ES)=0000H
000C 50 PUSH AX
000D 1F POP DS ;(DS)=0000H
000E FB STI
000F FC CLD
0010 BF0006 MOV DI,0600
0013 B90001 MOV CX,0100 ;共512位元組
0016 F2 REPNZ
0017 A5 MOVSW ;主引導程式把自己從0000:7C00處搬到
;0000:0600處,為Dos分區的引導程式騰
;出空間
0018 EA1D060000 JMP 0000:061D ;跳到0000:061D處繼續執行,實際上就是
;執行下面的MOV指令(001D位移處)
001D BEBE07 MOV SI,07BE ;07BE-0600=01BE,01BE是分區表的首址
0020 B304 MOV BL,04 ;分區表最多4項,即最多4個分區
0022 803C80 CMP BYTE PTR [SI],80 ;80H表示使用中的磁碟分割
0025 740E JZ 0035 ;找到使用中的磁碟分割則跳走
0027 803C00 CMP BYTE PTR [SI],00 ;00H為有效分區的標誌
002A 751C JNZ 0048 ;既非80H亦非00H則分區表無效
002C 83C610 ADD SI,+10 ;下一個分區表項,每項16位元組
002F FECB DEC BL ;迴圈計數減一
0031 75EF JNZ 0022 ;檢查下一個分區表項
0033 CD18 INT 18 ;4個都不能引導則進入ROM Basic
0035 8B14 MOV DX,[SI]
0037 8B4C02 MOV CX,[SI+02] ;取使用中的磁碟分割的開機磁區的面,柱面,扇區
003A 8BEE MOV BP,SI ;然後繼續檢查後面的分區表項
003C 83C610 ADD SI,+10
003F FECB DEC BL
0041 741A JZ 005D ;4個都查完則去引導使用中的磁碟分割
0043 803C00 CMP BYTE PTR [SI],00 ;00H為分區有效標誌
0046 74F4 JZ 003C ;此分區表項有效則繼續查下一個
0048 BE8B06 MOV SI,068B ;068B-0600=018B,取"無效分區"字串
004B AC LODSB ;從字串中取一字元
004C 3C00 CMP AL,00 ;00H表示串尾
004E 740B JZ 005B ;串顯示完了則進入死迴圈
0050 56 PUSH SI
0051 BB0700 MOV BX,0007
0054 B40E MOV AH,0E
0056 CD10 INT 10 ;顯示一個字元
0058 5E POP SI
0059 EBF0 JMP 004B ;迴圈顯示下一個字元
005B EBFE JMP 005B ;此處為死迴圈
005D BF0500 MOV DI,0005 ;讀入使用中的磁碟分割的引導扇,最多試讀5次
0060 BB007C MOV BX,7C00
0063 B80102 MOV AX,0201
0066 57 PUSH DI
0067 CD13 INT 13 ;讀
0069 5F POP DI
006A 730C JNB 0078 ;讀盤成功則跳走
006C 33C0 XOR AX,AX
006E CD13 INT 13 ;讀失敗則複位磁碟
0070 4F DEC DI
0071 75ED JNZ 0060 ;不到5次則再試讀
0073 BEA306 MOV SI,06A3 ;06A3-0600=00A3,即"Error loading"串
0076 EBD3 JMP 004B ;去顯示字串,然後進入死迴圈
0078 BEC206 MOV SI,06C2 ;06C2-0600=00C2,即"Missing.."串
0076 EBD3 JMP 004B ;去顯示字串,然後進入死迴圈
0078 BEC206 MOV SI,06C2 ;06C2-0600=00C2,即"Missing.."串
007B BFFE7D MOV DI,7DFE ;7DFE-7C00=01FE,即使用中的磁碟分割的引導扇
;區的最後兩位元組的首址
007E 813D55AA CMP WORD PTR [DI],AA55;最後兩位元組為AA55H則有效
0082 75C7 JNZ 004B ;無效則顯示字串並進入死迴圈
0084 8BF5 MOV SI,BP
0086 EA007C0000 JMP 0000:7C00 ;有效則跳去引導該分區
0080 49 6E 76 61 6C Inval
0090 69 64 20 70 61 72 74 69-74 69 6F 6E 20 74 61 62 id partition tab
00A0 6C 65 00 45 72 72 6F 72-20 6C 6F 61 64 69 6E 67 le.Error loading
00B0 20 6F 70 65 72 61 74 69-6E 67 20 73 79 73 74 65 operating syste
00C0 6D 00 4D 69 73 73 69 6E-67 20 6F 70 65 72 61 74 m.Missing operat
00D0 69 6E 67 20 73 79 73 74-65 6D 00 00 FB 4C 38 1D ing system...L8.
00E0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
00F0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0100 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0110 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0120 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0130 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0140 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0150 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0160 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0170 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0180 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0190 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
01A0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
01B0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 80 01 ................;分區表
01C0 01 00 06 0F 7F 9C 3F 00-00 00 F1 59 06 00 00 00 ......?....Y....
01D0 41 9D 05 0F FF 38 30 5A-06 00 40 56 06 00 00 00 A....80Z..@V....
01E0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
01F0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 55 AA ..............U.
使用INT 13H的02功能調用把位於硬碟保留扇區中0道0頭1扇區處的硬碟主引導記錄讀到記憶體的ES:BX處。現在把讀出程式碼進行如下分析:
1、移動主引導記錄程式
0E74:7C00 33C0 XOR AX,AX ;AX清零
0E74:7C02 8ED0 MOV SS,AX ;SS清零
0E74:7C04 BC007C MOV SP,7C00 ;SP=7C00,堆棧設在0:7C00H
0E74:7C07 FB STI ;開中斷
0E74:7C08 50 PUSH AX
0E74:7C09 07 POP ES ;ES=0
0E74:7C0A 50 PUSH AX
0E74:7C0B 1F POP DS ;DS=0
0E74:7C0C FC CLD
0E74:7C0D BE1B7C MOV SI,7C1B ;源地址為0:7C1BH
0E74:7C10 BF1B06 MOV DI,061B ;目的地址為0:061BH
0E74:7C13 50 PUSH AX
0E74:7C14 57 PUSH DI
0E74:7C15 B9E501 MOV CX,01E5 ;移動01E5位元組
0E74:7C18 F3 REPZ ;將主引導記錄從0:7C1B-0:7DFF
0E74:7C19 A4 MOVSB ;移至0:061B-0:07FF
0E74:7C1A CB RETF ;轉移到0:061B,繼續執行程式
2、順序尋找四個硬碟分區表,尋找自舉標誌
0E74:061B BEBE07 MOV SI,07BE ;SI指向硬碟分區表1的自舉標誌
0E74:061E B104 MOV CL,04 ;尋找四個分區
0E74:0620 382C CMP [SI],CH
0E74:0622 7C09 JL 062D ;如果[SI]的第7位為1,即為自
;舉標誌,轉062DH
0E74:0624 7515 JNZ 063B ;如果[SI]不為0,出錯,轉063BH
0E74:0626 83C610 ADD SI,+10 ;依次檢驗四個分區表,直至找到
0E74:0629 E2F5 LOOP 0620 ;自舉標誌
0E74:062B CD18 INT 18 ;找不到自舉標誌,進入BOOT異
;常處理常式。
0E74:062D 8B14 MOV DX,[SI] ;儲存自舉磁碟機代號於DL中
0E74:062F 8BEE MOV BP,SI ;儲存自舉分區地址指標於BP
0E74:0631 83C610 ADD SI,+10 ;繼續檢驗自舉分區後的分區
0E74:0634 49 DEC CX ;自舉標誌,直至四個分區都
0E74:0635 7416 JZ 064D ;檢查完
0E74:0637 382C CMP [SI],CH ;若其餘的自舉標誌不為0,出錯
0E74:0639 74F6 JZ 0631
3、出錯,寫螢幕程式段
0E74:063B BE1007 MOV SI,0710 ;錯誤資訊輸出,死迴圈
0E74:063E 4E DEC SI
0E74:063F AC LODSB
0E74:0640 3C00 CMP AL,00
0E74:0642 74FA JZ 063E
0E74:0644 BB0700 MOV BX,0007
0E74:0647 B40E MOV AH,0E
0E74:0649 CD10 INT 10
0E74:064B EBF2 JMP 063F
硬碟主引導記錄程式的功能是讀出自舉分區的BOOT程式,並把控制轉移到分區BOOT程式。整個程式流程如下:
1 將本來讀入到0:7C00H處的硬碟主引導記錄程式移至0:61BH處;
⑵ 順序讀入四個分區表的自舉標誌,以找出自舉分區,若找不到,轉而執行INT18H的BOOT異常執行中斷程式;
⑶ 找到自舉分區後,檢測該分區的系統標誌,若為32位FAT表或16位FAT表但支援13號中斷的擴充功能,就轉到執行13號中斷的41號功能調用進行安裝檢驗,檢驗成功,就執行42號擴充讀功能調用把BOOT區程式讀入到記憶體0:7C00H處,成功,跳到第⑸步,若讀失敗或系統標誌為其它,就調用13號中斷的讀扇區功能調用把BOOT讀到0:7C00H;
⑷ 用13號中斷的讀扇區功能時,用兩種方式分別進行5次試讀。第一種方式是直接從自舉分區的頭扇區讀入BOOT程式,若讀成功,但結束標誌不是55AA,則改用第二種方式,又如果用第一種方式試讀五次均不成功,就改用第二種方式。若兩種方式試讀均失敗,就轉到出錯處理常式;
⑸ 讀入BOOT區程式成功,轉至0:7C00H處執行BOOT程式。